mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-22 15:04:04 +00:00
Add support for generated columns skipping 'GENERATED ALWAYS' keywords (#1058)
This commit is contained in:
parent
d0fce121ef
commit
da2296e6d6
4 changed files with 49 additions and 1 deletions
|
@ -600,6 +600,8 @@ pub enum ColumnOption {
|
|||
sequence_options: Option<Vec<SequenceOptions>>,
|
||||
generation_expr: Option<Expr>,
|
||||
generation_expr_mode: Option<GeneratedExpressionMode>,
|
||||
/// false if 'GENERATED ALWAYS' is skipped (option starts with AS)
|
||||
generated_keyword: bool,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -641,6 +643,7 @@ impl fmt::Display for ColumnOption {
|
|||
sequence_options,
|
||||
generation_expr,
|
||||
generation_expr_mode,
|
||||
generated_keyword,
|
||||
} => {
|
||||
if let Some(expr) = generation_expr {
|
||||
let modifier = match generation_expr_mode {
|
||||
|
@ -648,7 +651,11 @@ impl fmt::Display for ColumnOption {
|
|||
Some(GeneratedExpressionMode::Virtual) => " VIRTUAL",
|
||||
Some(GeneratedExpressionMode::Stored) => " STORED",
|
||||
};
|
||||
if *generated_keyword {
|
||||
write!(f, "GENERATED ALWAYS AS ({expr}){modifier}")?;
|
||||
} else {
|
||||
write!(f, "AS ({expr}){modifier}")?;
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
// Like Postgres - generated from sequence
|
||||
|
|
|
@ -4288,6 +4288,10 @@ impl<'a> Parser<'a> {
|
|||
Ok(Some(ColumnOption::OnUpdate(expr)))
|
||||
} else if self.parse_keyword(Keyword::GENERATED) {
|
||||
self.parse_optional_column_option_generated()
|
||||
} else if self.parse_keyword(Keyword::AS)
|
||||
&& dialect_of!(self is MySqlDialect | SQLiteDialect | DuckDbDialect | GenericDialect)
|
||||
{
|
||||
self.parse_optional_column_option_as()
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
|
@ -4306,6 +4310,7 @@ impl<'a> Parser<'a> {
|
|||
sequence_options: Some(sequence_options),
|
||||
generation_expr: None,
|
||||
generation_expr_mode: None,
|
||||
generated_keyword: true,
|
||||
}))
|
||||
} else if self.parse_keywords(&[
|
||||
Keyword::BY,
|
||||
|
@ -4323,6 +4328,7 @@ impl<'a> Parser<'a> {
|
|||
sequence_options: Some(sequence_options),
|
||||
generation_expr: None,
|
||||
generation_expr_mode: None,
|
||||
generated_keyword: true,
|
||||
}))
|
||||
} else if self.parse_keywords(&[Keyword::ALWAYS, Keyword::AS]) {
|
||||
if self.expect_token(&Token::LParen).is_ok() {
|
||||
|
@ -4347,6 +4353,7 @@ impl<'a> Parser<'a> {
|
|||
sequence_options: None,
|
||||
generation_expr: Some(expr),
|
||||
generation_expr_mode: expr_mode,
|
||||
generated_keyword: true,
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
|
@ -4356,6 +4363,32 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_optional_column_option_as(&mut self) -> Result<Option<ColumnOption>, ParserError> {
|
||||
// Some DBs allow 'AS (expr)', shorthand for GENERATED ALWAYS AS
|
||||
self.expect_token(&Token::LParen)?;
|
||||
let expr = self.parse_expr()?;
|
||||
self.expect_token(&Token::RParen)?;
|
||||
|
||||
let (gen_as, expr_mode) = if self.parse_keywords(&[Keyword::STORED]) {
|
||||
(
|
||||
GeneratedAs::ExpStored,
|
||||
Some(GeneratedExpressionMode::Stored),
|
||||
)
|
||||
} else if self.parse_keywords(&[Keyword::VIRTUAL]) {
|
||||
(GeneratedAs::Always, Some(GeneratedExpressionMode::Virtual))
|
||||
} else {
|
||||
(GeneratedAs::Always, None)
|
||||
};
|
||||
|
||||
Ok(Some(ColumnOption::Generated {
|
||||
generated_as: gen_as,
|
||||
sequence_options: None,
|
||||
generation_expr: Some(expr),
|
||||
generation_expr_mode: expr_mode,
|
||||
generated_keyword: false,
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn parse_referential_action(&mut self) -> Result<ReferentialAction, ParserError> {
|
||||
if self.parse_keyword(Keyword::RESTRICT) {
|
||||
Ok(ReferentialAction::Restrict)
|
||||
|
|
|
@ -517,6 +517,10 @@ fn parse_create_table_gencol() {
|
|||
|
||||
let sql_stored = "CREATE TABLE t1 (a INT, b INT GENERATED ALWAYS AS (a * 2) STORED)";
|
||||
mysql_and_generic().verified_stmt(sql_stored);
|
||||
|
||||
mysql_and_generic().verified_stmt("CREATE TABLE t1 (a INT, b INT AS (a * 2))");
|
||||
mysql_and_generic().verified_stmt("CREATE TABLE t1 (a INT, b INT AS (a * 2) VIRTUAL)");
|
||||
mysql_and_generic().verified_stmt("CREATE TABLE t1 (a INT, b INT AS (a * 2) STORED)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -215,6 +215,10 @@ fn parse_create_table_gencol() {
|
|||
|
||||
let sql_stored = "CREATE TABLE t1 (a INT, b INT GENERATED ALWAYS AS (a * 2) STORED)";
|
||||
sqlite_and_generic().verified_stmt(sql_stored);
|
||||
|
||||
sqlite_and_generic().verified_stmt("CREATE TABLE t1 (a INT, b INT AS (a * 2))");
|
||||
sqlite_and_generic().verified_stmt("CREATE TABLE t1 (a INT, b INT AS (a * 2) VIRTUAL)");
|
||||
sqlite_and_generic().verified_stmt("CREATE TABLE t1 (a INT, b INT AS (a * 2) STORED)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue