diff --git a/src/ast/mod.rs b/src/ast/mod.rs index c83ead544..cc121aa01 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,116 @@ 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() { + //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() + } 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 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 ] +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 options in 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 MAXVALUE + 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 108427889..1b3d86372 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -5488,12 +5488,98 @@ 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, + 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 { 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]