You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by gi...@apache.org on 2025/12/10 11:51:59 UTC

(datafusion-sqlparser-rs) branch gh-readonly-queue/main/pr-2122-adbfc46177aad76b7d67d85fba0dea38a4f777cb created (now 048bc8f0)

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

github-bot pushed a change to branch gh-readonly-queue/main/pr-2122-adbfc46177aad76b7d67d85fba0dea38a4f777cb
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git


      at 048bc8f0 Added alter external table support for snowflake (#2122)

This branch includes the following new commits:

     new 048bc8f0 Added alter external table support for snowflake (#2122)

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



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


(datafusion-sqlparser-rs) 01/01: Added alter external table support for snowflake (#2122)

Posted by gi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

github-bot pushed a commit to branch gh-readonly-queue/main/pr-2122-adbfc46177aad76b7d67d85fba0dea38a4f777cb
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git

commit 048bc8f09d569d223db36db577b18c7466d55005
Author: Andriy Romanov <ar...@montecarlodata.com>
AuthorDate: Wed Dec 10 03:51:44 2025 -0800

    Added alter external table support for snowflake (#2122)
---
 src/ast/ddl.rs               | 25 ++++++++++++++++++------
 src/ast/spans.rs             |  2 +-
 src/dialect/snowflake.rs     | 46 +++++++++++++++++++++++++++++++++++++++++++-
 tests/sqlparser_snowflake.rs |  9 +++++++++
 4 files changed, 74 insertions(+), 8 deletions(-)

diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs
index 3516c64a..8ccd533c 100644
--- a/src/ast/ddl.rs
+++ b/src/ast/ddl.rs
@@ -371,10 +371,15 @@ pub enum AlterTableOperation {
     DropClusteringKey,
     SuspendRecluster,
     ResumeRecluster,
-    /// `REFRESH`
+    /// `REFRESH [ '<subpath>' ]`
     ///
-    /// Note: this is Snowflake specific for dynamic tables <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
-    Refresh,
+    /// Note: this is Snowflake specific for dynamic/external tables
+    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-dynamic-table>
+    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-external-table>
+    Refresh {
+        /// Optional subpath for external table refresh
+        subpath: Option<String>,
+    },
     /// `SUSPEND`
     ///
     /// Note: this is Snowflake specific for dynamic tables <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
@@ -863,8 +868,12 @@ impl fmt::Display for AlterTableOperation {
                 write!(f, "RESUME RECLUSTER")?;
                 Ok(())
             }
-            AlterTableOperation::Refresh => {
-                write!(f, "REFRESH")
+            AlterTableOperation::Refresh { subpath } => {
+                write!(f, "REFRESH")?;
+                if let Some(path) = subpath {
+                    write!(f, " '{path}'")?;
+                }
+                Ok(())
             }
             AlterTableOperation::Suspend => {
                 write!(f, "SUSPEND")
@@ -3977,8 +3986,11 @@ pub enum AlterTableType {
     /// <https://docs.snowflake.com/en/sql-reference/sql/alter-iceberg-table>
     Iceberg,
     /// Dynamic table type
-    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
+    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-dynamic-table>
     Dynamic,
+    /// External table type
+    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-external-table>
+    External,
 }
 
 /// ALTER TABLE statement
@@ -4008,6 +4020,7 @@ impl fmt::Display for AlterTable {
         match &self.table_type {
             Some(AlterTableType::Iceberg) => write!(f, "ALTER ICEBERG TABLE ")?,
             Some(AlterTableType::Dynamic) => write!(f, "ALTER DYNAMIC TABLE ")?,
+            Some(AlterTableType::External) => write!(f, "ALTER EXTERNAL TABLE ")?,
             None => write!(f, "ALTER TABLE ")?,
         }
 
diff --git a/src/ast/spans.rs b/src/ast/spans.rs
index d63ed62b..de8fba75 100644
--- a/src/ast/spans.rs
+++ b/src/ast/spans.rs
@@ -1145,7 +1145,7 @@ impl Spanned for AlterTableOperation {
             AlterTableOperation::DropClusteringKey => Span::empty(),
             AlterTableOperation::SuspendRecluster => Span::empty(),
             AlterTableOperation::ResumeRecluster => Span::empty(),
-            AlterTableOperation::Refresh => Span::empty(),
+            AlterTableOperation::Refresh { .. } => Span::empty(),
             AlterTableOperation::Suspend => Span::empty(),
             AlterTableOperation::Resume => Span::empty(),
             AlterTableOperation::Algorithm { .. } => Span::empty(),
diff --git a/src/dialect/snowflake.rs b/src/dialect/snowflake.rs
index 4cfaddce..ed01c128 100644
--- a/src/dialect/snowflake.rs
+++ b/src/dialect/snowflake.rs
@@ -221,6 +221,11 @@ impl Dialect for SnowflakeDialect {
             return Some(parse_alter_dynamic_table(parser));
         }
 
+        if parser.parse_keywords(&[Keyword::ALTER, Keyword::EXTERNAL, Keyword::TABLE]) {
+            // ALTER EXTERNAL TABLE
+            return Some(parse_alter_external_table(parser));
+        }
+
         if parser.parse_keywords(&[Keyword::ALTER, Keyword::SESSION]) {
             // ALTER SESSION
             let set = match parser.parse_one_of_keywords(&[Keyword::SET, Keyword::UNSET]) {
@@ -619,7 +624,7 @@ fn parse_alter_dynamic_table(parser: &mut Parser) -> Result<Statement, ParserErr
 
     // Parse the operation (REFRESH, SUSPEND, or RESUME)
     let operation = if parser.parse_keyword(Keyword::REFRESH) {
-        AlterTableOperation::Refresh
+        AlterTableOperation::Refresh { subpath: None }
     } else if parser.parse_keyword(Keyword::SUSPEND) {
         AlterTableOperation::Suspend
     } else if parser.parse_keyword(Keyword::RESUME) {
@@ -649,6 +654,45 @@ fn parse_alter_dynamic_table(parser: &mut Parser) -> Result<Statement, ParserErr
     }))
 }
 
+/// Parse snowflake alter external table.
+/// <https://docs.snowflake.com/en/sql-reference/sql/alter-external-table>
+fn parse_alter_external_table(parser: &mut Parser) -> Result<Statement, ParserError> {
+    let if_exists = parser.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
+    let table_name = parser.parse_object_name(true)?;
+
+    // Parse the operation (REFRESH for now)
+    let operation = if parser.parse_keyword(Keyword::REFRESH) {
+        // Optional subpath for refreshing specific partitions
+        let subpath = match parser.peek_token().token {
+            Token::SingleQuotedString(s) => {
+                parser.next_token();
+                Some(s)
+            }
+            _ => None,
+        };
+        AlterTableOperation::Refresh { subpath }
+    } else {
+        return parser.expected("REFRESH after ALTER EXTERNAL TABLE", parser.peek_token());
+    };
+
+    let end_token = if parser.peek_token_ref().token == Token::SemiColon {
+        parser.peek_token_ref().clone()
+    } else {
+        parser.get_current_token().clone()
+    };
+
+    Ok(Statement::AlterTable(AlterTable {
+        name: table_name,
+        if_exists,
+        only: false,
+        operations: vec![operation],
+        location: None,
+        on_cluster: None,
+        table_type: Some(AlterTableType::External),
+        end_token: AttachedToken(end_token),
+    }))
+}
+
 /// Parse snowflake alter session.
 /// <https://docs.snowflake.com/en/sql-reference/sql/alter-session>
 fn parse_alter_session(parser: &mut Parser, set: bool) -> Result<Statement, ParserError> {
diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs
index 22a63266..37e9f8cb 100644
--- a/tests/sqlparser_snowflake.rs
+++ b/tests/sqlparser_snowflake.rs
@@ -4635,3 +4635,12 @@ fn test_alter_dynamic_table() {
     snowflake().verified_stmt("ALTER DYNAMIC TABLE my_dyn_table SUSPEND");
     snowflake().verified_stmt("ALTER DYNAMIC TABLE my_dyn_table RESUME");
 }
+
+#[test]
+fn test_alter_external_table() {
+    snowflake().verified_stmt("ALTER EXTERNAL TABLE some_table REFRESH");
+    snowflake().verified_stmt("ALTER EXTERNAL TABLE some_table REFRESH 'year=2025/month=12/'");
+    snowflake().verified_stmt("ALTER EXTERNAL TABLE IF EXISTS some_table REFRESH");
+    snowflake()
+        .verified_stmt("ALTER EXTERNAL TABLE IF EXISTS some_table REFRESH 'year=2025/month=12/'");
+}


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