Skip to content

Commit 4be9a54

Browse files
authored
Revert "Add support for Snowflake column aliases that use SQL keywords (apache#1632)"
This reverts commit bc153a4.
1 parent d556181 commit 4be9a54

File tree

4 files changed

+56
-163
lines changed

4 files changed

+56
-163
lines changed

src/dialect/mod.rs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -820,20 +820,6 @@ pub trait Dialect: Debug + Any {
820820
fn supports_set_stmt_without_operator(&self) -> bool {
821821
false
822822
}
823-
824-
/// Returns true if the specified keyword should be parsed as a select item alias.
825-
/// When explicit is true, the keyword is preceded by an `AS` word. Parser is provided
826-
/// to enable looking ahead if needed.
827-
fn is_select_item_alias(&self, explicit: bool, kw: &Keyword, _parser: &mut Parser) -> bool {
828-
explicit || !keywords::RESERVED_FOR_COLUMN_ALIAS.contains(kw)
829-
}
830-
831-
/// Returns true if the specified keyword should be parsed as a table factor alias.
832-
/// When explicit is true, the keyword is preceded by an `AS` word. Parser is provided
833-
/// to enable looking ahead if needed.
834-
fn is_table_factor_alias(&self, explicit: bool, kw: &Keyword, _parser: &mut Parser) -> bool {
835-
explicit || !keywords::RESERVED_FOR_TABLE_ALIAS.contains(kw)
836-
}
837823
}
838824

839825
/// This represents the operators for which precedence must be defined

src/dialect/snowflake.rs

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -262,51 +262,6 @@ impl Dialect for SnowflakeDialect {
262262
fn supports_partiql(&self) -> bool {
263263
true
264264
}
265-
266-
fn is_select_item_alias(&self, explicit: bool, kw: &Keyword, parser: &mut Parser) -> bool {
267-
explicit
268-
|| match kw {
269-
// The following keywords can be considered an alias as long as
270-
// they are not followed by other tokens that may change their meaning
271-
// e.g. `SELECT * EXCEPT (col1) FROM tbl`
272-
Keyword::EXCEPT
273-
// e.g. `SELECT 1 LIMIT 5`
274-
| Keyword::LIMIT
275-
// e.g. `SELECT 1 OFFSET 5 ROWS`
276-
| Keyword::OFFSET
277-
// e.g. `INSERT INTO t SELECT 1 RETURNING *`
278-
| Keyword::RETURNING if !matches!(parser.peek_token_ref().token, Token::Comma | Token::EOF) =>
279-
{
280-
false
281-
}
282-
283-
// `FETCH` can be considered an alias as long as it's not followed by `FIRST`` or `NEXT`
284-
// which would give it a different meanins, for example: `SELECT 1 FETCH FIRST 10 ROWS` - not an alias
285-
Keyword::FETCH
286-
if parser.peek_keyword(Keyword::FIRST) || parser.peek_keyword(Keyword::NEXT) =>
287-
{
288-
false
289-
}
290-
291-
// Reserved keywords by the Snowflake dialect, which seem to be less strictive
292-
// than what is listed in `keywords::RESERVED_FOR_COLUMN_ALIAS`. The following
293-
// keywords were tested with the this statement: `SELECT 1 <KW>`.
294-
Keyword::FROM
295-
| Keyword::GROUP
296-
| Keyword::HAVING
297-
| Keyword::INTERSECT
298-
| Keyword::INTO
299-
| Keyword::MINUS
300-
| Keyword::ORDER
301-
| Keyword::SELECT
302-
| Keyword::UNION
303-
| Keyword::WHERE
304-
| Keyword::WITH => false,
305-
306-
// Any other word is considered an alias
307-
_ => true,
308-
}
309-
}
310265
}
311266

312267
fn parse_file_staging_command(kw: Keyword, parser: &mut Parser) -> Result<Statement, ParserError> {

src/parser/mod.rs

Lines changed: 56 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -8838,76 +8838,38 @@ impl<'a> Parser<'a> {
88388838
Ok(IdentWithAlias { ident, alias })
88398839
}
88408840

8841-
/// Optionally parses an alias for a select list item
8842-
fn maybe_parse_select_item_alias(&mut self) -> Result<Option<Ident>, ParserError> {
8843-
fn validator(explicit: bool, kw: &Keyword, parser: &mut Parser) -> bool {
8844-
parser.dialect.is_select_item_alias(explicit, kw, parser)
8845-
}
8846-
self.parse_optional_alias_inner(None, validator)
8847-
}
8848-
8849-
/// Optionally parses an alias for a table like in `... FROM generate_series(1, 10) AS t (col)`.
8850-
/// In this case, the alias is allowed to optionally name the columns in the table, in
8851-
/// addition to the table itself.
8852-
pub fn maybe_parse_table_alias(&mut self) -> Result<Option<TableAlias>, ParserError> {
8853-
fn validator(explicit: bool, kw: &Keyword, parser: &mut Parser) -> bool {
8854-
parser.dialect.is_table_factor_alias(explicit, kw, parser)
8855-
}
8856-
match self.parse_optional_alias_inner(None, validator)? {
8857-
Some(name) => {
8858-
let columns = self.parse_table_alias_column_defs()?;
8859-
Ok(Some(TableAlias { name, columns }))
8860-
}
8861-
None => Ok(None),
8862-
}
8863-
}
8864-
8865-
/// Wrapper for parse_optional_alias_inner, left for backwards-compatibility
8866-
/// but new flows should use the context-specific methods such as `maybe_parse_select_item_alias`
8867-
/// and `maybe_parse_table_alias`.
8841+
/// Parse `AS identifier` (or simply `identifier` if it's not a reserved keyword)
8842+
/// Some examples with aliases: `SELECT 1 foo`, `SELECT COUNT(*) AS cnt`,
8843+
/// `SELECT ... FROM t1 foo, t2 bar`, `SELECT ... FROM (...) AS bar`
88688844
pub fn parse_optional_alias(
88698845
&mut self,
88708846
reserved_kwds: &[Keyword],
88718847
) -> Result<Option<Ident>, ParserError> {
8872-
fn validator(_explicit: bool, _kw: &Keyword, _parser: &mut Parser) -> bool {
8873-
false
8874-
}
8875-
self.parse_optional_alias_inner(Some(reserved_kwds), validator)
8876-
}
8877-
8878-
/// Parses an optional alias after a SQL element such as a select list item
8879-
/// or a table name.
8880-
///
8881-
/// This method accepts an optional list of reserved keywords or a function
8882-
/// to call to validate if a keyword should be parsed as an alias, to allow
8883-
/// callers to customize the parsing logic based on their context.
8884-
fn parse_optional_alias_inner<F>(
8885-
&mut self,
8886-
reserved_kwds: Option<&[Keyword]>,
8887-
validator: F,
8888-
) -> Result<Option<Ident>, ParserError>
8889-
where
8890-
F: Fn(bool, &Keyword, &mut Parser) -> bool,
8891-
{
88928848
let after_as = self.parse_keyword(Keyword::AS);
8893-
88948849
let next_token = self.next_token();
88958850
match next_token.token {
8896-
// By default, if a word is located after the `AS` keyword we consider it an alias
8897-
// as long as it's not reserved.
8898-
Token::Word(w)
8899-
if after_as || reserved_kwds.is_some_and(|x| !x.contains(&w.keyword)) =>
8900-
{
8901-
Ok(Some(w.into_ident(next_token.span)))
8902-
}
8903-
// This pattern allows for customizing the acceptance of words as aliases based on the caller's
8904-
// context, such as to what SQL element this word is a potential alias of (select item alias, table name
8905-
// alias, etc.) or dialect-specific logic that goes beyond a simple list of reserved keywords.
8906-
Token::Word(w) if validator(after_as, &w.keyword, self) => {
8851+
// Accept any identifier after `AS` (though many dialects have restrictions on
8852+
// keywords that may appear here). If there's no `AS`: don't parse keywords,
8853+
// which may start a construct allowed in this position, to be parsed as aliases.
8854+
// (For example, in `FROM t1 JOIN` the `JOIN` will always be parsed as a keyword,
8855+
// not an alias.)
8856+
Token::Word(w) if after_as || !reserved_kwds.contains(&w.keyword) => {
89078857
Ok(Some(w.into_ident(next_token.span)))
89088858
}
8909-
// For backwards-compatibility, we accept quoted strings as aliases regardless of the context.
8859+
// MSSQL supports single-quoted strings as aliases for columns
8860+
// We accept them as table aliases too, although MSSQL does not.
8861+
//
8862+
// Note, that this conflicts with an obscure rule from the SQL
8863+
// standard, which we don't implement:
8864+
// https://crate.io/docs/sql-99/en/latest/chapters/07.html#character-string-literal-s
8865+
// "[Obscure Rule] SQL allows you to break a long <character
8866+
// string literal> up into two or more smaller <character string
8867+
// literal>s, split by a <separator> that includes a newline
8868+
// character. When it sees such a <literal>, your DBMS will
8869+
// ignore the <separator> and treat the multiple strings as
8870+
// a single <literal>."
89108871
Token::SingleQuotedString(s) => Ok(Some(Ident::with_quote('\'', s))),
8872+
// Support for MySql dialect double-quoted string, `AS "HOUR"` for example
89118873
Token::DoubleQuotedString(s) => Ok(Some(Ident::with_quote('\"', s))),
89128874
_ => {
89138875
if after_as {
@@ -8919,6 +8881,23 @@ impl<'a> Parser<'a> {
89198881
}
89208882
}
89218883

8884+
/// Parse `AS identifier` when the AS is describing a table-valued object,
8885+
/// like in `... FROM generate_series(1, 10) AS t (col)`. In this case
8886+
/// the alias is allowed to optionally name the columns in the table, in
8887+
/// addition to the table itself.
8888+
pub fn parse_optional_table_alias(
8889+
&mut self,
8890+
reserved_kwds: &[Keyword],
8891+
) -> Result<Option<TableAlias>, ParserError> {
8892+
match self.parse_optional_alias(reserved_kwds)? {
8893+
Some(name) => {
8894+
let columns = self.parse_table_alias_column_defs()?;
8895+
Ok(Some(TableAlias { name, columns }))
8896+
}
8897+
None => Ok(None),
8898+
}
8899+
}
8900+
89228901
pub fn parse_optional_group_by(&mut self) -> Result<Option<GroupByExpr>, ParserError> {
89238902
if self.parse_keywords(&[Keyword::GROUP, Keyword::BY]) {
89248903
let expressions = if self.parse_keyword(Keyword::ALL) {
@@ -10920,7 +10899,7 @@ impl<'a> Parser<'a> {
1092010899
let name = self.parse_object_name(false)?;
1092110900
self.expect_token(&Token::LParen)?;
1092210901
let args = self.parse_optional_args()?;
10923-
let alias = self.maybe_parse_table_alias()?;
10902+
let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
1092410903
Ok(TableFactor::Function {
1092510904
lateral: true,
1092610905
name,
@@ -10933,7 +10912,7 @@ impl<'a> Parser<'a> {
1093310912
self.expect_token(&Token::LParen)?;
1093410913
let expr = self.parse_expr()?;
1093510914
self.expect_token(&Token::RParen)?;
10936-
let alias = self.maybe_parse_table_alias()?;
10915+
let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
1093710916
Ok(TableFactor::TableFunction { expr, alias })
1093810917
} else if self.consume_token(&Token::LParen) {
1093910918
// A left paren introduces either a derived table (i.e., a subquery)
@@ -10982,7 +10961,7 @@ impl<'a> Parser<'a> {
1098210961
#[allow(clippy::if_same_then_else)]
1098310962
if !table_and_joins.joins.is_empty() {
1098410963
self.expect_token(&Token::RParen)?;
10985-
let alias = self.maybe_parse_table_alias()?;
10964+
let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
1098610965
Ok(TableFactor::NestedJoin {
1098710966
table_with_joins: Box::new(table_and_joins),
1098810967
alias,
@@ -10995,7 +10974,7 @@ impl<'a> Parser<'a> {
1099510974
// (B): `table_and_joins` (what we found inside the parentheses)
1099610975
// is a nested join `(foo JOIN bar)`, not followed by other joins.
1099710976
self.expect_token(&Token::RParen)?;
10998-
let alias = self.maybe_parse_table_alias()?;
10977+
let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
1099910978
Ok(TableFactor::NestedJoin {
1100010979
table_with_joins: Box::new(table_and_joins),
1100110980
alias,
@@ -11009,7 +10988,9 @@ impl<'a> Parser<'a> {
1100910988
// [AS alias])`) as well.
1101010989
self.expect_token(&Token::RParen)?;
1101110990

11012-
if let Some(outer_alias) = self.maybe_parse_table_alias()? {
10991+
if let Some(outer_alias) =
10992+
self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?
10993+
{
1101310994
// Snowflake also allows specifying an alias *after* parens
1101410995
// e.g. `FROM (mytable) AS alias`
1101510996
match &mut table_and_joins.relation {
@@ -11062,7 +11043,7 @@ impl<'a> Parser<'a> {
1106211043
// SELECT * FROM VALUES (1, 'a'), (2, 'b') AS t (col1, col2)
1106311044
// where there are no parentheses around the VALUES clause.
1106411045
let values = SetExpr::Values(self.parse_values(false)?);
11065-
let alias = self.maybe_parse_table_alias()?;
11046+
let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
1106611047
Ok(TableFactor::Derived {
1106711048
lateral: false,
1106811049
subquery: Box::new(Query {
@@ -11088,7 +11069,7 @@ impl<'a> Parser<'a> {
1108811069
self.expect_token(&Token::RParen)?;
1108911070

1109011071
let with_ordinality = self.parse_keywords(&[Keyword::WITH, Keyword::ORDINALITY]);
11091-
let alias = match self.maybe_parse_table_alias() {
11072+
let alias = match self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS) {
1109211073
Ok(Some(alias)) => Some(alias),
1109311074
Ok(None) => None,
1109411075
Err(e) => return Err(e),
@@ -11125,7 +11106,7 @@ impl<'a> Parser<'a> {
1112511106
let columns = self.parse_comma_separated(Parser::parse_json_table_column_def)?;
1112611107
self.expect_token(&Token::RParen)?;
1112711108
self.expect_token(&Token::RParen)?;
11128-
let alias = self.maybe_parse_table_alias()?;
11109+
let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
1112911110
Ok(TableFactor::JsonTable {
1113011111
json_expr,
1113111112
json_path,
@@ -11170,7 +11151,7 @@ impl<'a> Parser<'a> {
1117011151
}
1117111152
}
1117211153

11173-
let alias = self.maybe_parse_table_alias()?;
11154+
let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
1117411155

1117511156
// MSSQL-specific table hints:
1117611157
let mut with_hints = vec![];
@@ -11348,7 +11329,7 @@ impl<'a> Parser<'a> {
1134811329
} else {
1134911330
Vec::new()
1135011331
};
11351-
let alias = self.maybe_parse_table_alias()?;
11332+
let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
1135211333
Ok(TableFactor::OpenJsonTable {
1135311334
json_expr,
1135411335
json_path,
@@ -11447,7 +11428,7 @@ impl<'a> Parser<'a> {
1144711428

1144811429
self.expect_token(&Token::RParen)?;
1144911430

11450-
let alias = self.maybe_parse_table_alias()?;
11431+
let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
1145111432

1145211433
Ok(TableFactor::MatchRecognize {
1145311434
table: Box::new(table),
@@ -11691,7 +11672,7 @@ impl<'a> Parser<'a> {
1169111672
) -> Result<TableFactor, ParserError> {
1169211673
let subquery = self.parse_query()?;
1169311674
self.expect_token(&Token::RParen)?;
11694-
let alias = self.maybe_parse_table_alias()?;
11675+
let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
1169511676
Ok(TableFactor::Derived {
1169611677
lateral: match lateral {
1169711678
Lateral => true,
@@ -11785,7 +11766,7 @@ impl<'a> Parser<'a> {
1178511766
};
1178611767

1178711768
self.expect_token(&Token::RParen)?;
11788-
let alias = self.maybe_parse_table_alias()?;
11769+
let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
1178911770
Ok(TableFactor::Pivot {
1179011771
table: Box::new(table),
1179111772
aggregate_functions,
@@ -11807,7 +11788,7 @@ impl<'a> Parser<'a> {
1180711788
self.expect_keyword_is(Keyword::IN)?;
1180811789
let columns = self.parse_parenthesized_column_list(Mandatory, false)?;
1180911790
self.expect_token(&Token::RParen)?;
11810-
let alias = self.maybe_parse_table_alias()?;
11791+
let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
1181111792
Ok(TableFactor::Unpivot {
1181211793
table: Box::new(table),
1181311794
value,
@@ -12633,7 +12614,7 @@ impl<'a> Parser<'a> {
1263312614
})
1263412615
}
1263512616
expr => self
12636-
.maybe_parse_select_item_alias()
12617+
.parse_optional_alias(keywords::RESERVED_FOR_COLUMN_ALIAS)
1263712618
.map(|alias| match alias {
1263812619
Some(alias) => SelectItem::ExprWithAlias { expr, alias },
1263912620
None => SelectItem::UnnamedExpr(expr),

tests/sqlparser_snowflake.rs

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3115,32 +3115,3 @@ fn parse_ls_and_rm() {
31153115

31163116
snowflake().verified_stmt(r#"LIST @"STAGE_WITH_QUOTES""#);
31173117
}
3118-
3119-
#[test]
3120-
fn test_sql_keywords_as_select_item_aliases() {
3121-
// Some keywords that should be parsed as an alias
3122-
let unreserved_kws = vec!["CLUSTER", "FETCH", "RETURNING", "LIMIT", "EXCEPT"];
3123-
for kw in unreserved_kws {
3124-
snowflake()
3125-
.one_statement_parses_to(&format!("SELECT 1 {kw}"), &format!("SELECT 1 AS {kw}"));
3126-
}
3127-
3128-
// Some keywords that should not be parsed as an alias
3129-
let reserved_kws = vec![
3130-
"FROM",
3131-
"GROUP",
3132-
"HAVING",
3133-
"INTERSECT",
3134-
"INTO",
3135-
"ORDER",
3136-
"SELECT",
3137-
"UNION",
3138-
"WHERE",
3139-
"WITH",
3140-
];
3141-
for kw in reserved_kws {
3142-
assert!(snowflake()
3143-
.parse_sql_statements(&format!("SELECT 1 {kw}"))
3144-
.is_err());
3145-
}
3146-
}

0 commit comments

Comments
 (0)