@@ -1856,41 +1856,53 @@ impl<'a> Parser<'a> {
18561856 chain.push(AccessExpr::Dot(expr));
18571857 self.advance_token(); // The consumed string
18581858 }
1859- // Handle words (including keywords like INTERVAL) as identifiers
1860- // when they appear after a period. This ensures `T.interval` is
1861- // parsed as a compound identifier, not as an interval expression.
1862- // If followed by `(`, parse as a method call (but not for `(+)`
1863- // which is the outer join operator in some dialects).
1864- Token::Word(w) => {
1865- let ident = w.clone().into_ident(next_token.span);
1866- self.advance_token();
1867- if self.peek_token() == Token::LParen && !self.peek_outer_join_operator() {
1868- let expr = self.parse_function(ObjectName::from(vec![ident]))?;
1869- chain.push(AccessExpr::Dot(expr));
1870- } else {
1871- chain.push(AccessExpr::Dot(Expr::Identifier(ident)));
1859+ // Fallback to parsing an arbitrary expression, but restrict to expression
1860+ // types that are valid after the dot operator. This ensures that e.g.
1861+ // `T.interval` is parsed as a compound identifier, not as an interval
1862+ // expression.
1863+ _ => {
1864+ let expr = self.maybe_parse(|parser| {
1865+ let expr = parser
1866+ .parse_subexpr(parser.dialect.prec_value(Precedence::Period))?;
1867+ match &expr {
1868+ Expr::CompoundFieldAccess { .. }
1869+ | Expr::CompoundIdentifier(_)
1870+ | Expr::Identifier(_)
1871+ | Expr::Value(_)
1872+ | Expr::Function(_) => Ok(expr),
1873+ _ => parser.expected("an identifier or value", parser.peek_token()),
1874+ }
1875+ })?;
1876+
1877+ match expr {
1878+ // If we get back a compound field access or identifier,
1879+ // we flatten the nested expression.
1880+ // For example if the current root is `foo`
1881+ // and we get back a compound identifier expression `bar.baz`
1882+ // The full expression should be `foo.bar.baz` (i.e.
1883+ // a root with an access chain with 2 entries) and not
1884+ // `foo.(bar.baz)` (i.e. a root with an access chain with
1885+ // 1 entry`).
1886+ Some(Expr::CompoundFieldAccess { root, access_chain }) => {
1887+ chain.push(AccessExpr::Dot(*root));
1888+ chain.extend(access_chain);
1889+ }
1890+ Some(Expr::CompoundIdentifier(parts)) => chain.extend(
1891+ parts.into_iter().map(Expr::Identifier).map(AccessExpr::Dot),
1892+ ),
1893+ Some(expr) => {
1894+ chain.push(AccessExpr::Dot(expr));
1895+ }
1896+ // If the expression is not a valid suffix, fall back to
1897+ // parsing as an identifier. This handles cases like `T.interval`
1898+ // where `interval` is a keyword but should be treated as an identifier.
1899+ None => {
1900+ chain.push(AccessExpr::Dot(Expr::Identifier(
1901+ self.parse_identifier()?,
1902+ )));
1903+ }
18721904 }
18731905 }
1874- // Fallback to parsing an arbitrary expression.
1875- _ => match self.parse_subexpr(self.dialect.prec_value(Precedence::Period))? {
1876- // If we get back a compound field access or identifier,
1877- // we flatten the nested expression.
1878- // For example if the current root is `foo`
1879- // and we get back a compound identifier expression `bar.baz`
1880- // The full expression should be `foo.bar.baz` (i.e.
1881- // a root with an access chain with 2 entries) and not
1882- // `foo.(bar.baz)` (i.e. a root with an access chain with
1883- // 1 entry`).
1884- Expr::CompoundFieldAccess { root, access_chain } => {
1885- chain.push(AccessExpr::Dot(*root));
1886- chain.extend(access_chain);
1887- }
1888- Expr::CompoundIdentifier(parts) => chain
1889- .extend(parts.into_iter().map(Expr::Identifier).map(AccessExpr::Dot)),
1890- expr => {
1891- chain.push(AccessExpr::Dot(expr));
1892- }
1893- },
18941906 }
18951907 } else if !self.dialect.supports_partiql()
18961908 && self.peek_token_ref().token == Token::LBracket
0 commit comments