Skip to content

Commit 7ef2d21

Browse files
Fix Snowflake wildcard REPLACE ... RENAME order
1 parent a685e11 commit 7ef2d21

3 files changed

Lines changed: 50 additions & 12 deletions

File tree

src/ast/query.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -547,19 +547,20 @@ impl fmt::Display for IdentWithAlias {
547547
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
548548
pub struct WildcardAdditionalOptions {
549549
/// `[ILIKE...]`.
550-
/// Snowflake syntax: <https://docs.snowflake.com/en/sql-reference/sql/select>
550+
/// Snowflake syntax: <https://docs.snowflake.com/en/sql-reference/sql/select#parameters>
551551
pub opt_ilike: Option<IlikeSelectItem>,
552552
/// `[EXCLUDE...]`.
553553
pub opt_exclude: Option<ExcludeSelectItem>,
554554
/// `[EXCEPT...]`.
555555
/// Clickhouse syntax: <https://clickhouse.com/docs/en/sql-reference/statements/select#except>
556556
pub opt_except: Option<ExceptSelectItem>,
557-
/// `[RENAME ...]`.
558-
pub opt_rename: Option<RenameSelectItem>,
559557
/// `[REPLACE]`
560558
/// BigQuery syntax: <https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#select_replace>
561559
/// Clickhouse syntax: <https://clickhouse.com/docs/en/sql-reference/statements/select#replace>
560+
/// Snowflake syntax: <https://docs.snowflake.com/en/sql-reference/sql/select#parameters>
562561
pub opt_replace: Option<ReplaceSelectItem>,
562+
/// `[RENAME ...]`.
563+
pub opt_rename: Option<RenameSelectItem>,
563564
}
564565

565566
impl fmt::Display for WildcardAdditionalOptions {
@@ -573,12 +574,12 @@ impl fmt::Display for WildcardAdditionalOptions {
573574
if let Some(except) = &self.opt_except {
574575
write!(f, " {except}")?;
575576
}
576-
if let Some(rename) = &self.opt_rename {
577-
write!(f, " {rename}")?;
578-
}
579577
if let Some(replace) = &self.opt_replace {
580578
write!(f, " {replace}")?;
581579
}
580+
if let Some(rename) = &self.opt_rename {
581+
write!(f, " {rename}")?;
582+
}
582583
Ok(())
583584
}
584585
}

src/parser/mod.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10175,15 +10175,14 @@ impl<'a> Parser<'a> {
1017510175
} else {
1017610176
None
1017710177
};
10178-
let opt_rename = if dialect_of!(self is GenericDialect | SnowflakeDialect) {
10179-
self.parse_optional_select_item_rename()?
10178+
let opt_replace = if dialect_of!(self is GenericDialect | BigQueryDialect | ClickHouseDialect | DuckDbDialect | SnowflakeDialect)
10179+
{
10180+
self.parse_optional_select_item_replace()?
1018010181
} else {
1018110182
None
1018210183
};
10183-
10184-
let opt_replace = if dialect_of!(self is GenericDialect | BigQueryDialect | ClickHouseDialect | DuckDbDialect | SnowflakeDialect)
10185-
{
10186-
self.parse_optional_select_item_replace()?
10184+
let opt_rename = if dialect_of!(self is GenericDialect | SnowflakeDialect) {
10185+
self.parse_optional_select_item_rename()?
1018710186
} else {
1018810187
None
1018910188
};

tests/sqlparser_snowflake.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,6 +1016,43 @@ fn test_select_wildcard_with_rename() {
10161016
assert_eq!(expected, select.projection[0]);
10171017
}
10181018

1019+
#[test]
1020+
fn test_select_wildcard_with_replace_and_rename() {
1021+
let select = snowflake_and_generic()
1022+
.verified_only_select("SELECT * REPLACE (col_z || col_z AS col_z) RENAME (col_z AS col_zz) FROM data");
1023+
let expected = SelectItem::Wildcard(WildcardAdditionalOptions {
1024+
opt_replace: Some(ReplaceSelectItem {
1025+
items: vec![Box::new(ReplaceSelectElement {
1026+
expr: Expr::BinaryOp {
1027+
left: Box::new(Expr::Identifier(Ident::new("col_z"))),
1028+
op: BinaryOperator::StringConcat,
1029+
right: Box::new(Expr::Identifier(Ident::new("col_z"))),
1030+
},
1031+
column_name: Ident::new("col_z"),
1032+
as_keyword: true,
1033+
})],
1034+
}),
1035+
opt_rename: Some(RenameSelectItem::Multiple(
1036+
vec![IdentWithAlias {
1037+
ident: Ident::new("col_z"),
1038+
alias: Ident::new("col_zz"),
1039+
}]
1040+
)),
1041+
..Default::default()
1042+
});
1043+
assert_eq!(expected, select.projection[0]);
1044+
1045+
// rename cannot precede replace
1046+
// https://docs.snowflake.com/en/sql-reference/sql/select#parameters
1047+
assert_eq!(
1048+
snowflake_and_generic()
1049+
.parse_sql_statements("SELECT * RENAME (col_z AS col_zz) REPLACE (col_z || col_z AS col_z) FROM data")
1050+
.unwrap_err()
1051+
.to_string(),
1052+
"sql parser error: Expected: end of statement, found: REPLACE"
1053+
);
1054+
}
1055+
10191056
#[test]
10201057
fn test_select_wildcard_with_exclude_and_rename() {
10211058
let select = snowflake_and_generic()
@@ -1031,6 +1068,7 @@ fn test_select_wildcard_with_exclude_and_rename() {
10311068
assert_eq!(expected, select.projection[0]);
10321069

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

0 commit comments

Comments
 (0)