Skip to content

Commit afddab7

Browse files
committed
Added alter external table support for snowflake
1 parent effaac5 commit afddab7

File tree

4 files changed

+71
-8
lines changed

4 files changed

+71
-8
lines changed

src/ast/ddl.rs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -371,10 +371,15 @@ pub enum AlterTableOperation {
371371
DropClusteringKey,
372372
SuspendRecluster,
373373
ResumeRecluster,
374-
/// `REFRESH`
374+
/// `REFRESH [ '<subpath>' ]`
375375
///
376-
/// Note: this is Snowflake specific for dynamic tables <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
377-
Refresh,
376+
/// Note: this is Snowflake specific for dynamic/external tables
377+
/// <https://docs.snowflake.com/en/sql-reference/sql/alter-dynamic-table>
378+
/// <https://docs.snowflake.com/en/sql-reference/sql/alter-external-table>
379+
Refresh {
380+
/// Optional subpath for external table refresh
381+
subpath: Option<String>,
382+
},
378383
/// `SUSPEND`
379384
///
380385
/// 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 {
863868
write!(f, "RESUME RECLUSTER")?;
864869
Ok(())
865870
}
866-
AlterTableOperation::Refresh => {
867-
write!(f, "REFRESH")
871+
AlterTableOperation::Refresh { subpath } => {
872+
write!(f, "REFRESH")?;
873+
if let Some(path) = subpath {
874+
write!(f, " '{path}'")?;
875+
}
876+
Ok(())
868877
}
869878
AlterTableOperation::Suspend => {
870879
write!(f, "SUSPEND")
@@ -3880,8 +3889,11 @@ pub enum AlterTableType {
38803889
/// <https://docs.snowflake.com/en/sql-reference/sql/alter-iceberg-table>
38813890
Iceberg,
38823891
/// Dynamic table type
3883-
/// <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
3892+
/// <https://docs.snowflake.com/en/sql-reference/sql/alter-dynamic-table>
38843893
Dynamic,
3894+
/// External table type
3895+
/// <https://docs.snowflake.com/en/sql-reference/sql/alter-external-table>
3896+
External,
38853897
}
38863898

38873899
/// ALTER TABLE statement
@@ -3911,6 +3923,7 @@ impl fmt::Display for AlterTable {
39113923
match &self.table_type {
39123924
Some(AlterTableType::Iceberg) => write!(f, "ALTER ICEBERG TABLE ")?,
39133925
Some(AlterTableType::Dynamic) => write!(f, "ALTER DYNAMIC TABLE ")?,
3926+
Some(AlterTableType::External) => write!(f, "ALTER EXTERNAL TABLE ")?,
39143927
None => write!(f, "ALTER TABLE ")?,
39153928
}
39163929

src/ast/spans.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1145,7 +1145,7 @@ impl Spanned for AlterTableOperation {
11451145
AlterTableOperation::DropClusteringKey => Span::empty(),
11461146
AlterTableOperation::SuspendRecluster => Span::empty(),
11471147
AlterTableOperation::ResumeRecluster => Span::empty(),
1148-
AlterTableOperation::Refresh => Span::empty(),
1148+
AlterTableOperation::Refresh { .. } => Span::empty(),
11491149
AlterTableOperation::Suspend => Span::empty(),
11501150
AlterTableOperation::Resume => Span::empty(),
11511151
AlterTableOperation::Algorithm { .. } => Span::empty(),

src/dialect/snowflake.rs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,11 @@ impl Dialect for SnowflakeDialect {
221221
return Some(parse_alter_dynamic_table(parser));
222222
}
223223

224+
if parser.parse_keywords(&[Keyword::ALTER, Keyword::EXTERNAL, Keyword::TABLE]) {
225+
// ALTER EXTERNAL TABLE
226+
return Some(parse_alter_external_table(parser));
227+
}
228+
224229
if parser.parse_keywords(&[Keyword::ALTER, Keyword::SESSION]) {
225230
// ALTER SESSION
226231
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
619624

620625
// Parse the operation (REFRESH, SUSPEND, or RESUME)
621626
let operation = if parser.parse_keyword(Keyword::REFRESH) {
622-
AlterTableOperation::Refresh
627+
AlterTableOperation::Refresh { subpath: None }
623628
} else if parser.parse_keyword(Keyword::SUSPEND) {
624629
AlterTableOperation::Suspend
625630
} else if parser.parse_keyword(Keyword::RESUME) {
@@ -649,6 +654,45 @@ fn parse_alter_dynamic_table(parser: &mut Parser) -> Result<Statement, ParserErr
649654
}))
650655
}
651656

657+
/// Parse snowflake alter external table.
658+
/// <https://docs.snowflake.com/en/sql-reference/sql/alter-external-table>
659+
fn parse_alter_external_table(parser: &mut Parser) -> Result<Statement, ParserError> {
660+
let if_exists = parser.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
661+
let table_name = parser.parse_object_name(true)?;
662+
663+
// Parse the operation (REFRESH for now)
664+
let operation = if parser.parse_keyword(Keyword::REFRESH) {
665+
// Optional subpath for refreshing specific partitions
666+
let subpath = match parser.peek_token().token {
667+
Token::SingleQuotedString(s) => {
668+
parser.next_token();
669+
Some(s)
670+
}
671+
_ => None,
672+
};
673+
AlterTableOperation::Refresh { subpath }
674+
} else {
675+
return parser.expected("REFRESH after ALTER EXTERNAL TABLE", parser.peek_token());
676+
};
677+
678+
let end_token = if parser.peek_token_ref().token == Token::SemiColon {
679+
parser.peek_token_ref().clone()
680+
} else {
681+
parser.get_current_token().clone()
682+
};
683+
684+
Ok(Statement::AlterTable(AlterTable {
685+
name: table_name,
686+
if_exists,
687+
only: false,
688+
operations: vec![operation],
689+
location: None,
690+
on_cluster: None,
691+
table_type: Some(AlterTableType::External),
692+
end_token: AttachedToken(end_token),
693+
}))
694+
}
695+
652696
/// Parse snowflake alter session.
653697
/// <https://docs.snowflake.com/en/sql-reference/sql/alter-session>
654698
fn parse_alter_session(parser: &mut Parser, set: bool) -> Result<Statement, ParserError> {

tests/sqlparser_snowflake.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4635,3 +4635,9 @@ fn test_alter_dynamic_table() {
46354635
snowflake().verified_stmt("ALTER DYNAMIC TABLE my_dyn_table SUSPEND");
46364636
snowflake().verified_stmt("ALTER DYNAMIC TABLE my_dyn_table RESUME");
46374637
}
4638+
4639+
#[test]
4640+
fn test_alter_external_table() {
4641+
snowflake().verified_stmt("ALTER EXTERNAL TABLE some_table REFRESH");
4642+
snowflake().verified_stmt("ALTER EXTERNAL TABLE some_table REFRESH 'year=2025/month=12/'");
4643+
}

0 commit comments

Comments
 (0)