Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions fuzz/fuzz_seeds/postgres_alter_sequence.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ ALTER SEQUENCE IF EXISTS s RENAME TO s2;
ALTER SEQUENCE s SET UNLOGGED;
ALTER SEQUENCE s SET LOGGED;
ALTER SEQUENCE s AS bigint INCREMENT BY -2 NO MINVALUE MAXVALUE 100 START WITH 5 CACHE 10 NO CYCLE OWNED BY public.t.c;
ALTER SEQUENCE s RESTART;
ALTER SEQUENCE s RESTART WITH 7 INCREMENT 3;
24 changes: 20 additions & 4 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6641,17 +6641,19 @@ impl fmt::Display for Statement {
}
}

/// Can use to describe options in create sequence or table column type identity
/// Can use to describe options in create sequence, alter sequence, or table
/// column type identity
/// ```sql
/// [ AS data_type ] [ INCREMENT [ BY ] increment ]
/// [ MINVALUE minvalue | NO MINVALUE ] [ MAXVALUE maxvalue | NO MAXVALUE ]
/// [ START [ WITH ] start ] [ CACHE cache ] [ [ NO ] CYCLE ]
/// [ START [ WITH ] start ] [ RESTART [ [ WITH ] restart ] ]
/// [ CACHE cache ] [ [ NO ] CYCLE ]
/// [ OWNED BY { table_name.column_name | NONE } ]
/// ```
///
/// The options form an unordered list, so they are stored in the order written.
/// `AS` and `OWNED BY` are only accepted by `CREATE SEQUENCE`, not by an
/// identity column.
/// `AS` and `OWNED BY` are only accepted by `CREATE SEQUENCE` and `ALTER
/// SEQUENCE`, not by an identity column.
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
Expand All @@ -6666,6 +6668,9 @@ pub enum SequenceOptions {
MaxValue(Option<Expr>),
/// `START [WITH] <expr>`; second value indicates presence of `WITH`.
StartWith(Expr, bool),
/// `RESTART [ [ WITH ] restart ]`, `None` restarting from the start value.
/// The second value indicates presence of `WITH`.
Restart(Option<Expr>, bool),
/// `CACHE <expr>` option.
Cache(Expr),
/// `CYCLE` or `NO CYCLE` option.
Expand Down Expand Up @@ -6708,6 +6713,17 @@ impl fmt::Display for SequenceOptions {
start = start
)
}
SequenceOptions::Restart(None, _) => {
write!(f, " RESTART")
}
SequenceOptions::Restart(Some(restart), with) => {
write!(
f,
" RESTART{with} {restart}",
with = if *with { " WITH" } else { "" },
restart = restart
)
}
SequenceOptions::Cache(cache) => {
write!(f, " CACHE {}", *cache)
}
Expand Down
18 changes: 14 additions & 4 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21711,11 +21711,12 @@ impl<'a> Parser<'a> {
})
}

/// Parse the sequence options shared by `CREATE SEQUENCE` and identity
/// columns. The options form an unordered list, each allowed at most once.
/// Parse the sequence options shared by `CREATE SEQUENCE`, `ALTER SEQUENCE`
/// and identity columns. The options form an unordered list, each allowed
/// at most once.
///
/// `AS <data_type>` and `OWNED BY` are options of `CREATE SEQUENCE` only, so
/// `allow_type_and_owner` gates them off for an identity column.
/// `AS <data_type>` and `OWNED BY` are not options of an identity column, so
/// `allow_type_and_owner` gates them off there.
fn parse_sequence_options(
&mut self,
allow_type_and_owner: bool,
Expand Down Expand Up @@ -21752,6 +21753,15 @@ impl<'a> Parser<'a> {
SequenceOptions::StartWith(self.parse_number()?, with),
"START",
)
} else if self.parse_keyword(Keyword::RESTART) {
// [ RESTART [ [ WITH ] restart ] ]
let with = self.parse_keyword(Keyword::WITH);
let restart = if with {
Some(self.parse_number()?)
} else {
self.maybe_parse(|parser| parser.parse_number())?
};
(SequenceOptions::Restart(restart, with), "RESTART")
} else if self.parse_keyword(Keyword::CACHE) {
//[ CACHE cache ]
(SequenceOptions::Cache(self.parse_number()?), "CACHE")
Expand Down
3 changes: 3 additions & 0 deletions tests/sqlparser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6176,8 +6176,11 @@ fn parse_sequence_options_in_any_order() {
"CREATE SEQUENCE si OWNED BY NONE INCREMENT BY 2",
"CREATE SEQUENCE sj CACHE 1 AS BIGINT OWNED BY a.b START WITH 3",
"CREATE SEQUENCE sk OWNED BY none.c",
"CREATE SEQUENCE sl RESTART WITH 5 CACHE 2",
"CREATE TABLE t (id INT GENERATED ALWAYS AS IDENTITY ( START WITH 10 INCREMENT BY 1 CYCLE ))",
"ALTER TABLE t ALTER COLUMN id ADD GENERATED AS IDENTITY ( CACHE 2 INCREMENT 1 )",
"CREATE TABLE t (id INT GENERATED ALWAYS AS IDENTITY ( RESTART START WITH 3 ))",
"ALTER TABLE t ALTER COLUMN id ADD GENERATED BY DEFAULT AS IDENTITY ( RESTART 7 )",
] {
dialects.verified_stmt(sql);
}
Expand Down
42 changes: 42 additions & 0 deletions tests/sqlparser_postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13522,6 +13522,10 @@ fn parse_case_ending_in_end_keyword_is_not_silently_dropped() {
#[test]
fn parse_alter_sequence() {
let dialects = pg_and_generic();
dialects.verified_stmt("ALTER SEQUENCE s RESTART");
dialects.verified_stmt("ALTER SEQUENCE s RESTART WITH 5");
dialects.verified_stmt("ALTER SEQUENCE s RESTART 7");
dialects.verified_stmt("ALTER SEQUENCE IF EXISTS s RESTART");
dialects.verified_stmt("ALTER SEQUENCE s AS BIGINT");
dialects.verified_stmt("ALTER SEQUENCE s AS DOUBLE PRECISION");
dialects.verified_stmt("ALTER SEQUENCE s INCREMENT BY 2");
Expand Down Expand Up @@ -13556,6 +13560,7 @@ fn parse_alter_sequence() {
dialects.verified_stmt(
"ALTER SEQUENCE s INCREMENT BY 2 MINVALUE -5 MAXVALUE 50 START WITH 100 CACHE 3 NO CYCLE",
);
dialects.verified_stmt("ALTER SEQUENCE s NO CYCLE NO MAXVALUE OWNED BY NONE RESTART WITH 20");
dialects.verified_stmt("ALTER SEQUENCE s AS DOUBLE PRECISION INCREMENT 3 NO MINVALUE CYCLE");
}

Expand All @@ -13577,6 +13582,27 @@ fn parse_alter_sequence_ast() {
.parse_sql_statements("ALTER SEQUENCE s SET SCHEMA other")
.unwrap();
assert_eq!(statements[0].span(), Span::empty());
assert_eq!(
pg().parse_sql_statements("ALTER SEQUENCE s RESTART WITH 20 INCREMENT BY 3")
.unwrap(),
vec![Statement::AlterSequence(AlterSequence {
if_exists: false,
name: ObjectName::from(vec!["s".into()]),
operation: AlterSequenceOperation::Options(vec![
SequenceOptions::Restart(Some(Expr::value(number("20"))), true),
SequenceOptions::IncrementBy(Expr::value(number("3")), true),
]),
})]
);
assert_eq!(
pg().parse_sql_statements("ALTER SEQUENCE s RESTART")
.unwrap(),
vec![Statement::AlterSequence(AlterSequence {
if_exists: false,
name: ObjectName::from(vec!["s".into()]),
operation: AlterSequenceOperation::Options(vec![SequenceOptions::Restart(None, false)]),
})]
);
assert_eq!(
pg().parse_sql_statements("ALTER SEQUENCE s SET UNLOGGED")
.unwrap(),
Expand Down Expand Up @@ -13608,6 +13634,10 @@ fn parse_alter_sequence_errors() {
"ALTER SEQUENCE s INCREMENT BY 2 INCREMENT BY 3",
"INCREMENT specified more than once",
),
(
"ALTER SEQUENCE s RESTART RESTART WITH 2",
"RESTART specified more than once",
),
(
"ALTER SEQUENCE s SET SCHEMA",
"Expected: identifier, found: EOF",
Expand All @@ -13624,6 +13654,18 @@ fn parse_alter_sequence_errors() {
"ALTER SEQUENCE s INCREMENT",
"Expected: a value, found: EOF",
),
(
"ALTER SEQUENCE s RESTART WITH",
"Expected: a value, found: EOF",
),
(
"ALTER SEQUENCE s RESTART +",
"Expected: end of statement, found: +",
),
(
"ALTER SEQUENCE s RESTART x",
"Expected: end of statement, found: x",
),
] {
assert_eq!(
pg_and_generic().parse_sql_statements(sql).unwrap_err(),
Expand Down