This is an automated email from the ASF dual-hosted git repository.

iffyio pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git


The following commit(s) were added to refs/heads/main by this push:
     new 5327f0ce Add ICEBERG keyword support to ALTER TABLE statement (#1869)
5327f0ce is described below

commit 5327f0ce132e12de71db7d03711397c5ac6c0031
Author: Artem Osipov <59066880+osipovar...@users.noreply.github.com>
AuthorDate: Wed Jun 4 20:49:07 2025 +0300

    Add ICEBERG keyword support to ALTER TABLE statement (#1869)
---
 src/ast/mod.rs               | 13 +++++++--
 src/ast/spans.rs             |  1 +
 src/parser/mod.rs            | 65 +++++++++++++++++++++++++-------------------
 src/test_utils.rs            |  2 ++
 tests/sqlparser_mysql.rs     |  8 +++---
 tests/sqlparser_postgres.rs  |  6 ++--
 tests/sqlparser_snowflake.rs |  7 +++++
 7 files changed, 64 insertions(+), 38 deletions(-)

diff --git a/src/ast/mod.rs b/src/ast/mod.rs
index 653f58e4..711e580d 100644
--- a/src/ast/mod.rs
+++ b/src/ast/mod.rs
@@ -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 ")?;
                 }
diff --git a/src/ast/spans.rs b/src/ast/spans.rs
index d612738c..dd918c34 100644
--- a/src/ast/spans.rs
+++ b/src/ast/spans.rs
@@ -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()))
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index a28540d1..3e721072 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -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)?;
diff --git a/src/test_utils.rs b/src/test_utils.rs
index 3c22fa91..24c0ca57 100644
--- a/src/test_utils.rs
+++ b/src/test_utils.rs
@@ -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"),
diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs
index 337707c9..0800c329 100644
--- a/tests/sqlparser_mysql.rs
+++ b/tests/sqlparser_mysql.rs
@@ -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);
diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs
index 682c0d6c..d54d4e2a 100644
--- a/tests/sqlparser_postgres.rs
+++ b/tests/sqlparser_postgres.rs
@@ -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!(
diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs
index 52be3143..b4d62506 100644
--- a/tests/sqlparser_snowflake.rs
+++ b/tests/sqlparser_snowflake.rs
@@ -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") {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@datafusion.apache.org
For additional commands, e-mail: commits-h...@datafusion.apache.org

Reply via email to