Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions src/ast/ddl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -3880,8 +3889,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
Expand Down Expand Up @@ -3911,6 +3923,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 ")?,
}

Expand Down
2 changes: 1 addition & 1 deletion src/ast/spans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
46 changes: 45 additions & 1 deletion src/dialect/snowflake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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> {
Expand Down
6 changes: 6 additions & 0 deletions tests/sqlparser_snowflake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4635,3 +4635,9 @@ 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");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we add a test scenario that includes the 'IF EXISTS' clause?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@iffyio Updated. Thank you

snowflake().verified_stmt("ALTER EXTERNAL TABLE some_table REFRESH 'year=2025/month=12/'");
}