Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support create sequence with options INCREMENT, MINVALUE, MAXVALUE, START etc. #681

Merged
merged 9 commits into from Nov 3, 2022
104 changes: 102 additions & 2 deletions src/ast/mod.rs
Expand Up @@ -1458,6 +1458,9 @@ pub enum Statement {
temporary: bool,
if_not_exists: bool,
name: ObjectName,
data_type: Option<DataType>,
sequence_options: Vec<SequenceOptions>,
owned_by: Option<ObjectName>,
},
}

Expand Down Expand Up @@ -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
samjay000 marked this conversation as resolved.
Show resolved Hide resolved
// " 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
samjay000 marked this conversation as resolved.
Show resolved Hide resolved
/// [ 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 <expr> / MAXVALUE <expr>
Some(Expr),
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[non_exhaustive]
Expand Down
4 changes: 4 additions & 0 deletions src/keywords.rs
Expand Up @@ -277,6 +277,7 @@ define_keywords!(
IGNORE,
ILIKE,
IN,
INCREMENT,
INDEX,
INDICATOR,
INHERIT,
Expand Down Expand Up @@ -328,6 +329,7 @@ define_keywords!(
MATCHED,
MATERIALIZED,
MAX,
MAXVALUE,
MEDIUMINT,
MEMBER,
MERGE,
Expand All @@ -341,6 +343,7 @@ define_keywords!(
MILLISECONDS,
MIN,
MINUTE,
MINVALUE,
MOD,
MODIFIES,
MODULE,
Expand Down Expand Up @@ -397,6 +400,7 @@ define_keywords!(
OVERLAPS,
OVERLAY,
OVERWRITE,
OWNED,
PARAMETER,
PARQUET,
PARTITION,
Expand Down
86 changes: 86 additions & 0 deletions src/parser.rs
Expand Up @@ -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<DataType> = 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<Vec<SequenceOptions>, 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 {
Expand Down
43 changes: 43 additions & 0 deletions tests/sqlparser_postgres.rs
Expand Up @@ -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]
Expand Down