@@ -8837,68 +8837,76 @@ impl<'a> Parser<'a> {
88378837 Ok(IdentWithAlias { ident, alias })
88388838 }
88398839
8840- // Optionally parses an alias for a select list item
8840+ /// Optionally parses an alias for a select list item
88418841 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 }))
88648859 }
8860+ None => Ok(None),
88658861 }
88668862 }
88678863
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`.
88718867 pub fn parse_optional_alias(
88728868 &mut self,
88738869 reserved_kwds: &[Keyword],
88748870 ) -> 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+ {
88758891 let after_as = self.parse_keyword(Keyword::AS);
8892+
88768893 let next_token = self.next_token();
88778894 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+ {
88848900 Ok(Some(w.into_ident(next_token.span)))
88858901 }
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.
89008909 Token::SingleQuotedString(s) => Ok(Some(Ident::with_quote('\'', s))),
8901- // Support for MySql dialect double-quoted string, `AS "HOUR"` for example
89028910 Token::DoubleQuotedString(s) => Ok(Some(Ident::with_quote('\"', s))),
89038911 _ => {
89048912 if after_as {
@@ -8910,23 +8918,6 @@ impl<'a> Parser<'a> {
89108918 }
89118919 }
89128920
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-
89308921 pub fn parse_optional_group_by(&mut self) -> Result<Option<GroupByExpr>, ParserError> {
89318922 if self.parse_keywords(&[Keyword::GROUP, Keyword::BY]) {
89328923 let expressions = if self.parse_keyword(Keyword::ALL) {
@@ -10928,7 +10919,7 @@ impl<'a> Parser<'a> {
1092810919 let name = self.parse_object_name(false)?;
1092910920 self.expect_token(&Token::LParen)?;
1093010921 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( )?;
1093210923 Ok(TableFactor::Function {
1093310924 lateral: true,
1093410925 name,
@@ -10941,7 +10932,7 @@ impl<'a> Parser<'a> {
1094110932 self.expect_token(&Token::LParen)?;
1094210933 let expr = self.parse_expr()?;
1094310934 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( )?;
1094510936 Ok(TableFactor::TableFunction { expr, alias })
1094610937 } else if self.consume_token(&Token::LParen) {
1094710938 // A left paren introduces either a derived table (i.e., a subquery)
@@ -10990,7 +10981,7 @@ impl<'a> Parser<'a> {
1099010981 #[allow(clippy::if_same_then_else)]
1099110982 if !table_and_joins.joins.is_empty() {
1099210983 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( )?;
1099410985 Ok(TableFactor::NestedJoin {
1099510986 table_with_joins: Box::new(table_and_joins),
1099610987 alias,
@@ -11003,7 +10994,7 @@ impl<'a> Parser<'a> {
1100310994 // (B): `table_and_joins` (what we found inside the parentheses)
1100410995 // is a nested join `(foo JOIN bar)`, not followed by other joins.
1100510996 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( )?;
1100710998 Ok(TableFactor::NestedJoin {
1100810999 table_with_joins: Box::new(table_and_joins),
1100911000 alias,
@@ -11017,9 +11008,7 @@ impl<'a> Parser<'a> {
1101711008 // [AS alias])`) as well.
1101811009 self.expect_token(&Token::RParen)?;
1101911010
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()? {
1102311012 // Snowflake also allows specifying an alias *after* parens
1102411013 // e.g. `FROM (mytable) AS alias`
1102511014 match &mut table_and_joins.relation {
@@ -11072,7 +11061,7 @@ impl<'a> Parser<'a> {
1107211061 // SELECT * FROM VALUES (1, 'a'), (2, 'b') AS t (col1, col2)
1107311062 // where there are no parentheses around the VALUES clause.
1107411063 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( )?;
1107611065 Ok(TableFactor::Derived {
1107711066 lateral: false,
1107811067 subquery: Box::new(Query {
@@ -11098,7 +11087,7 @@ impl<'a> Parser<'a> {
1109811087 self.expect_token(&Token::RParen)?;
1109911088
1110011089 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( ) {
1110211091 Ok(Some(alias)) => Some(alias),
1110311092 Ok(None) => None,
1110411093 Err(e) => return Err(e),
@@ -11135,7 +11124,7 @@ impl<'a> Parser<'a> {
1113511124 let columns = self.parse_comma_separated(Parser::parse_json_table_column_def)?;
1113611125 self.expect_token(&Token::RParen)?;
1113711126 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( )?;
1113911128 Ok(TableFactor::JsonTable {
1114011129 json_expr,
1114111130 json_path,
@@ -11180,7 +11169,7 @@ impl<'a> Parser<'a> {
1118011169 }
1118111170 }
1118211171
11183- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
11172+ let alias = self.maybe_parse_table_alias( )?;
1118411173
1118511174 // MSSQL-specific table hints:
1118611175 let mut with_hints = vec![];
@@ -11358,7 +11347,7 @@ impl<'a> Parser<'a> {
1135811347 } else {
1135911348 Vec::new()
1136011349 };
11361- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
11350+ let alias = self.maybe_parse_table_alias( )?;
1136211351 Ok(TableFactor::OpenJsonTable {
1136311352 json_expr,
1136411353 json_path,
@@ -11457,7 +11446,7 @@ impl<'a> Parser<'a> {
1145711446
1145811447 self.expect_token(&Token::RParen)?;
1145911448
11460- let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS )?;
11449+ let alias = self.maybe_parse_table_alias( )?;
1146111450
1146211451 Ok(TableFactor::MatchRecognize {
1146311452 table: Box::new(table),
@@ -11701,7 +11690,7 @@ impl<'a> Parser<'a> {
1170111690 ) -> Result<TableFactor, ParserError> {
1170211691 let subquery = self.parse_query()?;
1170311692 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( )?;
1170511694 Ok(TableFactor::Derived {
1170611695 lateral: match lateral {
1170711696 Lateral => true,
@@ -11795,7 +11784,7 @@ impl<'a> Parser<'a> {
1179511784 };
1179611785
1179711786 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( )?;
1179911788 Ok(TableFactor::Pivot {
1180011789 table: Box::new(table),
1180111790 aggregate_functions,
@@ -11817,7 +11806,7 @@ impl<'a> Parser<'a> {
1181711806 self.expect_keyword_is(Keyword::IN)?;
1181811807 let columns = self.parse_parenthesized_column_list(Mandatory, false)?;
1181911808 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( )?;
1182111810 Ok(TableFactor::Unpivot {
1182211811 table: Box::new(table),
1182311812 value,
0 commit comments