Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
32 changes: 32 additions & 0 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4558,6 +4558,11 @@ pub enum Statement {
comment: Option<String>,
},
/// ```sql
/// DESC[RIBE] EXTERNAL VOLUME <name>
/// ```
/// See <https://docs.snowflake.com/en/sql-reference/sql/desc-external-volume>
DescribeExternalVolume(DescribeExternalVolume),
/// ```sql
/// CREATE [ OR REPLACE ] WAREHOUSE [ IF NOT EXISTS ] <name>
/// [ [ WITH ] <property> = <value> [ ... ] ]
/// ```
Expand Down Expand Up @@ -6293,6 +6298,7 @@ impl fmt::Display for Statement {
}
Ok(())
}
Statement::DescribeExternalVolume(s) => write!(f, "{s}"),
Statement::CreateWarehouse(s) => write!(f, "{s}"),
Statement::CopyIntoSnowflake {
kind,
Expand Down Expand Up @@ -11131,6 +11137,26 @@ pub struct ShowObjects {
pub show_options: ShowStatementOptions,
}

/// ```sql
/// DESC[RIBE] EXTERNAL VOLUME <name>
/// ```
/// See <https://docs.snowflake.com/en/sql-reference/sql/desc-external-volume>
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct DescribeExternalVolume {
/// The keyword used, `DESC` or `DESCRIBE`.
pub describe_alias: DescribeAlias,
/// External volume name.
pub name: ObjectName,
}

impl fmt::Display for DescribeExternalVolume {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} EXTERNAL VOLUME {}", self.describe_alias, self.name)
}
}

/// MSSQL's json null clause
///
/// ```plaintext
Expand Down Expand Up @@ -12626,6 +12652,12 @@ impl From<CreateUser> for Statement {
}
}

impl From<DescribeExternalVolume> for Statement {
fn from(d: DescribeExternalVolume) -> Self {
Self::DescribeExternalVolume(d)
}
}

impl From<CreateWarehouse> for Statement {
fn from(c: CreateWarehouse) -> Self {
Self::CreateWarehouse(c)
Expand Down
1 change: 1 addition & 0 deletions src/ast/spans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,7 @@ impl Spanned for Statement {
Statement::Vacuum(..) => Span::empty(),
Statement::AlterUser(..) => Span::empty(),
Statement::Reset(..) => Span::empty(),
Statement::DescribeExternalVolume(..) => Span::empty(),
}
}
}
Expand Down
40 changes: 34 additions & 6 deletions src/dialect/snowflake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,13 @@ use crate::ast::helpers::stmt_data_loading::{
use crate::ast::{
AlterTable, AlterTableOperation, AlterTableType, CatalogSyncNamespaceMode, ColumnOption,
ColumnPolicy, ColumnPolicyProperty, ContactEntry, CopyIntoSnowflakeKind, CreateTable,
CreateTableLikeKind, DollarQuotedString, Ident, IdentityParameters, IdentityProperty,
IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder, InitializeKind,
Insert, MultiTableInsertIntoClause, MultiTableInsertType, MultiTableInsertValue,
MultiTableInsertValues, MultiTableInsertWhenClause, ObjectName, ObjectNamePart,
RefreshModeKind, RowAccessPolicy, ShowObjects, SqlOption, Statement, StorageLifecyclePolicy,
StorageSerializationPolicy, TableObject, TagsColumnOption, Value, WrappedCollection,
CreateTableLikeKind, DescribeAlias, DescribeExternalVolume, DollarQuotedString, Ident,
IdentityParameters, IdentityProperty, IdentityPropertyFormatKind, IdentityPropertyKind,
IdentityPropertyOrder, InitializeKind, Insert, MultiTableInsertIntoClause,
MultiTableInsertType, MultiTableInsertValue, MultiTableInsertValues,
MultiTableInsertWhenClause, ObjectName, ObjectNamePart, RefreshModeKind, RowAccessPolicy,
ShowObjects, SqlOption, Statement, StorageLifecyclePolicy, StorageSerializationPolicy,
TableObject, TagsColumnOption, Value, WrappedCollection,
};
use crate::dialect::{Dialect, Precedence};
use crate::keywords::Keyword;
Expand Down Expand Up @@ -286,6 +287,20 @@ impl Dialect for SnowflakeDialect {
return Some(parse_alter_session(parser, set));
}

if let Some(kw) = parser.parse_one_of_keywords(&[Keyword::DESC, Keyword::DESCRIBE]) {
if parser.parse_keywords(&[Keyword::EXTERNAL, Keyword::VOLUME]) {
// DESC[RIBE] EXTERNAL VOLUME
let describe_alias = if kw == Keyword::DESC {
DescribeAlias::Desc
} else {
DescribeAlias::Describe
};
return Some(parse_describe_external_volume(describe_alias, parser));
}
// not EXTERNAL VOLUME — put back DESC/DESCRIBE
parser.prev_token();
}

if parser.parse_keyword(Keyword::CREATE) {
// possibly CREATE STAGE
//[ OR REPLACE ]
Expand Down Expand Up @@ -1988,3 +2003,16 @@ fn parse_multi_table_insert_when_clauses(

Ok((when_clauses, else_clause))
}

/// Parse `DESC[RIBE] EXTERNAL VOLUME <name>`
fn parse_describe_external_volume(
describe_alias: DescribeAlias,
parser: &mut Parser,
) -> Result<Statement, ParserError> {
let name = parser.parse_object_name(false)?;
Ok(DescribeExternalVolume {
describe_alias,
name,
}
.into())
}
29 changes: 29 additions & 0 deletions tests/sqlparser_snowflake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4912,3 +4912,32 @@ 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_describe_external_volume() {
match snowflake().verified_stmt("DESCRIBE EXTERNAL VOLUME my_vol") {
Statement::DescribeExternalVolume(DescribeExternalVolume {
describe_alias,
name,
}) => {
assert_eq!(DescribeAlias::Describe, describe_alias);
assert_eq!("my_vol", name.to_string());
}
_ => unreachable!(),
}
}

#[test]
fn test_desc_external_volume() {
// The DESC spelling is preserved on round-trip.
match snowflake().verified_stmt("DESC EXTERNAL VOLUME my_vol") {
Statement::DescribeExternalVolume(DescribeExternalVolume {
describe_alias,
name,
}) => {
assert_eq!(DescribeAlias::Desc, describe_alias);
assert_eq!("my_vol", name.to_string());
}
_ => unreachable!(),
}
}
Loading