@@ -8837,68 +8837,76 @@ impl<'a> Parser<'a> {
8837
8837
Ok(IdentWithAlias { ident, alias })
8838
8838
}
8839
8839
8840
- // Optionally parses an alias for a select list item
8840
+ /// Optionally parses an alias for a select list item
8841
8841
fn maybe_parse_select_item_alias(&mut self) -> Result<Option<Ident>, ParserError> {
8842
- let after_as = self.parse_keyword(Keyword::AS);
8843
- let next_token = self.next_token();
8844
- match next_token.token {
8845
- // Dialect-specific behavior for words that may be reserved from parsed
8846
- // as select item aliases.
8847
- Token::Word(w)
8848
- if self
8849
- .dialect
8850
- .is_select_item_alias(after_as, &w.keyword, self) =>
8851
- {
8852
- Ok(Some(w.into_ident(next_token.span)))
8853
- }
8854
- // MSSQL supports single-quoted strings as aliases for columns
8855
- Token::SingleQuotedString(s) => Ok(Some(Ident::with_quote('\'', s))),
8856
- // Support for MySql dialect double-quoted string, `AS "HOUR"` for example
8857
- Token::DoubleQuotedString(s) => Ok(Some(Ident::with_quote('\"', s))),
8858
- _ => {
8859
- if after_as {
8860
- return self.expected("an identifier after AS", next_token);
8861
- }
8862
- self.prev_token();
8863
- Ok(None) // no alias found
8842
+ fn validator(explicit: bool, kw: &Keyword, parser: &mut Parser) -> bool {
8843
+ parser.dialect.is_select_item_alias(explicit, kw, parser)
8844
+ }
8845
+ self.parse_optional_alias_inner(None, validator)
8846
+ }
8847
+
8848
+ /// Optionally parses an alias for a table like in `... FROM generate_series(1, 10) AS t (col)`.
8849
+ /// In this case, the alias is allowed to optionally name the columns in the table, in
8850
+ /// addition to the table itself.
8851
+ pub fn maybe_parse_table_alias(&mut self) -> Result<Option<TableAlias>, ParserError> {
8852
+ fn validator(explicit: bool, kw: &Keyword, parser: &mut Parser) -> bool {
8853
+ parser.dialect.is_table_factor_alias(explicit, kw, parser)
8854
+ }
8855
+ match self.parse_optional_alias_inner(None, validator)? {
8856
+ Some(name) => {
8857
+ let columns = self.parse_table_alias_column_defs()?;
8858
+ Ok(Some(TableAlias { name, columns }))
8864
8859
}
8860
+ None => Ok(None),
8865
8861
}
8866
8862
}
8867
8863
8868
- /// Parse `AS identifier` (or simply `identifier` if it's not a reserved keyword)
8869
- /// Some examples with aliases: `SELECT 1 foo`, `SELECT COUNT(*) AS cnt`,
8870
- /// `SELECT ... FROM t1 foo, t2 bar`, `SELECT ... FROM (...) AS bar`
8864
+ /// Wrapper for parse_optional_alias_inner, left for backwards-compatibility
8865
+ /// but new flows should use the context-specific methods such as `maybe_parse_select_item_alias`
8866
+ /// and `maybe_parse_table_alias`.
8871
8867
pub fn parse_optional_alias(
8872
8868
&mut self,
8873
8869
reserved_kwds: &[Keyword],
8874
8870
) -> Result<Option<Ident>, ParserError> {
8871
+ fn validator(_explicit: bool, _kw: &Keyword, _parser: &mut Parser) -> bool {
8872
+ false
8873
+ }
8874
+ self.parse_optional_alias_inner(Some(reserved_kwds), validator)
8875
+ }
8876
+
8877
+ /// Parses an optional alias after a SQL element such as a select list item
8878
+ /// or a table name.
8879
+ ///
8880
+ /// This method accepts an optional list of reserved keywords or a function
8881
+ /// to call to validate if a keyword should be parsed as an alias, to allow
8882
+ /// callers to customize the parsing logic based on their context.
8883
+ fn parse_optional_alias_inner<F>(
8884
+ &mut self,
8885
+ reserved_kwds: Option<&[Keyword]>,
8886
+ validator: F,
8887
+ ) -> Result<Option<Ident>, ParserError>
8888
+ where
8889
+ F: Fn(bool, &Keyword, &mut Parser) -> bool,
8890
+ {
8875
8891
let after_as = self.parse_keyword(Keyword::AS);
8892
+
8876
8893
let next_token = self.next_token();
8877
8894
match next_token.token {
8878
- // Accept any identifier after `AS` (though many dialects have restrictions on
8879
- // keywords that may appear here). If there's no `AS`: don't parse keywords,
8880
- // which may start a construct allowed in this position, to be parsed as aliases.
8881
- // (For example, in `FROM t1 JOIN` the `JOIN` will always be parsed as a keyword,
8882
- // not an alias.)
8883
- Token::Word(w) if after_as || !reserved_kwds.contains(&w.keyword) => {
8895
+ // By default, if a word is located after the `AS` keyword we consider it an alias
8896
+ // as long as it's not reserved.
8897
+ Token::Word(w)
8898
+ if after_as || reserved_kwds.map_or(false, |x| !x.contains(&w.keyword)) =>
8899
+ {
8884
8900
Ok(Some(w.into_ident(next_token.span)))
8885
8901
}
8886
- // Left the next two patterns for backwards-compatibility (despite not breaking
8887
- // any tests).
8888
- // MSSQL supports single-quoted strings as aliases for columns
8889
- // We accept them as table aliases too, although MSSQL does not.
8890
- //
8891
- // Note, that this conflicts with an obscure rule from the SQL
8892
- // standard, which we don't implement:
8893
- // https://crate.io/docs/sql-99/en/latest/chapters/07.html#character-string-literal-s
8894
- // "[Obscure Rule] SQL allows you to break a long <character
8895
- // string literal> up into two or more smaller <character string
8896
- // literal>s, split by a <separator> that includes a newline
8897
- // character. When it sees such a <literal>, your DBMS will
8898
- // ignore the <separator> and treat the multiple strings as
8899
- // a single <literal>."
8902
+ // This pattern allows for customizing the acceptance of words as aliases based on the caller's
8903
+ // context, such as to what SQL element this word is a potential alias of (select item alias, table name
8904
+ // alias, etc.) or dialect-specific logic that goes beyond a simple list of reserved keywords.
8905
+ Token::Word(w) if validator(after_as, &w.keyword, self) => {
8906
+ Ok(Some(w.into_ident(next_token.span)))
8907
+ }
8908
+ // For backwards-compatibility, we accept quoted strings as aliases regardless of the context.
8900
8909
Token::SingleQuotedString(s) => Ok(Some(Ident::with_quote('\'', s))),
8901
- // Support for MySql dialect double-quoted string, `AS "HOUR"` for example
8902
8910
Token::DoubleQuotedString(s) => Ok(Some(Ident::with_quote('\"', s))),
8903
8911
_ => {
8904
8912
if after_as {
@@ -8910,23 +8918,6 @@ impl<'a> Parser<'a> {
8910
8918
}
8911
8919
}
8912
8920
8913
- /// Parse `AS identifier` when the AS is describing a table-valued object,
8914
- /// like in `... FROM generate_series(1, 10) AS t (col)`. In this case
8915
- /// the alias is allowed to optionally name the columns in the table, in
8916
- /// addition to the table itself.
8917
- pub fn parse_optional_table_alias(
8918
- &mut self,
8919
- reserved_kwds: &[Keyword],
8920
- ) -> Result<Option<TableAlias>, ParserError> {
8921
- match self.parse_optional_alias(reserved_kwds)? {
8922
- Some(name) => {
8923
- let columns = self.parse_table_alias_column_defs()?;
8924
- Ok(Some(TableAlias { name, columns }))
8925
- }
8926
- None => Ok(None),
8927
- }
8928
- }
8929
-
8930
8921
pub fn parse_optional_group_by(&mut self) -> Result<Option<GroupByExpr>, ParserError> {
8931
8922
if self.parse_keywords(&[Keyword::GROUP, Keyword::BY]) {
8932
8923
let expressions = if self.parse_keyword(Keyword::ALL) {
@@ -10928,7 +10919,7 @@ impl<'a> Parser<'a> {
10928
10919
let name = self.parse_object_name(false)?;
10929
10920
self.expect_token(&Token::LParen)?;
10930
10921
let args = self.parse_optional_args()?;
10931
- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
10922
+ let alias = self.maybe_parse_table_alias( )?;
10932
10923
Ok(TableFactor::Function {
10933
10924
lateral: true,
10934
10925
name,
@@ -10941,7 +10932,7 @@ impl<'a> Parser<'a> {
10941
10932
self.expect_token(&Token::LParen)?;
10942
10933
let expr = self.parse_expr()?;
10943
10934
self.expect_token(&Token::RParen)?;
10944
- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
10935
+ let alias = self.maybe_parse_table_alias( )?;
10945
10936
Ok(TableFactor::TableFunction { expr, alias })
10946
10937
} else if self.consume_token(&Token::LParen) {
10947
10938
// A left paren introduces either a derived table (i.e., a subquery)
@@ -10990,7 +10981,7 @@ impl<'a> Parser<'a> {
10990
10981
#[allow(clippy::if_same_then_else)]
10991
10982
if !table_and_joins.joins.is_empty() {
10992
10983
self.expect_token(&Token::RParen)?;
10993
- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
10984
+ let alias = self.maybe_parse_table_alias( )?;
10994
10985
Ok(TableFactor::NestedJoin {
10995
10986
table_with_joins: Box::new(table_and_joins),
10996
10987
alias,
@@ -11003,7 +10994,7 @@ impl<'a> Parser<'a> {
11003
10994
// (B): `table_and_joins` (what we found inside the parentheses)
11004
10995
// is a nested join `(foo JOIN bar)`, not followed by other joins.
11005
10996
self.expect_token(&Token::RParen)?;
11006
- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
10997
+ let alias = self.maybe_parse_table_alias( )?;
11007
10998
Ok(TableFactor::NestedJoin {
11008
10999
table_with_joins: Box::new(table_and_joins),
11009
11000
alias,
@@ -11017,9 +11008,7 @@ impl<'a> Parser<'a> {
11017
11008
// [AS alias])`) as well.
11018
11009
self.expect_token(&Token::RParen)?;
11019
11010
11020
- if let Some(outer_alias) =
11021
- self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?
11022
- {
11011
+ if let Some(outer_alias) = self.maybe_parse_table_alias()? {
11023
11012
// Snowflake also allows specifying an alias *after* parens
11024
11013
// e.g. `FROM (mytable) AS alias`
11025
11014
match &mut table_and_joins.relation {
@@ -11072,7 +11061,7 @@ impl<'a> Parser<'a> {
11072
11061
// SELECT * FROM VALUES (1, 'a'), (2, 'b') AS t (col1, col2)
11073
11062
// where there are no parentheses around the VALUES clause.
11074
11063
let values = SetExpr::Values(self.parse_values(false)?);
11075
- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
11064
+ let alias = self.maybe_parse_table_alias( )?;
11076
11065
Ok(TableFactor::Derived {
11077
11066
lateral: false,
11078
11067
subquery: Box::new(Query {
@@ -11098,7 +11087,7 @@ impl<'a> Parser<'a> {
11098
11087
self.expect_token(&Token::RParen)?;
11099
11088
11100
11089
let with_ordinality = self.parse_keywords(&[Keyword::WITH, Keyword::ORDINALITY]);
11101
- let alias = match self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS ) {
11090
+ let alias = match self.maybe_parse_table_alias( ) {
11102
11091
Ok(Some(alias)) => Some(alias),
11103
11092
Ok(None) => None,
11104
11093
Err(e) => return Err(e),
@@ -11135,7 +11124,7 @@ impl<'a> Parser<'a> {
11135
11124
let columns = self.parse_comma_separated(Parser::parse_json_table_column_def)?;
11136
11125
self.expect_token(&Token::RParen)?;
11137
11126
self.expect_token(&Token::RParen)?;
11138
- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
11127
+ let alias = self.maybe_parse_table_alias( )?;
11139
11128
Ok(TableFactor::JsonTable {
11140
11129
json_expr,
11141
11130
json_path,
@@ -11180,7 +11169,7 @@ impl<'a> Parser<'a> {
11180
11169
}
11181
11170
}
11182
11171
11183
- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
11172
+ let alias = self.maybe_parse_table_alias( )?;
11184
11173
11185
11174
// MSSQL-specific table hints:
11186
11175
let mut with_hints = vec![];
@@ -11358,7 +11347,7 @@ impl<'a> Parser<'a> {
11358
11347
} else {
11359
11348
Vec::new()
11360
11349
};
11361
- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
11350
+ let alias = self.maybe_parse_table_alias( )?;
11362
11351
Ok(TableFactor::OpenJsonTable {
11363
11352
json_expr,
11364
11353
json_path,
@@ -11457,7 +11446,7 @@ impl<'a> Parser<'a> {
11457
11446
11458
11447
self.expect_token(&Token::RParen)?;
11459
11448
11460
- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
11449
+ let alias = self.maybe_parse_table_alias( )?;
11461
11450
11462
11451
Ok(TableFactor::MatchRecognize {
11463
11452
table: Box::new(table),
@@ -11701,7 +11690,7 @@ impl<'a> Parser<'a> {
11701
11690
) -> Result<TableFactor, ParserError> {
11702
11691
let subquery = self.parse_query()?;
11703
11692
self.expect_token(&Token::RParen)?;
11704
- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
11693
+ let alias = self.maybe_parse_table_alias( )?;
11705
11694
Ok(TableFactor::Derived {
11706
11695
lateral: match lateral {
11707
11696
Lateral => true,
@@ -11795,7 +11784,7 @@ impl<'a> Parser<'a> {
11795
11784
};
11796
11785
11797
11786
self.expect_token(&Token::RParen)?;
11798
- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
11787
+ let alias = self.maybe_parse_table_alias( )?;
11799
11788
Ok(TableFactor::Pivot {
11800
11789
table: Box::new(table),
11801
11790
aggregate_functions,
@@ -11817,7 +11806,7 @@ impl<'a> Parser<'a> {
11817
11806
self.expect_keyword_is(Keyword::IN)?;
11818
11807
let columns = self.parse_parenthesized_column_list(Mandatory, false)?;
11819
11808
self.expect_token(&Token::RParen)?;
11820
- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
11809
+ let alias = self.maybe_parse_table_alias( )?;
11821
11810
Ok(TableFactor::Unpivot {
11822
11811
table: Box::new(table),
11823
11812
value,
0 commit comments