Skip to content

Commit

Permalink
Support for pg ADD GENERATED in ALTER COLUMN statements
Browse files Browse the repository at this point in the history
Signed-off-by: Toby Hede <toby@cipherstash.com>
  • Loading branch information
tobyhede committed Jan 1, 2024
1 parent a75778c commit 7a34cd5
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 5 deletions.
33 changes: 33 additions & 0 deletions src/ast/ddl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,13 @@ pub enum AlterColumnOperation {
/// PostgreSQL specific
using: Option<Expr>,
},
/// `ADD GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options ) ]`
///
/// Note: this is a PostgreSQL-specific operation.
AddGenerated {
generated_as: Option<GeneratedAs>,
sequence_options: Option<Vec<SequenceOptions>>,
},
}

impl fmt::Display for AlterColumnOperation {
Expand All @@ -335,6 +342,32 @@ impl fmt::Display for AlterColumnOperation {
write!(f, "SET DATA TYPE {data_type}")
}
}
AlterColumnOperation::AddGenerated {
generated_as,
sequence_options,
} => {
let generated_as = match generated_as {
Some(GeneratedAs::Always) => " ALWAYS",
Some(GeneratedAs::ByDefault) => " BY DEFAULT",
_ => "",
};

write!(f, "ADD GENERATED{generated_as} AS IDENTITY",)?;
if let Some(options) = sequence_options {
if !options.is_empty() {
write!(f, " (")?;
}

for sequence_option in options {
write!(f, "{sequence_option}")?;
}

if !options.is_empty() {
write!(f, " )")?;
}
}
Ok(())
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/keywords.rs
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,7 @@ define_keywords!(
REPLICATION,
RESET,
RESPECT,
RESTART,
RESTRICT,
RESULT,
RETAIN,
Expand Down
40 changes: 35 additions & 5 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4841,7 +4841,11 @@ impl<'a> Parser<'a> {
let column_name = self.parse_identifier()?;
let is_postgresql = dialect_of!(self is PostgreSqlDialect);

let op = if self.parse_keywords(&[Keyword::SET, Keyword::NOT, Keyword::NULL]) {
let op: AlterColumnOperation = if self.parse_keywords(&[
Keyword::SET,
Keyword::NOT,
Keyword::NULL,
]) {
AlterColumnOperation::SetNotNull {}
} else if self.parse_keywords(&[Keyword::DROP, Keyword::NOT, Keyword::NULL]) {
AlterColumnOperation::DropNotNull {}
Expand All @@ -4861,11 +4865,37 @@ impl<'a> Parser<'a> {
None
};
AlterColumnOperation::SetDataType { data_type, using }
} else if self.parse_keywords(&[Keyword::ADD, Keyword::GENERATED]) {
let generated_as = if self.parse_keyword(Keyword::ALWAYS) {
Some(GeneratedAs::Always)
} else if self.parse_keywords(&[Keyword::BY, Keyword::DEFAULT]) {
Some(GeneratedAs::ByDefault)
} else {
None
};

let _ = self.expect_keywords(&[Keyword::AS, Keyword::IDENTITY]);

let mut sequence_options: Option<Vec<SequenceOptions>> = None;

if self.peek_token().token == Token::LParen {
self.expect_token(&Token::LParen)?;
sequence_options = self.parse_create_sequence_options().ok();
self.expect_token(&Token::RParen)?;
}

AlterColumnOperation::AddGenerated {
generated_as,
sequence_options,
}
} else {
return self.expected(
"SET/DROP NOT NULL, SET DEFAULT, SET DATA TYPE after ALTER COLUMN",
self.peek_token(),
);
let message = if is_postgresql {
"SET/DROP NOT NULL, SET DEFAULT, SET DATA TYPE, or ADD GENERATED after ALTER COLUMN"
} else {
"SET/DROP NOT NULL, SET DEFAULT, SET DATA TYPE, after ALTER COLUMN"
};

return self.expected(message, self.peek_token());
};
AlterTableOperation::AlterColumn { column_name, op }
} else if self.parse_keyword(Keyword::SWAP) {
Expand Down
14 changes: 14 additions & 0 deletions tests/sqlparser_postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,20 @@ fn parse_alter_table_alter_column() {
}
}

#[test]
fn parse_alter_table_alter_column_add_generated() {
pg_and_generic()
.verified_stmt("ALTER TABLE t ALTER COLUMN id ADD GENERATED ALWAYS AS IDENTITY");
pg_and_generic()
.verified_stmt("ALTER TABLE t ALTER COLUMN id ADD GENERATED BY DEFAULT AS IDENTITY");
pg_and_generic().verified_stmt("ALTER TABLE t ALTER COLUMN id ADD GENERATED AS IDENTITY");
pg_and_generic().verified_stmt(
"ALTER TABLE t ALTER COLUMN id ADD GENERATED AS IDENTITY ( INCREMENT 1 MINVALUE 1 )",
);

pg_and_generic().verified_stmt("ALTER TABLE t ALTER COLUMN id ADD GENERATED AS IDENTITY ( )");
}

#[test]
fn parse_alter_table_add_columns() {
match pg().verified_stmt("ALTER TABLE IF EXISTS ONLY tab ADD COLUMN a TEXT, ADD COLUMN b INT") {
Expand Down

0 comments on commit 7a34cd5

Please sign in to comment.