From e276f9103e32ec49aaa859247dc3bec3d3a04041 Mon Sep 17 00:00:00 2001 From: sam-mmm <2740878+sam-mmm@users.noreply.github.com> Date: Fri, 21 Oct 2022 00:56:34 +0530 Subject: [PATCH 1/8] Creat sequence options model [ INCREMENT [ BY ] increment ] [ MINVALUE minvalue | NO MINVALUE ] [ MAXVALUE maxvalue | NO MAXVALUE ] [ START [ WITH ] start ] [ CACHE cache ] [ [ NO ] CYCLE ] [ OWNED BY { table_name.column_name | NONE } ] --- src/ast/mod.rs | 102 +++++++++++++++++++++++++++++++++++- src/keywords.rs | 4 ++ src/parser.rs | 3 ++ tests/sqlparser_postgres.rs | 43 +++++++++++++++ 4 files changed, 150 insertions(+), 2 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index c83ead544..145303143 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -1458,6 +1458,9 @@ pub enum Statement { temporary: bool, if_not_exists: bool, name: ObjectName, + data_type: Option, + sequence_options: Vec, + owned_by: Option, }, } @@ -2479,19 +2482,114 @@ impl fmt::Display for Statement { temporary, if_not_exists, name, + data_type, + sequence_options, + owned_by, } => { + let as_type: String = if let Some(dt) = data_type.as_ref() { + format!(" AS {}", dt) + } else { + "".to_string() + }; write!( f, - "CREATE {temporary}SEQUENCE {if_not_exists}{name}", + "CREATE {temporary}SEQUENCE {if_not_exists}{name}{as_type}", if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" }, temporary = if *temporary { "TEMPORARY " } else { "" }, - name = name + name = name, + as_type = as_type + )?; + for sequence_option in sequence_options { + write!(f, "{}", sequence_option)?; + } + if let Some(ob) = owned_by.as_ref() { + write!(f, " OWNED BY {}", ob)?; + } + write!(f, "") + } + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +/// Can use to describe create sequence or table column type identity +/// [ INCREMENT [ BY ] increment ] +/// [ MINVALUE minvalue | NO MINVALUE ] [ MAXVALUE maxvalue | NO MAXVALUE ] +/// [ START [ WITH ] start ] [ CACHE cache ] [ [ NO ] CYCLE ] +pub enum SequenceOptions { + IncrementBy(Expr, bool), + MinValue(MinMaxValue), + MaxValue(MinMaxValue), + StartWith(Expr, bool), + Cache(Expr), + Cycle(bool), +} + +impl fmt::Display for SequenceOptions { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + SequenceOptions::IncrementBy(increment, by) => { + write!( + f, + " INCREMENT{by} {increment}", + by = if *by { " BY" } else { "" }, + increment = increment ) } + SequenceOptions::MinValue(value) => match value { + MinMaxValue::Empty => { + write!(f, "") + } + MinMaxValue::None => { + write!(f, " NO MINVALUE") + } + MinMaxValue::Some(minvalue) => { + write!(f, " MINVALUE {minvalue}", minvalue = minvalue) + } + }, + SequenceOptions::MaxValue(value) => match value { + MinMaxValue::Empty => { + write!(f, "") + } + MinMaxValue::None => { + write!(f, " NO MAXVALUE") + } + MinMaxValue::Some(maxvalue) => { + write!(f, " MAXVALUE {maxvalue}", maxvalue = maxvalue) + } + }, + SequenceOptions::StartWith(start, with) => { + write!( + f, + " START{with} {start}", + with = if *with { " WITH" } else { "" }, + start = start + ) + } + SequenceOptions::Cache(cache) => { + write!(f, " CACHE {}", *cache) + } + SequenceOptions::Cycle(no) => { + write!(f, " {}CYCLE", if *no { "NO " } else { "" }) + } } } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +/// Can use to describe create sequence or table column type identity +/// [ MINVALUE minvalue | NO MINVALUE ] [ MAXVALUE maxvalue | NO MAXVALUE ] +pub enum MinMaxValue { + // clause is not specified + Empty, + // NO MINVALUE/NO MAX VALUE + None, + // MINVALUE / MAXVALUE + Some(Expr), +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[non_exhaustive] diff --git a/src/keywords.rs b/src/keywords.rs index e29ebdfdb..f8d125067 100644 --- a/src/keywords.rs +++ b/src/keywords.rs @@ -277,6 +277,7 @@ define_keywords!( IGNORE, ILIKE, IN, + INCREMENT, INDEX, INDICATOR, INHERIT, @@ -328,6 +329,7 @@ define_keywords!( MATCHED, MATERIALIZED, MAX, + MAXVALUE, MEDIUMINT, MEMBER, MERGE, @@ -341,6 +343,7 @@ define_keywords!( MILLISECONDS, MIN, MINUTE, + MINVALUE, MOD, MODIFIES, MODULE, @@ -397,6 +400,7 @@ define_keywords!( OVERLAPS, OVERLAY, OVERWRITE, + OWNED, PARAMETER, PARQUET, PARTITION, diff --git a/src/parser.rs b/src/parser.rs index 0254a2f9a..4c9e9b352 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -5463,6 +5463,9 @@ impl<'a> Parser<'a> { temporary, if_not_exists, name, + data_type: None, + sequence_options: vec![], + owned_by: None, }) } } diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index c5d4bd0fc..67302e840 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -37,6 +37,49 @@ fn parse_create_sequence() { let sql4 = "CREATE TEMPORARY SEQUENCE name0"; pg().one_statement_parses_to(sql4, "CREATE TEMPORARY SEQUENCE name0"); + + let sql2 = "CREATE TEMPORARY SEQUENCE IF NOT EXISTS name1 + AS BIGINT + INCREMENT BY 1 + MINVALUE 1 MAXVALUE 20 + START WITH 10"; + pg().one_statement_parses_to( + sql2, + "CREATE TEMPORARY SEQUENCE IF NOT EXISTS name1 AS BIGINT INCREMENT BY 1 MINVALUE 1 MAXVALUE 20 START WITH 10", ); + + let sql3 = "CREATE SEQUENCE IF NOT EXISTS name2 + AS BIGINT + INCREMENT 1 + MINVALUE 1 MAXVALUE 20 + START WITH 10 CACHE 2 NO CYCLE"; + pg().one_statement_parses_to( + sql3, + "CREATE SEQUENCE IF NOT EXISTS name2 AS BIGINT INCREMENT 1 MINVALUE 1 MAXVALUE 20 START WITH 10 CACHE 2 NO CYCLE", + ); + + let sql4 = "CREATE TEMPORARY SEQUENCE IF NOT EXISTS name3 + INCREMENT 1 + NO MINVALUE MAXVALUE 20 CACHE 2 CYCLE"; + pg().one_statement_parses_to( + sql4, + "CREATE TEMPORARY SEQUENCE IF NOT EXISTS name3 INCREMENT 1 NO MINVALUE MAXVALUE 20 CACHE 2 CYCLE", + ); + + let sql5 = "CREATE TEMPORARY SEQUENCE IF NOT EXISTS name3 + INCREMENT 1 + NO MINVALUE MAXVALUE 20 OWNED BY public.table01"; + pg().one_statement_parses_to( + sql5, + "CREATE TEMPORARY SEQUENCE IF NOT EXISTS name3 INCREMENT 1 NO MINVALUE MAXVALUE 20 OWNED BY public.table01", + ); + + let sql6 = "CREATE TEMPORARY SEQUENCE IF NOT EXISTS name3 + INCREMENT 1 + NO MINVALUE MAXVALUE 20 OWNED BY NONE"; + pg().one_statement_parses_to( + sql6, + "CREATE TEMPORARY SEQUENCE IF NOT EXISTS name3 INCREMENT 1 NO MINVALUE MAXVALUE 20 OWNED BY NONE", + ); } #[test] From 54e57543be5625d5352b782cd23a695ad0c3784a Mon Sep 17 00:00:00 2001 From: sam-mmm <2740878+sam-mmm@users.noreply.github.com> Date: Fri, 21 Oct 2022 01:08:22 +0530 Subject: [PATCH 2/8] Fix for format! not avalable in --target thumbv6m-none-eabi --- src/ast/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 145303143..05071eb72 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -2487,7 +2487,8 @@ impl fmt::Display for Statement { owned_by, } => { let as_type: String = if let Some(dt) = data_type.as_ref() { - format!(" AS {}", dt) + //Cannot use format!(" AS {}", dt), due to format! is not available in --target thumbv6m-none-eabi + " AS ".to_owned()+&dt.to_string() } else { "".to_string() }; From bf68bc9b7015707db08a1ac22693893b70457168 Mon Sep 17 00:00:00 2001 From: sam-mmm <2740878+sam-mmm@users.noreply.github.com> Date: Fri, 21 Oct 2022 01:08:39 +0530 Subject: [PATCH 3/8] Fix for format! not avalable in --target thumbv6m-none-eabi --- src/ast/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 05071eb72..2084234af 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -2488,7 +2488,7 @@ impl fmt::Display for Statement { } => { let as_type: String = if let Some(dt) = data_type.as_ref() { //Cannot use format!(" AS {}", dt), due to format! is not available in --target thumbv6m-none-eabi - " AS ".to_owned()+&dt.to_string() + " AS ".to_owned() + &dt.to_string() } else { "".to_string() }; From e51171df3a35287dd4928019006001ecab5c68c4 Mon Sep 17 00:00:00 2001 From: sam-mmm <2740878+sam-mmm@users.noreply.github.com> Date: Fri, 21 Oct 2022 01:20:22 +0530 Subject: [PATCH 4/8] Fix for format! not avalable in --target thumbv6m-none-eabi --- src/ast/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 2084234af..d7ccc829a 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -2488,7 +2488,8 @@ impl fmt::Display for Statement { } => { let as_type: String = if let Some(dt) = data_type.as_ref() { //Cannot use format!(" AS {}", dt), due to format! is not available in --target thumbv6m-none-eabi - " AS ".to_owned() + &dt.to_string() + // " AS ".to_owned() + &dt.to_string() + [" AS ",&dt.to_string()].concat() } else { "".to_string() }; From 97b4059373e7d9db34b7a46c36be54f003a0d9a9 Mon Sep 17 00:00:00 2001 From: sam-mmm <2740878+sam-mmm@users.noreply.github.com> Date: Fri, 21 Oct 2022 01:23:00 +0530 Subject: [PATCH 5/8] Fix for format! not avalable in --target thumbv6m-none-eabi --- src/ast/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index d7ccc829a..b412b3488 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -2489,7 +2489,7 @@ impl fmt::Display for Statement { let as_type: String = if let Some(dt) = data_type.as_ref() { //Cannot use format!(" AS {}", dt), due to format! is not available in --target thumbv6m-none-eabi // " AS ".to_owned() + &dt.to_string() - [" AS ",&dt.to_string()].concat() + [" AS ", &dt.to_string()].concat() } else { "".to_string() }; From c67684daf11253bb6a4211c0a5c6cfb3de318b80 Mon Sep 17 00:00:00 2001 From: sam-mmm <2740878+sam-mmm@users.noreply.github.com> Date: Fri, 21 Oct 2022 02:25:20 +0530 Subject: [PATCH 6/8] Updated parser for sequence options --- src/ast/mod.rs | 4 +-- src/parser.rs | 91 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 90 insertions(+), 5 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index b412b3488..d664d0244 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -2515,7 +2515,7 @@ impl fmt::Display for Statement { #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -/// Can use to describe create sequence or table column type identity +/// Can use to describe options in create sequence or table column type identity /// [ INCREMENT [ BY ] increment ] /// [ MINVALUE minvalue | NO MINVALUE ] [ MAXVALUE maxvalue | NO MAXVALUE ] /// [ START [ WITH ] start ] [ CACHE cache ] [ [ NO ] CYCLE ] @@ -2581,7 +2581,7 @@ impl fmt::Display for SequenceOptions { #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -/// Can use to describe create sequence or table column type identity +/// Can use to describe options in create sequence or table column type identity /// [ MINVALUE minvalue | NO MINVALUE ] [ MAXVALUE maxvalue | NO MAXVALUE ] pub enum MinMaxValue { // clause is not specified diff --git a/src/parser.rs b/src/parser.rs index 4c9e9b352..c6a8469d5 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -5459,15 +5459,100 @@ impl<'a> Parser<'a> { let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]); //name let name = self.parse_object_name()?; + //[ AS data_type ] + let mut data_type: Option = None; + if self.parse_keywords(&[Keyword::AS]) { + data_type = Some(self.parse_data_type()?) + } + let sequence_options = self.parse_create_sequence_options()?; + // [ OWNED BY { table_name.column_name | NONE } ] + let owned_by = if self.parse_keywords(&[Keyword::OWNED, Keyword::BY]) { + if self.parse_keywords(&[Keyword::NONE]) { + Some(ObjectName(vec![Ident::new("NONE")])) + } else { + Some(self.parse_object_name()?) + } + } else { + None + }; Ok(Statement::CreateSequence { temporary, if_not_exists, name, - data_type: None, - sequence_options: vec![], - owned_by: None, + data_type, + sequence_options, + owned_by, + }) } + + fn parse_create_sequence_options(&mut self) -> Result, ParserError> { + let mut sequence_options = vec![]; + //[ INCREMENT [ BY ] increment ] + if self.parse_keywords(&[Keyword::INCREMENT]) { + if self.parse_keywords(&[Keyword::BY]) { + sequence_options.push(SequenceOptions::IncrementBy( + Expr::Value(self.parse_number_value()?), + true, + )); + } else { + sequence_options.push(SequenceOptions::IncrementBy( + Expr::Value(self.parse_number_value()?), + false, + )); + } + } + //[ MINVALUE minvalue | NO MINVALUE ] + if self.parse_keyword(Keyword::MINVALUE) { + sequence_options.push(SequenceOptions::MinValue( + MinMaxValue::Some(Expr::Value(self.parse_number_value()?)) + )); + } else if self.parse_keywords(&[Keyword::NO, Keyword::MINVALUE]) { + sequence_options.push(SequenceOptions::MinValue(MinMaxValue::None)); + }else { + sequence_options.push(SequenceOptions::MinValue(MinMaxValue::Empty)); + } + //[ MAXVALUE maxvalue | NO MAXVALUE ] + if self.parse_keywords(&[Keyword::MAXVALUE]) { + sequence_options.push(SequenceOptions::MaxValue( + MinMaxValue::Some(Expr::Value(self.parse_number_value()?)) + )); + } else if self.parse_keywords(&[Keyword::NO, Keyword::MAXVALUE]) { + sequence_options.push(SequenceOptions::MaxValue(MinMaxValue::None)); + }else { + sequence_options.push(SequenceOptions::MaxValue(MinMaxValue::Empty)); + } + //[ START [ WITH ] start ] + if self.parse_keywords(&[Keyword::START]) { + if self.parse_keywords(&[Keyword::WITH]) { + sequence_options.push(SequenceOptions::StartWith( + Expr::Value(self.parse_number_value()?), + true, + )); + } else { + sequence_options.push(SequenceOptions::StartWith( + Expr::Value(self.parse_number_value()?), + false, + )); + } + } + //[ CACHE cache ] + if self.parse_keywords(&[Keyword::CACHE]) { + sequence_options.push(SequenceOptions::Cache(Expr::Value( + self.parse_number_value()?, + ))); + } + // [ [ NO ] CYCLE ] + if self.parse_keywords(&[Keyword::NO]) { + if self.parse_keywords(&[Keyword::CYCLE]) { + sequence_options.push(SequenceOptions::Cycle(true)); + } + } else if self.parse_keywords(&[Keyword::CYCLE]) { + sequence_options.push(SequenceOptions::Cycle(false)); + } + Ok(sequence_options) + } + } impl Word { From 97ca09933180f53d2040d456d6fa367302915d8f Mon Sep 17 00:00:00 2001 From: sam-mmm <2740878+sam-mmm@users.noreply.github.com> Date: Fri, 21 Oct 2022 02:30:17 +0530 Subject: [PATCH 7/8] Updated parser for sequence options --- src/parser.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index c6a8469d5..dbb8360b0 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -5482,7 +5482,6 @@ impl<'a> Parser<'a> { data_type, sequence_options, owned_by, - }) } @@ -5504,22 +5503,22 @@ impl<'a> Parser<'a> { } //[ MINVALUE minvalue | NO MINVALUE ] if self.parse_keyword(Keyword::MINVALUE) { - sequence_options.push(SequenceOptions::MinValue( - MinMaxValue::Some(Expr::Value(self.parse_number_value()?)) - )); + sequence_options.push(SequenceOptions::MinValue(MinMaxValue::Some(Expr::Value( + self.parse_number_value()?, + )))); } else if self.parse_keywords(&[Keyword::NO, Keyword::MINVALUE]) { sequence_options.push(SequenceOptions::MinValue(MinMaxValue::None)); - }else { + } else { sequence_options.push(SequenceOptions::MinValue(MinMaxValue::Empty)); } //[ MAXVALUE maxvalue | NO MAXVALUE ] if self.parse_keywords(&[Keyword::MAXVALUE]) { - sequence_options.push(SequenceOptions::MaxValue( - MinMaxValue::Some(Expr::Value(self.parse_number_value()?)) - )); + sequence_options.push(SequenceOptions::MaxValue(MinMaxValue::Some(Expr::Value( + self.parse_number_value()?, + )))); } else if self.parse_keywords(&[Keyword::NO, Keyword::MAXVALUE]) { sequence_options.push(SequenceOptions::MaxValue(MinMaxValue::None)); - }else { + } else { sequence_options.push(SequenceOptions::MaxValue(MinMaxValue::Empty)); } //[ START [ WITH ] start ] @@ -5552,7 +5551,6 @@ impl<'a> Parser<'a> { } Ok(sequence_options) } - } impl Word { From b15229807d8d8ffd387b1cc9530264f4036e73b9 Mon Sep 17 00:00:00 2001 From: sam <2740878+sam-mmm@users.noreply.github.com> Date: Wed, 2 Nov 2022 23:38:15 +0530 Subject: [PATCH 8/8] Update src/ast/mod.rs Co-authored-by: Andrew Lamb --- src/ast/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index d664d0244..cc121aa01 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -2586,7 +2586,7 @@ impl fmt::Display for SequenceOptions { pub enum MinMaxValue { // clause is not specified Empty, - // NO MINVALUE/NO MAX VALUE + // NO MINVALUE/NO MAXVALUE None, // MINVALUE / MAXVALUE Some(Expr),