@@ -8838,38 +8838,76 @@ impl<'a> Parser<'a> {
8838
8838
Ok(IdentWithAlias { ident, alias })
8839
8839
}
8840
8840
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`
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`.
8844
8868
pub fn parse_optional_alias(
8845
8869
&mut self,
8846
8870
reserved_kwds: &[Keyword],
8847
8871
) -> 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
+ {
8848
8892
let after_as = self.parse_keyword(Keyword::AS);
8893
+
8849
8894
let next_token = self.next_token();
8850
8895
match next_token.token {
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) => {
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
+ {
8857
8901
Ok(Some(w.into_ident(next_token.span)))
8858
8902
}
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>."
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) => {
8907
+ Ok(Some(w.into_ident(next_token.span)))
8908
+ }
8909
+ // For backwards-compatibility, we accept quoted strings as aliases regardless of the context.
8871
8910
Token::SingleQuotedString(s) => Ok(Some(Ident::with_quote('\'', s))),
8872
- // Support for MySql dialect double-quoted string, `AS "HOUR"` for example
8873
8911
Token::DoubleQuotedString(s) => Ok(Some(Ident::with_quote('\"', s))),
8874
8912
_ => {
8875
8913
if after_as {
@@ -8881,23 +8919,6 @@ impl<'a> Parser<'a> {
8881
8919
}
8882
8920
}
8883
8921
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
-
8901
8922
pub fn parse_optional_group_by(&mut self) -> Result<Option<GroupByExpr>, ParserError> {
8902
8923
if self.parse_keywords(&[Keyword::GROUP, Keyword::BY]) {
8903
8924
let expressions = if self.parse_keyword(Keyword::ALL) {
@@ -10899,7 +10920,7 @@ impl<'a> Parser<'a> {
10899
10920
let name = self.parse_object_name(false)?;
10900
10921
self.expect_token(&Token::LParen)?;
10901
10922
let args = self.parse_optional_args()?;
10902
- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
10923
+ let alias = self.maybe_parse_table_alias( )?;
10903
10924
Ok(TableFactor::Function {
10904
10925
lateral: true,
10905
10926
name,
@@ -10912,7 +10933,7 @@ impl<'a> Parser<'a> {
10912
10933
self.expect_token(&Token::LParen)?;
10913
10934
let expr = self.parse_expr()?;
10914
10935
self.expect_token(&Token::RParen)?;
10915
- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
10936
+ let alias = self.maybe_parse_table_alias( )?;
10916
10937
Ok(TableFactor::TableFunction { expr, alias })
10917
10938
} else if self.consume_token(&Token::LParen) {
10918
10939
// A left paren introduces either a derived table (i.e., a subquery)
@@ -10961,7 +10982,7 @@ impl<'a> Parser<'a> {
10961
10982
#[allow(clippy::if_same_then_else)]
10962
10983
if !table_and_joins.joins.is_empty() {
10963
10984
self.expect_token(&Token::RParen)?;
10964
- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
10985
+ let alias = self.maybe_parse_table_alias( )?;
10965
10986
Ok(TableFactor::NestedJoin {
10966
10987
table_with_joins: Box::new(table_and_joins),
10967
10988
alias,
@@ -10974,7 +10995,7 @@ impl<'a> Parser<'a> {
10974
10995
// (B): `table_and_joins` (what we found inside the parentheses)
10975
10996
// is a nested join `(foo JOIN bar)`, not followed by other joins.
10976
10997
self.expect_token(&Token::RParen)?;
10977
- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
10998
+ let alias = self.maybe_parse_table_alias( )?;
10978
10999
Ok(TableFactor::NestedJoin {
10979
11000
table_with_joins: Box::new(table_and_joins),
10980
11001
alias,
@@ -10988,9 +11009,7 @@ impl<'a> Parser<'a> {
10988
11009
// [AS alias])`) as well.
10989
11010
self.expect_token(&Token::RParen)?;
10990
11011
10991
- if let Some(outer_alias) =
10992
- self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?
10993
- {
11012
+ if let Some(outer_alias) = self.maybe_parse_table_alias()? {
10994
11013
// Snowflake also allows specifying an alias *after* parens
10995
11014
// e.g. `FROM (mytable) AS alias`
10996
11015
match &mut table_and_joins.relation {
@@ -11043,7 +11062,7 @@ impl<'a> Parser<'a> {
11043
11062
// SELECT * FROM VALUES (1, 'a'), (2, 'b') AS t (col1, col2)
11044
11063
// where there are no parentheses around the VALUES clause.
11045
11064
let values = SetExpr::Values(self.parse_values(false)?);
11046
- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
11065
+ let alias = self.maybe_parse_table_alias( )?;
11047
11066
Ok(TableFactor::Derived {
11048
11067
lateral: false,
11049
11068
subquery: Box::new(Query {
@@ -11069,7 +11088,7 @@ impl<'a> Parser<'a> {
11069
11088
self.expect_token(&Token::RParen)?;
11070
11089
11071
11090
let with_ordinality = self.parse_keywords(&[Keyword::WITH, Keyword::ORDINALITY]);
11072
- let alias = match self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS ) {
11091
+ let alias = match self.maybe_parse_table_alias( ) {
11073
11092
Ok(Some(alias)) => Some(alias),
11074
11093
Ok(None) => None,
11075
11094
Err(e) => return Err(e),
@@ -11106,7 +11125,7 @@ impl<'a> Parser<'a> {
11106
11125
let columns = self.parse_comma_separated(Parser::parse_json_table_column_def)?;
11107
11126
self.expect_token(&Token::RParen)?;
11108
11127
self.expect_token(&Token::RParen)?;
11109
- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
11128
+ let alias = self.maybe_parse_table_alias( )?;
11110
11129
Ok(TableFactor::JsonTable {
11111
11130
json_expr,
11112
11131
json_path,
@@ -11151,7 +11170,7 @@ impl<'a> Parser<'a> {
11151
11170
}
11152
11171
}
11153
11172
11154
- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
11173
+ let alias = self.maybe_parse_table_alias( )?;
11155
11174
11156
11175
// MSSQL-specific table hints:
11157
11176
let mut with_hints = vec![];
@@ -11329,7 +11348,7 @@ impl<'a> Parser<'a> {
11329
11348
} else {
11330
11349
Vec::new()
11331
11350
};
11332
- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
11351
+ let alias = self.maybe_parse_table_alias( )?;
11333
11352
Ok(TableFactor::OpenJsonTable {
11334
11353
json_expr,
11335
11354
json_path,
@@ -11428,7 +11447,7 @@ impl<'a> Parser<'a> {
11428
11447
11429
11448
self.expect_token(&Token::RParen)?;
11430
11449
11431
- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
11450
+ let alias = self.maybe_parse_table_alias( )?;
11432
11451
11433
11452
Ok(TableFactor::MatchRecognize {
11434
11453
table: Box::new(table),
@@ -11672,7 +11691,7 @@ impl<'a> Parser<'a> {
11672
11691
) -> Result<TableFactor, ParserError> {
11673
11692
let subquery = self.parse_query()?;
11674
11693
self.expect_token(&Token::RParen)?;
11675
- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
11694
+ let alias = self.maybe_parse_table_alias( )?;
11676
11695
Ok(TableFactor::Derived {
11677
11696
lateral: match lateral {
11678
11697
Lateral => true,
@@ -11766,7 +11785,7 @@ impl<'a> Parser<'a> {
11766
11785
};
11767
11786
11768
11787
self.expect_token(&Token::RParen)?;
11769
- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
11788
+ let alias = self.maybe_parse_table_alias( )?;
11770
11789
Ok(TableFactor::Pivot {
11771
11790
table: Box::new(table),
11772
11791
aggregate_functions,
@@ -11788,7 +11807,7 @@ impl<'a> Parser<'a> {
11788
11807
self.expect_keyword_is(Keyword::IN)?;
11789
11808
let columns = self.parse_parenthesized_column_list(Mandatory, false)?;
11790
11809
self.expect_token(&Token::RParen)?;
11791
- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
11810
+ let alias = self.maybe_parse_table_alias( )?;
11792
11811
Ok(TableFactor::Unpivot {
11793
11812
table: Box::new(table),
11794
11813
value,
@@ -12614,7 +12633,7 @@ impl<'a> Parser<'a> {
12614
12633
})
12615
12634
}
12616
12635
expr => self
12617
- .parse_optional_alias(keywords::RESERVED_FOR_COLUMN_ALIAS )
12636
+ .maybe_parse_select_item_alias( )
12618
12637
.map(|alias| match alias {
12619
12638
Some(alias) => SelectItem::ExprWithAlias { expr, alias },
12620
12639
None => SelectItem::UnnamedExpr(expr),
0 commit comments