@@ -1880,8 +1880,27 @@ impl<'a> Parser<'a> {
18801880 let is_outer_join = self.peek_outer_join_operator();
18811881 match &self.peek_token_ref().token {
18821882 Token::LParen if !is_outer_join => {
1883- let id_parts = vec![w.to_ident(w_span)];
1884- self.parse_function(ObjectName::from(id_parts))
1883+ let ident = w.to_ident(w_span);
1884+ // Snowflake call-by-name in expression position:
1885+ // `IDENTIFIER('f')(args)`. The `IDENTIFIER('f')` forms the
1886+ // callee name (an `ObjectNamePart::Function`) and the trailing
1887+ // `(args)` is the actual call — mirror the object-name grammar
1888+ // so the resulting `Expr::Function` matches the CALL path shape.
1889+ if self.dialect.is_identifier_generating_function_name(&ident, &[]) {
1890+ let checkpoint = self.index;
1891+ self.expect_token(&Token::LParen)?;
1892+ let args = self
1893+ .parse_comma_separated0(Self::parse_function_args, Token::RParen)?;
1894+ self.expect_token(&Token::RParen)?;
1895+ if self.peek_token_ref().token == Token::LParen {
1896+ let name = ObjectName(vec![ObjectNamePart::Function(
1897+ ObjectNamePartFunction { name: ident, args },
1898+ )]);
1899+ return self.parse_function(name);
1900+ }
1901+ self.index = checkpoint;
1902+ }
1903+ self.parse_function(ObjectName::from(vec![ident]))
18851904 }
18861905 // string introducer https://dev.mysql.com/doc/refman/8.0/en/charset-introducer.html
18871906 Token::SingleQuotedString(_)
0 commit comments