mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-04 06:18:17 +00:00
Add support of MATERIALIZED/ALIAS/EPHERMERAL default column options for ClickHouse (#1348)
This commit is contained in:
parent
b27abf00e2
commit
390d4d3554
4 changed files with 137 additions and 0 deletions
|
@ -923,6 +923,18 @@ pub enum ColumnOption {
|
|||
NotNull,
|
||||
/// `DEFAULT <restricted-expr>`
|
||||
Default(Expr),
|
||||
|
||||
/// ClickHouse supports `MATERIALIZE`, `EPHEMERAL` and `ALIAS` expr to generate default values.
|
||||
/// Syntax: `b INT MATERIALIZE (a + 1)`
|
||||
/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
|
||||
|
||||
/// `MATERIALIZE <expr>`
|
||||
Materialized(Expr),
|
||||
/// `EPHEMERAL [<expr>]`
|
||||
Ephemeral(Option<Expr>),
|
||||
/// `ALIAS <expr>`
|
||||
Alias(Expr),
|
||||
|
||||
/// `{ PRIMARY KEY | UNIQUE } [<constraint_characteristics>]`
|
||||
Unique {
|
||||
is_primary: bool,
|
||||
|
@ -978,6 +990,15 @@ impl fmt::Display for ColumnOption {
|
|||
Null => write!(f, "NULL"),
|
||||
NotNull => write!(f, "NOT NULL"),
|
||||
Default(expr) => write!(f, "DEFAULT {expr}"),
|
||||
Materialized(expr) => write!(f, "MATERIALIZED {expr}"),
|
||||
Ephemeral(expr) => {
|
||||
if let Some(e) = expr {
|
||||
write!(f, "EPHEMERAL {e}")
|
||||
} else {
|
||||
write!(f, "EPHEMERAL")
|
||||
}
|
||||
}
|
||||
Alias(expr) => write!(f, "ALIAS {expr}"),
|
||||
Unique {
|
||||
is_primary,
|
||||
characteristics,
|
||||
|
|
|
@ -77,6 +77,7 @@ define_keywords!(
|
|||
AFTER,
|
||||
AGAINST,
|
||||
AGGREGATION,
|
||||
ALIAS,
|
||||
ALL,
|
||||
ALLOCATE,
|
||||
ALTER,
|
||||
|
@ -267,6 +268,7 @@ define_keywords!(
|
|||
ENFORCED,
|
||||
ENGINE,
|
||||
ENUM,
|
||||
EPHEMERAL,
|
||||
EPOCH,
|
||||
EQUALS,
|
||||
ERROR,
|
||||
|
|
|
@ -5748,6 +5748,24 @@ impl<'a> Parser<'a> {
|
|||
Ok(Some(ColumnOption::Null))
|
||||
} else if self.parse_keyword(Keyword::DEFAULT) {
|
||||
Ok(Some(ColumnOption::Default(self.parse_expr()?)))
|
||||
} else if dialect_of!(self is ClickHouseDialect| GenericDialect)
|
||||
&& self.parse_keyword(Keyword::MATERIALIZED)
|
||||
{
|
||||
Ok(Some(ColumnOption::Materialized(self.parse_expr()?)))
|
||||
} else if dialect_of!(self is ClickHouseDialect| GenericDialect)
|
||||
&& self.parse_keyword(Keyword::ALIAS)
|
||||
{
|
||||
Ok(Some(ColumnOption::Alias(self.parse_expr()?)))
|
||||
} else if dialect_of!(self is ClickHouseDialect| GenericDialect)
|
||||
&& self.parse_keyword(Keyword::EPHEMERAL)
|
||||
{
|
||||
// The expression is optional for the EPHEMERAL syntax, so we need to check
|
||||
// if the column definition has remaining tokens before parsing the expression.
|
||||
if matches!(self.peek_token().token, Token::Comma | Token::RParen) {
|
||||
Ok(Some(ColumnOption::Ephemeral(None)))
|
||||
} else {
|
||||
Ok(Some(ColumnOption::Ephemeral(Some(self.parse_expr()?))))
|
||||
}
|
||||
} else if self.parse_keywords(&[Keyword::PRIMARY, Keyword::KEY]) {
|
||||
let characteristics = self.parse_constraint_characteristics()?;
|
||||
Ok(Some(ColumnOption::Unique {
|
||||
|
|
|
@ -493,6 +493,102 @@ fn parse_create_table_with_primary_key() {
|
|||
.expect_err("ORDER BY supports one expression with tuple");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_create_table_with_variant_default_expressions() {
|
||||
let sql = concat!(
|
||||
"CREATE TABLE table (",
|
||||
"a DATETIME MATERIALIZED now(),",
|
||||
" b DATETIME EPHEMERAL now(),",
|
||||
" c DATETIME EPHEMERAL,",
|
||||
" d STRING ALIAS toString(c)",
|
||||
") ENGINE=MergeTree"
|
||||
);
|
||||
match clickhouse_and_generic().verified_stmt(sql) {
|
||||
Statement::CreateTable(CreateTable { columns, .. }) => {
|
||||
assert_eq!(
|
||||
columns,
|
||||
vec![
|
||||
ColumnDef {
|
||||
name: Ident::new("a"),
|
||||
data_type: DataType::Datetime(None),
|
||||
collation: None,
|
||||
options: vec![ColumnOptionDef {
|
||||
name: None,
|
||||
option: ColumnOption::Materialized(Expr::Function(Function {
|
||||
name: ObjectName(vec![Ident::new("now")]),
|
||||
args: FunctionArguments::List(FunctionArgumentList {
|
||||
args: vec![],
|
||||
duplicate_treatment: None,
|
||||
clauses: vec![],
|
||||
}),
|
||||
parameters: FunctionArguments::None,
|
||||
null_treatment: None,
|
||||
filter: None,
|
||||
over: None,
|
||||
within_group: vec![],
|
||||
}))
|
||||
}],
|
||||
},
|
||||
ColumnDef {
|
||||
name: Ident::new("b"),
|
||||
data_type: DataType::Datetime(None),
|
||||
collation: None,
|
||||
options: vec![ColumnOptionDef {
|
||||
name: None,
|
||||
option: ColumnOption::Ephemeral(Some(Expr::Function(Function {
|
||||
name: ObjectName(vec![Ident::new("now")]),
|
||||
args: FunctionArguments::List(FunctionArgumentList {
|
||||
args: vec![],
|
||||
duplicate_treatment: None,
|
||||
clauses: vec![],
|
||||
}),
|
||||
parameters: FunctionArguments::None,
|
||||
null_treatment: None,
|
||||
filter: None,
|
||||
over: None,
|
||||
within_group: vec![],
|
||||
})))
|
||||
}],
|
||||
},
|
||||
ColumnDef {
|
||||
name: Ident::new("c"),
|
||||
data_type: DataType::Datetime(None),
|
||||
collation: None,
|
||||
options: vec![ColumnOptionDef {
|
||||
name: None,
|
||||
option: ColumnOption::Ephemeral(None)
|
||||
}],
|
||||
},
|
||||
ColumnDef {
|
||||
name: Ident::new("d"),
|
||||
data_type: DataType::String(None),
|
||||
collation: None,
|
||||
options: vec![ColumnOptionDef {
|
||||
name: None,
|
||||
option: ColumnOption::Alias(Expr::Function(Function {
|
||||
name: ObjectName(vec![Ident::new("toString")]),
|
||||
args: FunctionArguments::List(FunctionArgumentList {
|
||||
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
|
||||
Identifier(Ident::new("c"))
|
||||
))],
|
||||
duplicate_treatment: None,
|
||||
clauses: vec![],
|
||||
}),
|
||||
parameters: FunctionArguments::None,
|
||||
null_treatment: None,
|
||||
filter: None,
|
||||
over: None,
|
||||
within_group: vec![],
|
||||
}))
|
||||
}],
|
||||
}
|
||||
]
|
||||
)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_create_view_with_fields_data_types() {
|
||||
match clickhouse().verified_stmt(r#"CREATE VIEW v (i "int", f "String") AS SELECT * FROM t"#) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue