Fix Snowflake SELECT * wildcard REPLACE ... RENAME order (#1321)

This commit is contained in:
Alexander Beedie 2024-06-27 15:56:21 +04:00 committed by GitHub
parent a685e11993
commit f5ccef6ea9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 51 additions and 12 deletions

View file

@ -547,19 +547,20 @@ impl fmt::Display for IdentWithAlias {
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct WildcardAdditionalOptions { pub struct WildcardAdditionalOptions {
/// `[ILIKE...]`. /// `[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>, pub opt_ilike: Option<IlikeSelectItem>,
/// `[EXCLUDE...]`. /// `[EXCLUDE...]`.
pub opt_exclude: Option<ExcludeSelectItem>, pub opt_exclude: Option<ExcludeSelectItem>,
/// `[EXCEPT...]`. /// `[EXCEPT...]`.
/// Clickhouse syntax: <https://clickhouse.com/docs/en/sql-reference/statements/select#except> /// Clickhouse syntax: <https://clickhouse.com/docs/en/sql-reference/statements/select#except>
pub opt_except: Option<ExceptSelectItem>, pub opt_except: Option<ExceptSelectItem>,
/// `[RENAME ...]`.
pub opt_rename: Option<RenameSelectItem>,
/// `[REPLACE]` /// `[REPLACE]`
/// BigQuery syntax: <https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#select_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> /// 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>, pub opt_replace: Option<ReplaceSelectItem>,
/// `[RENAME ...]`.
pub opt_rename: Option<RenameSelectItem>,
} }
impl fmt::Display for WildcardAdditionalOptions { impl fmt::Display for WildcardAdditionalOptions {
@ -573,12 +574,12 @@ impl fmt::Display for WildcardAdditionalOptions {
if let Some(except) = &self.opt_except { if let Some(except) = &self.opt_except {
write!(f, " {except}")?; write!(f, " {except}")?;
} }
if let Some(rename) = &self.opt_rename {
write!(f, " {rename}")?;
}
if let Some(replace) = &self.opt_replace { if let Some(replace) = &self.opt_replace {
write!(f, " {replace}")?; write!(f, " {replace}")?;
} }
if let Some(rename) = &self.opt_rename {
write!(f, " {rename}")?;
}
Ok(()) Ok(())
} }
} }

View file

@ -10175,15 +10175,14 @@ impl<'a> Parser<'a> {
} else { } else {
None None
}; };
let opt_rename = if dialect_of!(self is GenericDialect | SnowflakeDialect) { let opt_replace = if dialect_of!(self is GenericDialect | BigQueryDialect | ClickHouseDialect | DuckDbDialect | SnowflakeDialect)
self.parse_optional_select_item_rename()? {
self.parse_optional_select_item_replace()?
} else { } else {
None None
}; };
let opt_rename = if dialect_of!(self is GenericDialect | SnowflakeDialect) {
let opt_replace = if dialect_of!(self is GenericDialect | BigQueryDialect | ClickHouseDialect | DuckDbDialect | SnowflakeDialect) self.parse_optional_select_item_rename()?
{
self.parse_optional_select_item_replace()?
} else { } else {
None None
}; };

View file

@ -1016,6 +1016,44 @@ fn test_select_wildcard_with_rename() {
assert_eq!(expected, select.projection[0]); assert_eq!(expected, select.projection[0]);
} }
#[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,
})],
}),
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
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] #[test]
fn test_select_wildcard_with_exclude_and_rename() { fn test_select_wildcard_with_exclude_and_rename() {
let select = snowflake_and_generic() let select = snowflake_and_generic()
@ -1031,6 +1069,7 @@ fn test_select_wildcard_with_exclude_and_rename() {
assert_eq!(expected, select.projection[0]); assert_eq!(expected, select.projection[0]);
// rename cannot precede exclude // rename cannot precede exclude
// https://docs.snowflake.com/en/sql-reference/sql/select#parameters
assert_eq!( assert_eq!(
snowflake_and_generic() snowflake_and_generic()
.parse_sql_statements("SELECT * RENAME col_a AS col_b EXCLUDE col_z FROM data") .parse_sql_statements("SELECT * RENAME col_a AS col_b EXCLUDE col_z FROM data")