Skip to content

Commit d2aed31

Browse files
committed
Add support for generated columns skipping 'GENERATED ALWAYS' keywords
1 parent 8d97330 commit d2aed31

File tree

4 files changed

+49
-1
lines changed

4 files changed

+49
-1
lines changed

src/ast/ddl.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,8 @@ pub enum ColumnOption {
600600
sequence_options: Option<Vec<SequenceOptions>>,
601601
generation_expr: Option<Expr>,
602602
generation_expr_mode: Option<GeneratedExpressionMode>,
603+
/// false if 'GENERATED ALWAYS' is skipped (option starts with AS)
604+
generated_kw: bool,
603605
},
604606
}
605607

@@ -641,14 +643,19 @@ impl fmt::Display for ColumnOption {
641643
sequence_options,
642644
generation_expr,
643645
generation_expr_mode,
646+
generated_kw,
644647
} => {
645648
if let Some(expr) = generation_expr {
646649
let modifier = match generation_expr_mode {
647650
None => "",
648651
Some(GeneratedExpressionMode::Virtual) => " VIRTUAL",
649652
Some(GeneratedExpressionMode::Stored) => " STORED",
650653
};
651-
write!(f, "GENERATED ALWAYS AS ({expr}){modifier}")?;
654+
if *generated_kw {
655+
write!(f, "GENERATED ALWAYS AS ({expr}){modifier}")?;
656+
} else {
657+
write!(f, "AS ({expr}){modifier}")?;
658+
}
652659
Ok(())
653660
} else {
654661
// Like Postgres - generated from sequence

src/parser/mod.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4282,6 +4282,10 @@ impl<'a> Parser<'a> {
42824282
Ok(Some(ColumnOption::OnUpdate(expr)))
42834283
} else if self.parse_keyword(Keyword::GENERATED) {
42844284
self.parse_optional_column_option_generated()
4285+
} else if self.parse_keyword(Keyword::AS)
4286+
&& dialect_of!(self is MySqlDialect | SQLiteDialect | DuckDbDialect | GenericDialect)
4287+
{
4288+
self.parse_optional_column_option_as()
42854289
} else {
42864290
Ok(None)
42874291
}
@@ -4300,6 +4304,7 @@ impl<'a> Parser<'a> {
43004304
sequence_options: Some(sequence_options),
43014305
generation_expr: None,
43024306
generation_expr_mode: None,
4307+
generated_kw: true,
43034308
}))
43044309
} else if self.parse_keywords(&[
43054310
Keyword::BY,
@@ -4317,6 +4322,7 @@ impl<'a> Parser<'a> {
43174322
sequence_options: Some(sequence_options),
43184323
generation_expr: None,
43194324
generation_expr_mode: None,
4325+
generated_kw: true,
43204326
}))
43214327
} else if self.parse_keywords(&[Keyword::ALWAYS, Keyword::AS]) {
43224328
if self.expect_token(&Token::LParen).is_ok() {
@@ -4341,6 +4347,7 @@ impl<'a> Parser<'a> {
43414347
sequence_options: None,
43424348
generation_expr: Some(expr),
43434349
generation_expr_mode: expr_mode,
4350+
generated_kw: true,
43444351
}))
43454352
} else {
43464353
Ok(None)
@@ -4350,6 +4357,32 @@ impl<'a> Parser<'a> {
43504357
}
43514358
}
43524359

4360+
fn parse_optional_column_option_as(&mut self) -> Result<Option<ColumnOption>, ParserError> {
4361+
// Some DBs allow 'AS (expr)', shorthand for GENERATED ALWAYS AS
4362+
self.expect_token(&Token::LParen)?;
4363+
let expr = self.parse_expr()?;
4364+
self.expect_token(&Token::RParen)?;
4365+
4366+
let (gen_as, expr_mode) = if self.parse_keywords(&[Keyword::STORED]) {
4367+
(
4368+
GeneratedAs::ExpStored,
4369+
Some(GeneratedExpressionMode::Stored),
4370+
)
4371+
} else if self.parse_keywords(&[Keyword::VIRTUAL]) {
4372+
(GeneratedAs::Always, Some(GeneratedExpressionMode::Virtual))
4373+
} else {
4374+
(GeneratedAs::Always, None)
4375+
};
4376+
4377+
Ok(Some(ColumnOption::Generated {
4378+
generated_as: gen_as,
4379+
sequence_options: None,
4380+
generation_expr: Some(expr),
4381+
generation_expr_mode: expr_mode,
4382+
generated_kw: false,
4383+
}))
4384+
}
4385+
43534386
pub fn parse_referential_action(&mut self) -> Result<ReferentialAction, ParserError> {
43544387
if self.parse_keyword(Keyword::RESTRICT) {
43554388
Ok(ReferentialAction::Restrict)

tests/sqlparser_mysql.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,10 @@ fn parse_create_table_gencol() {
517517

518518
let sql_stored = "CREATE TABLE t1 (a INT, b INT GENERATED ALWAYS AS (a * 2) STORED)";
519519
mysql_and_generic().verified_stmt(sql_stored);
520+
521+
mysql_and_generic().verified_stmt("CREATE TABLE t1 (a INT, b INT AS (a * 2))");
522+
mysql_and_generic().verified_stmt("CREATE TABLE t1 (a INT, b INT AS (a * 2) VIRTUAL)");
523+
mysql_and_generic().verified_stmt("CREATE TABLE t1 (a INT, b INT AS (a * 2) STORED)");
520524
}
521525

522526
#[test]

tests/sqlparser_sqlite.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,10 @@ fn parse_create_table_gencol() {
215215

216216
let sql_stored = "CREATE TABLE t1 (a INT, b INT GENERATED ALWAYS AS (a * 2) STORED)";
217217
sqlite_and_generic().verified_stmt(sql_stored);
218+
219+
sqlite_and_generic().verified_stmt("CREATE TABLE t1 (a INT, b INT AS (a * 2))");
220+
sqlite_and_generic().verified_stmt("CREATE TABLE t1 (a INT, b INT AS (a * 2) VIRTUAL)");
221+
sqlite_and_generic().verified_stmt("CREATE TABLE t1 (a INT, b INT AS (a * 2) STORED)");
218222
}
219223

220224
#[test]

0 commit comments

Comments
 (0)