From 6dd0bf120f6e98887a81fab798adc055ada7be5c Mon Sep 17 00:00:00 2001 From: sabir-akhadov-localstack Date: Tue, 1 Sep 2026 10:56:15 +0200 Subject: [PATCH 1/2] Snowflake: Add SHOW EXTERNAL VOLUMES Co-Authored-By: Claude Fable 5 --- src/ast/mod.rs | 34 ++++++++++++++++++++++++++++++++++ src/ast/spans.rs | 1 + src/dialect/snowflake.rs | 14 ++++++++++++-- src/keywords.rs | 1 + tests/sqlparser_snowflake.rs | 22 ++++++++++++++++++++++ 5 files changed, 70 insertions(+), 2 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 87618bbc5f..ed8f86f115 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -4648,6 +4648,11 @@ pub enum Statement { comment: Option, }, /// ```sql + /// SHOW EXTERNAL VOLUMES [LIKE ''] + /// ``` + /// See + ShowExternalVolumes(ShowExternalVolumes), + /// ```sql /// CREATE [ OR REPLACE ] WAREHOUSE [ IF NOT EXISTS ] /// [ [ WITH ] = [ ... ] ] /// ``` @@ -6373,6 +6378,7 @@ impl fmt::Display for Statement { } Ok(()) } + Statement::ShowExternalVolumes(s) => write!(f, "{s}"), Statement::CreateWarehouse(s) => write!(f, "{s}"), Statement::CopyIntoSnowflake { kind, @@ -11256,6 +11262,28 @@ pub struct ShowObjects { pub show_options: ShowStatementOptions, } +/// ```sql +/// SHOW EXTERNAL VOLUMES [LIKE ''] +/// ``` +/// See +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] +pub struct ShowExternalVolumes { + /// Optional filter (e.g. `LIKE`). + pub filter: Option, +} + +impl fmt::Display for ShowExternalVolumes { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "SHOW EXTERNAL VOLUMES")?; + if let Some(ref filter) = self.filter { + write!(f, " {filter}")?; + } + Ok(()) + } +} + /// MSSQL's json null clause /// /// ```plaintext @@ -12751,6 +12779,12 @@ impl From for Statement { } } +impl From for Statement { + fn from(s: ShowExternalVolumes) -> Self { + Self::ShowExternalVolumes(s) + } +} + impl From for Statement { fn from(c: CreateWarehouse) -> Self { Self::CreateWarehouse(c) diff --git a/src/ast/spans.rs b/src/ast/spans.rs index 74e0844d56..24bd0349bc 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -529,6 +529,7 @@ impl Spanned for Statement { Statement::AlterUser(..) => Span::empty(), Statement::Reset(..) => Span::empty(), Statement::CreateAggregate(create_aggregate) => create_aggregate.span(), + Statement::ShowExternalVolumes(..) => Span::empty(), } } } diff --git a/src/dialect/snowflake.rs b/src/dialect/snowflake.rs index dc462f5ba2..c46875306b 100644 --- a/src/dialect/snowflake.rs +++ b/src/dialect/snowflake.rs @@ -33,8 +33,9 @@ use crate::ast::{ IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder, InitializeKind, Insert, MultiTableInsertIntoClause, MultiTableInsertType, MultiTableInsertValue, MultiTableInsertValues, MultiTableInsertWhenClause, ObjectName, ObjectNamePart, - RefreshModeKind, RowAccessPolicy, ShowObjects, SqlOption, Statement, StorageLifecyclePolicy, - StorageSerializationPolicy, TableObject, TagsColumnOption, Value, WrappedCollection, + RefreshModeKind, RowAccessPolicy, ShowExternalVolumes, ShowObjects, SqlOption, Statement, + StorageLifecyclePolicy, StorageSerializationPolicy, TableObject, TagsColumnOption, Value, + WrappedCollection, }; use crate::dialect::{Dialect, Precedence}; use crate::keywords::Keyword; @@ -394,6 +395,9 @@ impl Dialect for SnowflakeDialect { } if parser.parse_keyword(Keyword::SHOW) { + if parser.parse_keywords(&[Keyword::EXTERNAL, Keyword::VOLUMES]) { + return Some(parse_show_external_volumes(parser)); + } let terse = parser.parse_keyword(Keyword::TERSE); if parser.parse_keyword(Keyword::OBJECTS) { return Some(parse_show_objects(terse, parser)); @@ -2031,3 +2035,9 @@ fn parse_multi_table_insert_when_clauses( Ok((when_clauses, else_clause)) } + +/// Parse `SHOW EXTERNAL VOLUMES [LIKE '']` +fn parse_show_external_volumes(parser: &mut Parser) -> Result { + let filter = parser.parse_show_statement_filter()?; + Ok(ShowExternalVolumes { filter }.into()) +} diff --git a/src/keywords.rs b/src/keywords.rs index b35644befb..39f36def7d 100644 --- a/src/keywords.rs +++ b/src/keywords.rs @@ -1195,6 +1195,7 @@ define_keywords!( VIRTUAL, VOLATILE, VOLUME, + VOLUMES, WAITFOR, WAREHOUSE, WAREHOUSES, diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index 5e3cbc8e01..0c0fa28b42 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -5042,3 +5042,25 @@ fn test_stage_name_delimiters() { ParserError::ParserError("Expected: stage name identifier, found: .".to_string()), ); } + +#[test] +fn test_show_external_volumes() { + match snowflake().verified_stmt("SHOW EXTERNAL VOLUMES") { + Statement::ShowExternalVolumes(ShowExternalVolumes { filter }) => { + assert!(filter.is_none()); + } + _ => unreachable!(), + } +} + +#[test] +fn test_show_external_volumes_like() { + match snowflake().verified_stmt("SHOW EXTERNAL VOLUMES LIKE 'my_%'") { + Statement::ShowExternalVolumes(ShowExternalVolumes { + filter: Some(ShowStatementFilter::Like(pattern)), + }) => { + assert_eq!("my_%", pattern); + } + _ => unreachable!(), + } +} From 55bd0f455b9eae1689acc94ddb84908224da0841 Mon Sep 17 00:00:00 2001 From: sabir-akhadov-localstack Date: Thu, 15 Oct 2026 14:39:31 +0200 Subject: [PATCH 2/2] Add tests for SHOW EXTERNAL VOLUMES coverage Co-Authored-By: Claude Opus 5.5 --- tests/sqlparser_snowflake.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index 0c0fa28b42..9a434bec6c 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -5045,12 +5045,21 @@ fn test_stage_name_delimiters() { #[test] fn test_show_external_volumes() { - match snowflake().verified_stmt("SHOW EXTERNAL VOLUMES") { + let stmt = snowflake().verified_stmt("SHOW EXTERNAL VOLUMES"); + assert_eq!(Span::empty(), stmt.span()); + match stmt { Statement::ShowExternalVolumes(ShowExternalVolumes { filter }) => { assert!(filter.is_none()); } _ => unreachable!(), } + + assert_eq!( + snowflake() + .parse_sql_statements("SHOW EXTERNAL VOLUMES LIKE") + .unwrap_err(), + ParserError::ParserError("Expected: literal string, found: EOF".to_string()) + ); } #[test]