diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 75e88f8a83..8bf750765c 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -4059,6 +4059,12 @@ pub enum Statement { immediate: bool, into: Vec, using: Vec, + /// Whether the last parameter is the return value of the procedure + /// MSSQL: + output: bool, + /// Whether to invoke the procedure with the default parameter values + /// MSSQL: + default: bool, }, /// ```sql /// PREPARE name [ ( data_type [, ...] ) ] AS statement @@ -5815,6 +5821,8 @@ impl fmt::Display for Statement { immediate, into, using, + output, + default, } => { let (open, close) = if *has_parentheses { ("(", ")") @@ -5835,6 +5843,12 @@ impl fmt::Display for Statement { if !using.is_empty() { write!(f, " USING {}", display_comma_separated(using))?; }; + if *output { + write!(f, " OUTPUT")?; + } + if *default { + write!(f, " DEFAULT")?; + } Ok(()) } Statement::Prepare { diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 47b63da87d..b3ceec7e27 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -15734,10 +15734,11 @@ impl<'a> Parser<'a> { let has_parentheses = self.consume_token(&Token::LParen); + let end_kws = &[Keyword::USING, Keyword::OUTPUT, Keyword::DEFAULT]; let end_token = match (has_parentheses, self.peek_token().token) { (true, _) => Token::RParen, (false, Token::EOF) => Token::EOF, - (false, Token::Word(w)) if w.keyword == Keyword::USING => Token::Word(w), + (false, Token::Word(w)) if end_kws.contains(&w.keyword) => Token::Word(w), (false, _) => Token::SemiColon, }; @@ -15759,6 +15760,10 @@ impl<'a> Parser<'a> { vec![] }; + let output = self.parse_keyword(Keyword::OUTPUT); + + let default = self.parse_keyword(Keyword::DEFAULT); + Ok(Statement::Execute { immediate: name.is_none(), name, @@ -15766,6 +15771,8 @@ impl<'a> Parser<'a> { has_parentheses, into, using, + output, + default, }) } diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 15144479c7..ff237a4787 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -11406,6 +11406,8 @@ fn parse_execute_stored_procedure() { immediate: false, using: vec![], into: vec![], + output: false, + default: false, }; assert_eq!( // Microsoft SQL Server does not use parentheses around arguments for EXECUTE @@ -11420,6 +11422,18 @@ fn parse_execute_stored_procedure() { ), expected ); + match ms_and_generic().verified_stmt("EXECUTE dbo.proc1 @ReturnVal = @X OUTPUT") { + Statement::Execute { output, .. } => { + assert!(output); + } + _ => unreachable!(), + } + match ms_and_generic().verified_stmt("EXECUTE dbo.proc1 DEFAULT") { + Statement::Execute { default, .. } => { + assert!(default); + } + _ => unreachable!(), + } } #[test] @@ -11438,6 +11452,8 @@ fn parse_execute_immediate() { into: vec![Ident::new("a")], name: None, has_parentheses: false, + output: false, + default: false, }; let stmt = dialects.verified_stmt("EXECUTE IMMEDIATE 'SELECT 1' INTO a USING 1 AS b"); diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index 0d1d138cd5..461277d81d 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -1666,7 +1666,9 @@ fn parse_execute() { has_parentheses: false, using: vec![], immediate: false, - into: vec![] + into: vec![], + output: false, + default: false, } ); @@ -1682,7 +1684,9 @@ fn parse_execute() { has_parentheses: true, using: vec![], immediate: false, - into: vec![] + into: vec![], + output: false, + default: false, } ); @@ -1719,7 +1723,9 @@ fn parse_execute() { }, ], immediate: false, - into: vec![] + into: vec![], + output: false, + default: false, } ); }