MSSQL: Add support for EXEC output and default keywords (#1940)

This commit is contained in:
Yoav Cohen 2025-07-14 10:19:28 +02:00 committed by GitHub
parent 750a7aa054
commit 9b9ffe450c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 47 additions and 4 deletions

View file

@ -4059,6 +4059,12 @@ pub enum Statement {
immediate: bool, immediate: bool,
into: Vec<Ident>, into: Vec<Ident>,
using: Vec<ExprWithAlias>, using: Vec<ExprWithAlias>,
/// Whether the last parameter is the return value of the procedure
/// MSSQL: <https://learn.microsoft.com/en-us/sql/t-sql/language-elements/execute-transact-sql?view=sql-server-ver17#output>
output: bool,
/// Whether to invoke the procedure with the default parameter values
/// MSSQL: <https://learn.microsoft.com/en-us/sql/t-sql/language-elements/execute-transact-sql?view=sql-server-ver17#default>
default: bool,
}, },
/// ```sql /// ```sql
/// PREPARE name [ ( data_type [, ...] ) ] AS statement /// PREPARE name [ ( data_type [, ...] ) ] AS statement
@ -5815,6 +5821,8 @@ impl fmt::Display for Statement {
immediate, immediate,
into, into,
using, using,
output,
default,
} => { } => {
let (open, close) = if *has_parentheses { let (open, close) = if *has_parentheses {
("(", ")") ("(", ")")
@ -5835,6 +5843,12 @@ impl fmt::Display for Statement {
if !using.is_empty() { if !using.is_empty() {
write!(f, " USING {}", display_comma_separated(using))?; write!(f, " USING {}", display_comma_separated(using))?;
}; };
if *output {
write!(f, " OUTPUT")?;
}
if *default {
write!(f, " DEFAULT")?;
}
Ok(()) Ok(())
} }
Statement::Prepare { Statement::Prepare {

View file

@ -15734,10 +15734,11 @@ impl<'a> Parser<'a> {
let has_parentheses = self.consume_token(&Token::LParen); 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) { let end_token = match (has_parentheses, self.peek_token().token) {
(true, _) => Token::RParen, (true, _) => Token::RParen,
(false, Token::EOF) => Token::EOF, (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, (false, _) => Token::SemiColon,
}; };
@ -15759,6 +15760,10 @@ impl<'a> Parser<'a> {
vec![] vec![]
}; };
let output = self.parse_keyword(Keyword::OUTPUT);
let default = self.parse_keyword(Keyword::DEFAULT);
Ok(Statement::Execute { Ok(Statement::Execute {
immediate: name.is_none(), immediate: name.is_none(),
name, name,
@ -15766,6 +15771,8 @@ impl<'a> Parser<'a> {
has_parentheses, has_parentheses,
into, into,
using, using,
output,
default,
}) })
} }

View file

@ -11393,6 +11393,8 @@ fn parse_execute_stored_procedure() {
immediate: false, immediate: false,
using: vec![], using: vec![],
into: vec![], into: vec![],
output: false,
default: false,
}; };
assert_eq!( assert_eq!(
// Microsoft SQL Server does not use parentheses around arguments for EXECUTE // Microsoft SQL Server does not use parentheses around arguments for EXECUTE
@ -11407,6 +11409,18 @@ fn parse_execute_stored_procedure() {
), ),
expected 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] #[test]
@ -11425,6 +11439,8 @@ fn parse_execute_immediate() {
into: vec![Ident::new("a")], into: vec![Ident::new("a")],
name: None, name: None,
has_parentheses: false, has_parentheses: false,
output: false,
default: false,
}; };
let stmt = dialects.verified_stmt("EXECUTE IMMEDIATE 'SELECT 1' INTO a USING 1 AS b"); let stmt = dialects.verified_stmt("EXECUTE IMMEDIATE 'SELECT 1' INTO a USING 1 AS b");

View file

@ -1666,7 +1666,9 @@ fn parse_execute() {
has_parentheses: false, has_parentheses: false,
using: vec![], using: vec![],
immediate: false, immediate: false,
into: vec![] into: vec![],
output: false,
default: false,
} }
); );
@ -1682,7 +1684,9 @@ fn parse_execute() {
has_parentheses: true, has_parentheses: true,
using: vec![], using: vec![],
immediate: false, immediate: false,
into: vec![] into: vec![],
output: false,
default: false,
} }
); );
@ -1719,7 +1723,9 @@ fn parse_execute() {
}, },
], ],
immediate: false, immediate: false,
into: vec![] into: vec![],
output: false,
default: false,
} }
); );
} }