@@ -1104,12 +1104,13 @@ impl<'a> Parser<'a> {
11041104 && self.peek_nth_token_ref(1).token == Token::Assignment
11051105 {
11061106 // bare assignment: var := expr
1107- // Accepts `(EXECUTE IMMEDIATE …)` / `(SHOW …)` payloads the same
1108- // way a RESULTSET declaration initializer does, so a dynamic
1109- // query can be assigned to an existing RESULTSET variable.
1107+ // Accepts `(EXECUTE IMMEDIATE …)` / `(SHOW …)` / `(CALL …)`
1108+ // payloads the same way a RESULTSET declaration initializer
1109+ // does, so a dynamic query or procedure call can be assigned to
1110+ // an existing RESULTSET variable.
11101111 let target = self.parse_identifier()?;
11111112 self.expect_token(&Token::Assignment)?;
1112- let value = self.parse_snowflake_declaration_payload_expr()?;
1113+ let value = self.parse_snowflake_declaration_payload_expr(true )?;
11131114 Statement::Assignment { target, value }
11141115 } else if let Some(kind) = loop_control_keyword(&self.peek_nth_token_ref(0).token) {
11151116 // Loop-control statements only make sense inside a scripting
@@ -8717,14 +8718,14 @@ impl<'a> Parser<'a> {
87178718 Some(DeclareType::Cursor),
87188719 None,
87198720 Some(DeclareAssignment::For(Box::new(
8720- self.parse_snowflake_declaration_payload_expr()?,
8721+ self.parse_snowflake_declaration_payload_expr(false )?,
87218722 ))),
87228723 None,
87238724 ),
87248725 }
87258726 } else if self.parse_keyword(Keyword::RESULTSET) {
87268727 let assigned_expr = if self.peek_token_ref().token != Token::SemiColon {
8727- self.parse_snowflake_variable_declaration_expression()?
8728+ self.parse_snowflake_variable_declaration_expression(true )?
87288729 } else {
87298730 // Nothing more to do. The statement has no further parameters.
87308731 None
@@ -8743,13 +8744,13 @@ impl<'a> Parser<'a> {
87438744 } else {
87448745 // Without an explicit keyword, the only valid option is variable declaration.
87458746 let (assigned_expr, data_type) = if let Some(assigned_expr) =
8746- self.parse_snowflake_variable_declaration_expression()?
8747+ self.parse_snowflake_variable_declaration_expression(false )?
87478748 {
87488749 (Some(assigned_expr), None)
87498750 } else if let Token::Word(_) = &self.peek_token_ref().token {
87508751 let data_type = self.parse_data_type()?;
87518752 (
8752- self.parse_snowflake_variable_declaration_expression()?,
8753+ self.parse_snowflake_variable_declaration_expression(false )?,
87538754 Some(data_type),
87548755 )
87558756 } else {
@@ -8860,18 +8861,19 @@ impl<'a> Parser<'a> {
88608861 /// <https://docs.snowflake.com/en/sql-reference/snowflake-scripting/declare#variable-declaration-syntax>
88618862 pub fn parse_snowflake_variable_declaration_expression(
88628863 &mut self,
8864+ allow_call: bool,
88638865 ) -> Result<Option<DeclareAssignment>, ParserError> {
88648866 Ok(match &self.peek_token_ref().token {
88658867 Token::Word(w) if w.keyword == Keyword::DEFAULT => {
88668868 self.next_token(); // Skip `DEFAULT`
88678869 Some(DeclareAssignment::Default(Box::new(
8868- self.parse_snowflake_declaration_payload_expr()?,
8870+ self.parse_snowflake_declaration_payload_expr(allow_call )?,
88698871 )))
88708872 }
88718873 Token::Assignment => {
88728874 self.next_token(); // Skip `:=`
88738875 Some(DeclareAssignment::DuckAssignment(Box::new(
8874- self.parse_snowflake_declaration_payload_expr()?,
8876+ self.parse_snowflake_declaration_payload_expr(allow_call )?,
88758877 )))
88768878 }
88778879 _ => None,
@@ -8880,11 +8882,64 @@ impl<'a> Parser<'a> {
88808882
88818883 /// Parses the expression payload of a Snowflake `RESULTSET` / `CURSOR`
88828884 /// declaration. Identical to [`Parser::parse_expr`] except that, under a
8883- /// dialect that allows it, a parenthesized `SHOW` statement is accepted as
8884- /// the query payload and wrapped as an [`Expr::Subquery`] whose body is a
8885- /// [`SetExpr::Show`]. The pre-existing `(SELECT ...)` subquery path is left
8886- /// untouched.
8887- fn parse_snowflake_declaration_payload_expr(&mut self) -> Result<Expr, ParserError> {
8885+ /// dialect that allows it, a parenthesized `SHOW` / `EXECUTE IMMEDIATE`
8886+ /// statement is accepted as the query payload and wrapped as an
8887+ /// [`Expr::Subquery`] whose body is a [`SetExpr::Show`] / [`SetExpr::Execute`].
8888+ /// When `allow_call` is set, a parenthesized `CALL` is likewise accepted and
8889+ /// wrapped as a [`SetExpr::Call`] — the `RESULTSET` initializer and
8890+ /// bare-assignment positions pass `true`, the `CURSOR FOR` position passes
8891+ /// `false` (Snowflake rejects `CURSOR FOR (CALL ...)`). The pre-existing
8892+ /// `(SELECT ...)` subquery path is left untouched.
8893+ fn parse_snowflake_declaration_payload_expr(
8894+ &mut self,
8895+ allow_call: bool,
8896+ ) -> Result<Expr, ParserError> {
8897+ let is_paren_call = allow_call
8898+ && self.dialect.supports_call_in_resultset()
8899+ && self.peek_nth_token_ref(0).token == Token::LParen
8900+ && matches!(
8901+ &self.peek_nth_token_ref(1).token,
8902+ Token::Word(w) if w.keyword == Keyword::CALL
8903+ );
8904+ if is_paren_call {
8905+ self.expect_token(&Token::LParen)?;
8906+ self.expect_keyword_is(Keyword::CALL)?;
8907+ let call = self.parse_call()?;
8908+ self.expect_token(&Token::RParen)?;
8909+ return Ok(Expr::Subquery(Box::new(Query {
8910+ with: None,
8911+ body: Box::new(SetExpr::Call(call)),
8912+ order_by: None,
8913+ limit_clause: None,
8914+ fetch: None,
8915+ locks: vec![],
8916+ for_clause: None,
8917+ settings: None,
8918+ format_clause: None,
8919+ pipe_operators: vec![],
8920+ })));
8921+ }
8922+ // Reject a `CALL` payload the accepted arm above did not consume. A bare
8923+ // (unparenthesized) `CALL` is never a valid payload expression, and a
8924+ // `(CALL ...)` in a position that forbids the procedure-call payload
8925+ // (`CURSOR FOR`, or any dialect without `supports_call_in_resultset`) is
8926+ // likewise invalid. Snowflake rejects both at the `CALL` keyword itself;
8927+ // the fork would otherwise parse `CALL` as a bare identifier and
8928+ // misreport the following token. Point the error at the `CALL` keyword.
8929+ let bare_call =
8930+ matches!(&self.peek_nth_token_ref(0).token, Token::Word(w) if w.keyword == Keyword::CALL);
8931+ let paren_call = self.peek_nth_token_ref(0).token == Token::LParen
8932+ && matches!(
8933+ &self.peek_nth_token_ref(1).token,
8934+ Token::Word(w) if w.keyword == Keyword::CALL
8935+ );
8936+ if bare_call {
8937+ return self.expected_ref("an expression", self.peek_nth_token_ref(0));
8938+ }
8939+ if paren_call {
8940+ self.expect_token(&Token::LParen)?;
8941+ return self.expected_ref("an expression", self.peek_nth_token_ref(0));
8942+ }
88888943 let is_paren_execute = self.dialect.supports_execute_immediate()
88898944 && self.peek_nth_token_ref(0).token == Token::LParen
88908945 && matches!(
0 commit comments