Allow stored procedures to be defined without BEGIN/END (#1834)

This commit is contained in:
Andrew Harper 2025-05-08 19:40:03 -04:00 committed by GitHub
parent ac1c339666
commit 6cd237ea43
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 56 additions and 54 deletions

View file

@ -3826,7 +3826,7 @@ pub enum Statement {
or_alter: bool, or_alter: bool,
name: ObjectName, name: ObjectName,
params: Option<Vec<ProcedureParam>>, params: Option<Vec<ProcedureParam>>,
body: Vec<Statement>, body: ConditionalStatements,
}, },
/// ```sql /// ```sql
/// CREATE MACRO /// CREATE MACRO
@ -4705,11 +4705,8 @@ impl fmt::Display for Statement {
write!(f, " ({})", display_comma_separated(p))?; write!(f, " ({})", display_comma_separated(p))?;
} }
} }
write!(
f, write!(f, " AS {body}")
" AS BEGIN {body} END",
body = display_separated(body, "; ")
)
} }
Statement::CreateMacro { Statement::CreateMacro {
or_replace, or_replace,

View file

@ -15505,14 +15505,14 @@ impl<'a> Parser<'a> {
let name = self.parse_object_name(false)?; let name = self.parse_object_name(false)?;
let params = self.parse_optional_procedure_parameters()?; let params = self.parse_optional_procedure_parameters()?;
self.expect_keyword_is(Keyword::AS)?; self.expect_keyword_is(Keyword::AS)?;
self.expect_keyword_is(Keyword::BEGIN)?;
let statements = self.parse_statements()?; let body = self.parse_conditional_statements(&[Keyword::END])?;
self.expect_keyword_is(Keyword::END)?;
Ok(Statement::CreateProcedure { Ok(Statement::CreateProcedure {
name, name,
or_alter, or_alter,
params, params,
body: statements, body,
}) })
} }

View file

@ -100,48 +100,52 @@ fn parse_mssql_delimited_identifiers() {
#[test] #[test]
fn parse_create_procedure() { fn parse_create_procedure() {
let sql = "CREATE OR ALTER PROCEDURE test (@foo INT, @bar VARCHAR(256)) AS BEGIN SELECT 1 END"; let sql = "CREATE OR ALTER PROCEDURE test (@foo INT, @bar VARCHAR(256)) AS BEGIN SELECT 1; END";
assert_eq!( assert_eq!(
ms().verified_stmt(sql), ms().verified_stmt(sql),
Statement::CreateProcedure { Statement::CreateProcedure {
or_alter: true, or_alter: true,
body: vec![Statement::Query(Box::new(Query { body: ConditionalStatements::BeginEnd(BeginEndStatements {
with: None, begin_token: AttachedToken::empty(),
limit_clause: None, statements: vec![Statement::Query(Box::new(Query {
fetch: None, with: None,
locks: vec![], limit_clause: None,
for_clause: None, fetch: None,
order_by: None, locks: vec![],
settings: None, for_clause: None,
format_clause: None, order_by: None,
pipe_operators: vec![], settings: None,
body: Box::new(SetExpr::Select(Box::new(Select { format_clause: None,
select_token: AttachedToken::empty(), pipe_operators: vec![],
distinct: None, body: Box::new(SetExpr::Select(Box::new(Select {
top: None, select_token: AttachedToken::empty(),
top_before_distinct: false, distinct: None,
projection: vec![SelectItem::UnnamedExpr(Expr::Value( top: None,
(number("1")).with_empty_span() top_before_distinct: false,
))], projection: vec![SelectItem::UnnamedExpr(Expr::Value(
into: None, (number("1")).with_empty_span()
from: vec![], ))],
lateral_views: vec![], into: None,
prewhere: None, from: vec![],
selection: None, lateral_views: vec![],
group_by: GroupByExpr::Expressions(vec![], vec![]), prewhere: None,
cluster_by: vec![], selection: None,
distribute_by: vec![], group_by: GroupByExpr::Expressions(vec![], vec![]),
sort_by: vec![], cluster_by: vec![],
having: None, distribute_by: vec![],
named_window: vec![], sort_by: vec![],
window_before_qualify: false, having: None,
qualify: None, named_window: vec![],
value_table_mode: None, window_before_qualify: false,
connect_by: None, qualify: None,
flavor: SelectFlavor::Standard, value_table_mode: None,
}))) connect_by: None,
}))], flavor: SelectFlavor::Standard,
})))
}))],
end_token: AttachedToken::empty(),
}),
params: Some(vec![ params: Some(vec![
ProcedureParam { ProcedureParam {
name: Ident { name: Ident {
@ -174,19 +178,20 @@ fn parse_create_procedure() {
#[test] #[test]
fn parse_mssql_create_procedure() { fn parse_mssql_create_procedure() {
let _ = ms_and_generic().verified_stmt("CREATE OR ALTER PROCEDURE foo AS BEGIN SELECT 1 END"); let _ = ms_and_generic().verified_stmt("CREATE OR ALTER PROCEDURE foo AS SELECT 1;");
let _ = ms_and_generic().verified_stmt("CREATE PROCEDURE foo AS BEGIN SELECT 1 END"); let _ = ms_and_generic().verified_stmt("CREATE OR ALTER PROCEDURE foo AS BEGIN SELECT 1; END");
let _ = ms_and_generic().verified_stmt("CREATE PROCEDURE foo AS BEGIN SELECT 1; END");
let _ = ms().verified_stmt( let _ = ms().verified_stmt(
"CREATE PROCEDURE foo AS BEGIN SELECT [myColumn] FROM [myschema].[mytable] END", "CREATE PROCEDURE foo AS BEGIN SELECT [myColumn] FROM [myschema].[mytable]; END",
); );
let _ = ms_and_generic().verified_stmt( let _ = ms_and_generic().verified_stmt(
"CREATE PROCEDURE foo (@CustomerName NVARCHAR(50)) AS BEGIN SELECT * FROM DEV END", "CREATE PROCEDURE foo (@CustomerName NVARCHAR(50)) AS BEGIN SELECT * FROM DEV; END",
); );
let _ = ms().verified_stmt("CREATE PROCEDURE [foo] AS BEGIN UPDATE bar SET col = 'test' END"); let _ = ms().verified_stmt("CREATE PROCEDURE [foo] AS BEGIN UPDATE bar SET col = 'test'; END");
// Test a statement with END in it // Test a statement with END in it
let _ = ms().verified_stmt("CREATE PROCEDURE [foo] AS BEGIN SELECT [foo], CASE WHEN [foo] IS NULL THEN 'empty' ELSE 'notempty' END AS [foo] END"); let _ = ms().verified_stmt("CREATE PROCEDURE [foo] AS BEGIN SELECT [foo], CASE WHEN [foo] IS NULL THEN 'empty' ELSE 'notempty' END AS [foo]; END");
// Multiple statements // Multiple statements
let _ = ms().verified_stmt("CREATE PROCEDURE [foo] AS BEGIN UPDATE bar SET col = 'test'; SELECT [foo] FROM BAR WHERE [FOO] > 10 END"); let _ = ms().verified_stmt("CREATE PROCEDURE [foo] AS BEGIN UPDATE bar SET col = 'test'; SELECT [foo] FROM BAR WHERE [FOO] > 10; END");
} }
#[test] #[test]