diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 4d86dd6a6..3003d3c89 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -4558,6 +4558,11 @@ pub enum Statement { comment: Option, }, /// ```sql + /// SHOW EXTERNAL VOLUMES [LIKE ''] + /// ``` + /// See + ShowExternalVolumes(ShowExternalVolumes), + /// ```sql /// CREATE [ OR REPLACE ] WAREHOUSE [ IF NOT EXISTS ] /// [ [ WITH ] = [ ... ] ] /// ``` @@ -6293,6 +6298,7 @@ impl fmt::Display for Statement { } Ok(()) } + Statement::ShowExternalVolumes(s) => write!(f, "{s}"), Statement::CreateWarehouse(s) => write!(f, "{s}"), Statement::CopyIntoSnowflake { kind, @@ -11131,6 +11137,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 @@ -12626,6 +12654,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 a34fe66d9..c7ef4d132 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -523,6 +523,7 @@ impl Spanned for Statement { Statement::Vacuum(..) => Span::empty(), Statement::AlterUser(..) => Span::empty(), Statement::Reset(..) => Span::empty(), + Statement::ShowExternalVolumes(..) => Span::empty(), } } } diff --git a/src/dialect/snowflake.rs b/src/dialect/snowflake.rs index 0bedb12a5..db90fce73 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; @@ -368,6 +369,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)); @@ -1988,3 +1992,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 0c50703c3..27c27b8dc 100644 --- a/src/keywords.rs +++ b/src/keywords.rs @@ -1162,6 +1162,7 @@ define_keywords!( VIRTUAL, VOLATILE, VOLUME, + VOLUMES, WAITFOR, WAREHOUSE, WAREHOUSES, diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index 059560dcc..aaead8d76 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -4912,3 +4912,25 @@ fn test_select_dollar_column_from_stage() { // With table function args, without alias snowflake().verified_stmt("SELECT $1, $2 FROM @mystage1(file_format => 'myformat')"); } + +#[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!(), + } +}