Add ICEBERG keyword support to ALTER TABLE statement (#1869)

This commit is contained in:
Artem Osipov 2025-06-04 20:49:07 +03:00 committed by GitHub
parent 394a534486
commit 5327f0ce13
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 64 additions and 38 deletions

View file

@ -3281,6 +3281,9 @@ pub enum Statement {
/// For example: `ALTER TABLE table_name ON CLUSTER cluster_name ADD COLUMN c UInt32`
/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/update)
on_cluster: Option<Ident>,
/// Snowflake "ICEBERG" clause for Iceberg tables
/// <https://docs.snowflake.com/en/sql-reference/sql/alter-iceberg-table>
iceberg: bool,
},
/// ```sql
/// ALTER INDEX
@ -3405,7 +3408,7 @@ pub enum Statement {
purge: bool,
/// MySQL-specific "TEMPORARY" keyword
temporary: bool,
/// MySQL-specific drop index syntax, which requires table specification
/// MySQL-specific drop index syntax, which requires table specification
/// See <https://dev.mysql.com/doc/refman/8.4/en/drop-index.html>
table: Option<ObjectName>,
},
@ -5139,8 +5142,14 @@ impl fmt::Display for Statement {
operations,
location,
on_cluster,
iceberg,
} => {
write!(f, "ALTER TABLE ")?;
if *iceberg {
write!(f, "ALTER ICEBERG TABLE ")?;
} else {
write!(f, "ALTER TABLE ")?;
}
if *if_exists {
write!(f, "IF EXISTS ")?;
}

View file

@ -431,6 +431,7 @@ impl Spanned for Statement {
operations,
location: _,
on_cluster,
iceberg: _,
} => union_spans(
core::iter::once(name.span())
.chain(operations.iter().map(|i| i.span()))

View file

@ -8893,38 +8893,15 @@ impl<'a> Parser<'a> {
Keyword::ROLE,
Keyword::POLICY,
Keyword::CONNECTOR,
Keyword::ICEBERG,
])?;
match object_type {
Keyword::VIEW => self.parse_alter_view(),
Keyword::TYPE => self.parse_alter_type(),
Keyword::TABLE => {
let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
let only = self.parse_keyword(Keyword::ONLY); // [ ONLY ]
let table_name = self.parse_object_name(false)?;
let on_cluster = self.parse_optional_on_cluster()?;
let operations = self.parse_comma_separated(Parser::parse_alter_table_operation)?;
let mut location = None;
if self.parse_keyword(Keyword::LOCATION) {
location = Some(HiveSetLocation {
has_set: false,
location: self.parse_identifier()?,
});
} else if self.parse_keywords(&[Keyword::SET, Keyword::LOCATION]) {
location = Some(HiveSetLocation {
has_set: true,
location: self.parse_identifier()?,
});
}
Ok(Statement::AlterTable {
name: table_name,
if_exists,
only,
operations,
location,
on_cluster,
})
Keyword::TABLE => self.parse_alter_table(false),
Keyword::ICEBERG => {
self.expect_keyword(Keyword::TABLE)?;
self.parse_alter_table(true)
}
Keyword::INDEX => {
let index_name = self.parse_object_name(false)?;
@ -8952,6 +8929,38 @@ impl<'a> Parser<'a> {
}
}
/// Parse a [Statement::AlterTable]
pub fn parse_alter_table(&mut self, iceberg: bool) -> Result<Statement, ParserError> {
let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
let only = self.parse_keyword(Keyword::ONLY); // [ ONLY ]
let table_name = self.parse_object_name(false)?;
let on_cluster = self.parse_optional_on_cluster()?;
let operations = self.parse_comma_separated(Parser::parse_alter_table_operation)?;
let mut location = None;
if self.parse_keyword(Keyword::LOCATION) {
location = Some(HiveSetLocation {
has_set: false,
location: self.parse_identifier()?,
});
} else if self.parse_keywords(&[Keyword::SET, Keyword::LOCATION]) {
location = Some(HiveSetLocation {
has_set: true,
location: self.parse_identifier()?,
});
}
Ok(Statement::AlterTable {
name: table_name,
if_exists,
only,
operations,
location,
on_cluster,
iceberg,
})
}
pub fn parse_alter_view(&mut self) -> Result<Statement, ParserError> {
let name = self.parse_object_name(false)?;
let columns = self.parse_parenthesized_column_list(Optional, false)?;

View file

@ -345,10 +345,12 @@ pub fn alter_table_op_with_name(stmt: Statement, expected_name: &str) -> AlterTa
operations,
on_cluster: _,
location: _,
iceberg,
} => {
assert_eq!(name.to_string(), expected_name);
assert!(!if_exists);
assert!(!is_only);
assert!(!iceberg);
only(operations)
}
_ => panic!("Expected ALTER TABLE statement"),

View file

@ -2507,11 +2507,13 @@ fn parse_alter_table_add_column() {
if_exists,
only,
operations,
iceberg,
location: _,
on_cluster: _,
} => {
assert_eq!(name.to_string(), "tab");
assert!(!if_exists);
assert!(!iceberg);
assert!(!only);
assert_eq!(
operations,
@ -2536,8 +2538,7 @@ fn parse_alter_table_add_column() {
if_exists,
only,
operations,
location: _,
on_cluster: _,
..
} => {
assert_eq!(name.to_string(), "tab");
assert!(!if_exists);
@ -2574,8 +2575,7 @@ fn parse_alter_table_add_columns() {
if_exists,
only,
operations,
location: _,
on_cluster: _,
..
} => {
assert_eq!(name.to_string(), "tab");
assert!(!if_exists);

View file

@ -834,8 +834,7 @@ fn parse_alter_table_add_columns() {
if_exists,
only,
operations,
location: _,
on_cluster: _,
..
} => {
assert_eq!(name.to_string(), "tab");
assert!(if_exists);
@ -915,8 +914,7 @@ fn parse_alter_table_owner_to() {
if_exists: _,
only: _,
operations,
location: _,
on_cluster: _,
..
} => {
assert_eq!(name.to_string(), "tab");
assert_eq!(

View file

@ -1591,6 +1591,13 @@ fn test_alter_table_clustering() {
snowflake_and_generic().verified_stmt("ALTER TABLE tbl RESUME RECLUSTER");
}
#[test]
fn test_alter_iceberg_table() {
snowflake_and_generic().verified_stmt("ALTER ICEBERG TABLE tbl DROP CLUSTERING KEY");
snowflake_and_generic().verified_stmt("ALTER ICEBERG TABLE tbl SUSPEND RECLUSTER");
snowflake_and_generic().verified_stmt("ALTER ICEBERG TABLE tbl RESUME RECLUSTER");
}
#[test]
fn test_drop_stage() {
match snowflake_and_generic().verified_stmt("DROP STAGE s1") {