Skip to content

Commit da2296e

Browse files
authoredDec 19, 2023
Add support for generated columns skipping 'GENERATED ALWAYS' keywords (apache#1058)
1 parent d0fce12 commit da2296e

File tree

4 files changed

+49
-1
lines changed

4 files changed

+49
-1
lines changed
 

‎src/ast/ddl.rs

+8-1
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_keyword: 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_keyword,
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_keyword {
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

+33
Original file line numberDiff line numberDiff line change
@@ -4288,6 +4288,10 @@ impl<'a> Parser<'a> {
42884288
Ok(Some(ColumnOption::OnUpdate(expr)))
42894289
} else if self.parse_keyword(Keyword::GENERATED) {
42904290
self.parse_optional_column_option_generated()
4291+
} else if self.parse_keyword(Keyword::AS)
4292+
&& dialect_of!(self is MySqlDialect | SQLiteDialect | DuckDbDialect | GenericDialect)
4293+
{
4294+
self.parse_optional_column_option_as()
42914295
} else {
42924296
Ok(None)
42934297
}
@@ -4306,6 +4310,7 @@ impl<'a> Parser<'a> {
43064310
sequence_options: Some(sequence_options),
43074311
generation_expr: None,
43084312
generation_expr_mode: None,
4313+
generated_keyword: true,
43094314
}))
43104315
} else if self.parse_keywords(&[
43114316
Keyword::BY,
@@ -4323,6 +4328,7 @@ impl<'a> Parser<'a> {
43234328
sequence_options: Some(sequence_options),
43244329
generation_expr: None,
43254330
generation_expr_mode: None,
4331+
generated_keyword: true,
43264332
}))
43274333
} else if self.parse_keywords(&[Keyword::ALWAYS, Keyword::AS]) {
43284334
if self.expect_token(&Token::LParen).is_ok() {
@@ -4347,6 +4353,7 @@ impl<'a> Parser<'a> {
43474353
sequence_options: None,
43484354
generation_expr: Some(expr),
43494355
generation_expr_mode: expr_mode,
4356+
generated_keyword: true,
43504357
}))
43514358
} else {
43524359
Ok(None)
@@ -4356,6 +4363,32 @@ impl<'a> Parser<'a> {
43564363
}
43574364
}
43584365

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

‎tests/sqlparser_mysql.rs

+4
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

+4
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)