Snowflake ALTER TABLE clustering options (#1579)

This commit is contained in:
Yoav Cohen 2024-12-06 10:41:01 +01:00 committed by GitHub
parent 7b50ac31c3
commit d0fcc06652
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 123 additions and 15 deletions

View file

@ -70,7 +70,10 @@ pub enum AlterTableOperation {
///
/// Note: this is a ClickHouse-specific operation.
/// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#drop-projection)
DropProjection { if_exists: bool, name: Ident },
DropProjection {
if_exists: bool,
name: Ident,
},
/// `MATERIALIZE PROJECTION [IF EXISTS] name [IN PARTITION partition_name]`
///
@ -99,11 +102,15 @@ pub enum AlterTableOperation {
/// `DISABLE RULE rewrite_rule_name`
///
/// Note: this is a PostgreSQL-specific operation.
DisableRule { name: Ident },
DisableRule {
name: Ident,
},
/// `DISABLE TRIGGER [ trigger_name | ALL | USER ]`
///
/// Note: this is a PostgreSQL-specific operation.
DisableTrigger { name: Ident },
DisableTrigger {
name: Ident,
},
/// `DROP CONSTRAINT [ IF EXISTS ] <name>`
DropConstraint {
if_exists: bool,
@ -152,19 +159,27 @@ pub enum AlterTableOperation {
/// `ENABLE ALWAYS RULE rewrite_rule_name`
///
/// Note: this is a PostgreSQL-specific operation.
EnableAlwaysRule { name: Ident },
EnableAlwaysRule {
name: Ident,
},
/// `ENABLE ALWAYS TRIGGER trigger_name`
///
/// Note: this is a PostgreSQL-specific operation.
EnableAlwaysTrigger { name: Ident },
EnableAlwaysTrigger {
name: Ident,
},
/// `ENABLE REPLICA RULE rewrite_rule_name`
///
/// Note: this is a PostgreSQL-specific operation.
EnableReplicaRule { name: Ident },
EnableReplicaRule {
name: Ident,
},
/// `ENABLE REPLICA TRIGGER trigger_name`
///
/// Note: this is a PostgreSQL-specific operation.
EnableReplicaTrigger { name: Ident },
EnableReplicaTrigger {
name: Ident,
},
/// `ENABLE ROW LEVEL SECURITY`
///
/// Note: this is a PostgreSQL-specific operation.
@ -172,11 +187,15 @@ pub enum AlterTableOperation {
/// `ENABLE RULE rewrite_rule_name`
///
/// Note: this is a PostgreSQL-specific operation.
EnableRule { name: Ident },
EnableRule {
name: Ident,
},
/// `ENABLE TRIGGER [ trigger_name | ALL | USER ]`
///
/// Note: this is a PostgreSQL-specific operation.
EnableTrigger { name: Ident },
EnableTrigger {
name: Ident,
},
/// `RENAME TO PARTITION (partition=val)`
RenamePartitions {
old_partitions: Vec<Expr>,
@ -197,7 +216,9 @@ pub enum AlterTableOperation {
new_column_name: Ident,
},
/// `RENAME TO <table_name>`
RenameTable { table_name: ObjectName },
RenameTable {
table_name: ObjectName,
},
// CHANGE [ COLUMN ] <old_name> <new_name> <data_type> [ <options> ]
ChangeColumn {
old_name: Ident,
@ -218,7 +239,10 @@ pub enum AlterTableOperation {
/// `RENAME CONSTRAINT <old_constraint_name> TO <new_constraint_name>`
///
/// Note: this is a PostgreSQL-specific operation.
RenameConstraint { old_name: Ident, new_name: Ident },
RenameConstraint {
old_name: Ident,
new_name: Ident,
},
/// `ALTER [ COLUMN ]`
AlterColumn {
column_name: Ident,
@ -227,14 +251,27 @@ pub enum AlterTableOperation {
/// 'SWAP WITH <table_name>'
///
/// Note: this is Snowflake specific <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
SwapWith { table_name: ObjectName },
SwapWith {
table_name: ObjectName,
},
/// 'SET TBLPROPERTIES ( { property_key [ = ] property_val } [, ...] )'
SetTblProperties { table_properties: Vec<SqlOption> },
SetTblProperties {
table_properties: Vec<SqlOption>,
},
/// `OWNER TO { <new_owner> | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
///
/// Note: this is PostgreSQL-specific <https://www.postgresql.org/docs/current/sql-altertable.html>
OwnerTo { new_owner: Owner },
OwnerTo {
new_owner: Owner,
},
/// Snowflake table clustering options
/// <https://docs.snowflake.com/en/sql-reference/sql/alter-table#clustering-actions-clusteringaction>
ClusterBy {
exprs: Vec<Expr>,
},
DropClusteringKey,
SuspendRecluster,
ResumeRecluster,
}
/// An `ALTER Policy` (`Statement::AlterPolicy`) operation
@ -548,6 +585,22 @@ impl fmt::Display for AlterTableOperation {
}
Ok(())
}
AlterTableOperation::ClusterBy { exprs } => {
write!(f, "CLUSTER BY ({})", display_comma_separated(exprs))?;
Ok(())
}
AlterTableOperation::DropClusteringKey => {
write!(f, "DROP CLUSTERING KEY")?;
Ok(())
}
AlterTableOperation::SuspendRecluster => {
write!(f, "SUSPEND RECLUSTER")?;
Ok(())
}
AlterTableOperation::ResumeRecluster => {
write!(f, "RESUME RECLUSTER")?;
Ok(())
}
}
}
}

View file

@ -1020,6 +1020,10 @@ impl Spanned for AlterTableOperation {
union_spans(table_properties.iter().map(|i| i.span()))
}
AlterTableOperation::OwnerTo { .. } => Span::empty(),
AlterTableOperation::ClusterBy { exprs } => union_spans(exprs.iter().map(|e| e.span())),
AlterTableOperation::DropClusteringKey => Span::empty(),
AlterTableOperation::SuspendRecluster => Span::empty(),
AlterTableOperation::ResumeRecluster => Span::empty(),
}
}
}

View file

@ -168,6 +168,7 @@ define_keywords!(
CLOSE,
CLUSTER,
CLUSTERED,
CLUSTERING,
COALESCE,
COLLATE,
COLLATION,
@ -622,6 +623,7 @@ define_keywords!(
READS,
READ_ONLY,
REAL,
RECLUSTER,
RECURSIVE,
REF,
REFERENCES,
@ -656,6 +658,7 @@ define_keywords!(
RESTRICTIVE,
RESULT,
RESULTSET,
RESUME,
RETAIN,
RETURN,
RETURNING,
@ -745,6 +748,7 @@ define_keywords!(
SUM,
SUPER,
SUPERUSER,
SUSPEND,
SWAP,
SYMMETRIC,
SYNC,

View file

@ -7273,6 +7273,8 @@ impl<'a> Parser<'a> {
let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
let name = self.parse_identifier(false)?;
AlterTableOperation::DropProjection { if_exists, name }
} else if self.parse_keywords(&[Keyword::CLUSTERING, Keyword::KEY]) {
AlterTableOperation::DropClusteringKey
} else {
let _ = self.parse_keyword(Keyword::COLUMN); // [ COLUMN ]
let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
@ -7444,6 +7446,15 @@ impl<'a> Parser<'a> {
partition,
with_name,
}
} else if self.parse_keywords(&[Keyword::CLUSTER, Keyword::BY]) {
self.expect_token(&Token::LParen)?;
let exprs = self.parse_comma_separated(|parser| parser.parse_expr())?;
self.expect_token(&Token::RParen)?;
AlterTableOperation::ClusterBy { exprs }
} else if self.parse_keywords(&[Keyword::SUSPEND, Keyword::RECLUSTER]) {
AlterTableOperation::SuspendRecluster
} else if self.parse_keywords(&[Keyword::RESUME, Keyword::RECLUSTER]) {
AlterTableOperation::ResumeRecluster
} else {
let options: Vec<SqlOption> =
self.parse_options_with_keywords(&[Keyword::SET, Keyword::TBLPROPERTIES])?;

View file

@ -1411,6 +1411,42 @@ fn test_alter_table_swap_with() {
};
}
#[test]
fn test_alter_table_clustering() {
let sql = r#"ALTER TABLE tab CLUSTER BY (c1, "c2", TO_DATE(c3))"#;
match alter_table_op(snowflake_and_generic().verified_stmt(sql)) {
AlterTableOperation::ClusterBy { exprs } => {
assert_eq!(
exprs,
[
Expr::Identifier(Ident::new("c1")),
Expr::Identifier(Ident::with_quote('"', "c2")),
Expr::Function(Function {
name: ObjectName(vec![Ident::new("TO_DATE")]),
parameters: FunctionArguments::None,
args: FunctionArguments::List(FunctionArgumentList {
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
Expr::Identifier(Ident::new("c3"))
))],
duplicate_treatment: None,
clauses: vec![],
}),
filter: None,
null_treatment: None,
over: None,
within_group: vec![]
})
],
);
}
_ => unreachable!(),
}
snowflake_and_generic().verified_stmt("ALTER TABLE tbl DROP CLUSTERING KEY");
snowflake_and_generic().verified_stmt("ALTER TABLE tbl SUSPEND RECLUSTER");
snowflake_and_generic().verified_stmt("ALTER TABLE tbl RESUME RECLUSTER");
}
#[test]
fn test_drop_stage() {
match snowflake_and_generic().verified_stmt("DROP STAGE s1") {