Skip to content

Commit

Permalink
Fix Snowflake wildcard REPLACE ... RENAME order
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-beedie committed Jun 23, 2024
1 parent a685e11 commit 7ef2d21
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 12 deletions.
13 changes: 7 additions & 6 deletions src/ast/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -547,19 +547,20 @@ impl fmt::Display for IdentWithAlias {
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct WildcardAdditionalOptions {
/// `[ILIKE...]`.
/// Snowflake syntax: <https://docs.snowflake.com/en/sql-reference/sql/select>
/// Snowflake syntax: <https://docs.snowflake.com/en/sql-reference/sql/select#parameters>
pub opt_ilike: Option<IlikeSelectItem>,
/// `[EXCLUDE...]`.
pub opt_exclude: Option<ExcludeSelectItem>,
/// `[EXCEPT...]`.
/// Clickhouse syntax: <https://clickhouse.com/docs/en/sql-reference/statements/select#except>
pub opt_except: Option<ExceptSelectItem>,
/// `[RENAME ...]`.
pub opt_rename: Option<RenameSelectItem>,
/// `[REPLACE]`
/// BigQuery syntax: <https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#select_replace>
/// Clickhouse syntax: <https://clickhouse.com/docs/en/sql-reference/statements/select#replace>
/// Snowflake syntax: <https://docs.snowflake.com/en/sql-reference/sql/select#parameters>
pub opt_replace: Option<ReplaceSelectItem>,
/// `[RENAME ...]`.
pub opt_rename: Option<RenameSelectItem>,
}

impl fmt::Display for WildcardAdditionalOptions {
Expand All @@ -573,12 +574,12 @@ impl fmt::Display for WildcardAdditionalOptions {
if let Some(except) = &self.opt_except {
write!(f, " {except}")?;
}
if let Some(rename) = &self.opt_rename {
write!(f, " {rename}")?;
}
if let Some(replace) = &self.opt_replace {
write!(f, " {replace}")?;
}
if let Some(rename) = &self.opt_rename {
write!(f, " {rename}")?;
}
Ok(())
}
}
Expand Down
11 changes: 5 additions & 6 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10175,15 +10175,14 @@ impl<'a> Parser<'a> {
} else {
None
};
let opt_rename = if dialect_of!(self is GenericDialect | SnowflakeDialect) {
self.parse_optional_select_item_rename()?
let opt_replace = if dialect_of!(self is GenericDialect | BigQueryDialect | ClickHouseDialect | DuckDbDialect | SnowflakeDialect)
{
self.parse_optional_select_item_replace()?
} else {
None
};

let opt_replace = if dialect_of!(self is GenericDialect | BigQueryDialect | ClickHouseDialect | DuckDbDialect | SnowflakeDialect)
{
self.parse_optional_select_item_replace()?
let opt_rename = if dialect_of!(self is GenericDialect | SnowflakeDialect) {
self.parse_optional_select_item_rename()?
} else {
None
};
Expand Down
38 changes: 38 additions & 0 deletions tests/sqlparser_snowflake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1016,6 +1016,43 @@ fn test_select_wildcard_with_rename() {
assert_eq!(expected, select.projection[0]);
}

Check failure on line 1018 in tests/sqlparser_snowflake.rs

View workflow job for this annotation

GitHub Actions / codestyle

Diff in /home/runner/work/sqlparser-rs/sqlparser-rs/tests/sqlparser_snowflake.rs
#[test]
fn test_select_wildcard_with_replace_and_rename() {
let select = snowflake_and_generic()
.verified_only_select("SELECT * REPLACE (col_z || col_z AS col_z) RENAME (col_z AS col_zz) FROM data");
let expected = SelectItem::Wildcard(WildcardAdditionalOptions {
opt_replace: Some(ReplaceSelectItem {
items: vec![Box::new(ReplaceSelectElement {
expr: Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::new("col_z"))),
op: BinaryOperator::StringConcat,
right: Box::new(Expr::Identifier(Ident::new("col_z"))),
},
column_name: Ident::new("col_z"),
as_keyword: true,

Check failure on line 1032 in tests/sqlparser_snowflake.rs

View workflow job for this annotation

GitHub Actions / codestyle

Diff in /home/runner/work/sqlparser-rs/sqlparser-rs/tests/sqlparser_snowflake.rs
})],
}),
opt_rename: Some(RenameSelectItem::Multiple(
vec![IdentWithAlias {
ident: Ident::new("col_z"),
alias: Ident::new("col_zz"),
}]
)),
..Default::default()
});
assert_eq!(expected, select.projection[0]);

// rename cannot precede replace
// https://docs.snowflake.com/en/sql-reference/sql/select#parameters

Check failure on line 1046 in tests/sqlparser_snowflake.rs

View workflow job for this annotation

GitHub Actions / codestyle

Diff in /home/runner/work/sqlparser-rs/sqlparser-rs/tests/sqlparser_snowflake.rs
assert_eq!(
snowflake_and_generic()
.parse_sql_statements("SELECT * RENAME (col_z AS col_zz) REPLACE (col_z || col_z AS col_z) FROM data")
.unwrap_err()
.to_string(),
"sql parser error: Expected: end of statement, found: REPLACE"
);
}

#[test]
fn test_select_wildcard_with_exclude_and_rename() {
let select = snowflake_and_generic()
Expand All @@ -1031,6 +1068,7 @@ fn test_select_wildcard_with_exclude_and_rename() {
assert_eq!(expected, select.projection[0]);

// rename cannot precede exclude
// https://docs.snowflake.com/en/sql-reference/sql/select#parameters
assert_eq!(
snowflake_and_generic()
.parse_sql_statements("SELECT * RENAME col_a AS col_b EXCLUDE col_z FROM data")
Expand Down

0 comments on commit 7ef2d21

Please sign in to comment.