Skip to content

Commit 4f56f81

Browse files
committed
Support BEGIN as standalon clause
1 parent 7dbb724 commit 4f56f81

File tree

2 files changed

+77
-11
lines changed

2 files changed

+77
-11
lines changed

src/parser/mod.rs

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15597,6 +15597,25 @@ impl<'a> Parser<'a> {
1559715597
}
1559815598

1559915599
pub fn parse_begin_exception_end(&mut self) -> Result<Statement, ParserError> {
15600+
// Snowflake allows BEGIN as a standalone transaction statement (no END).
15601+
// If the next token is a semicolon or EOF, treat it as a standalone BEGIN.
15602+
if dialect_of!(self is SnowflakeDialect) {
15603+
match &self.peek_token_ref().token {
15604+
Token::SemiColon | Token::EOF => {
15605+
return Ok(Statement::StartTransaction {
15606+
begin: true,
15607+
statements: vec![],
15608+
exception: None,
15609+
has_end_keyword: false,
15610+
transaction: None,
15611+
modifier: None,
15612+
modes: Default::default(),
15613+
})
15614+
}
15615+
_ => {}
15616+
}
15617+
}
15618+
1560015619
let statements = self.parse_statement_list(&[Keyword::EXCEPTION, Keyword::END])?;
1560115620

1560215621
let exception = if self.parse_keyword(Keyword::EXCEPTION) {
@@ -15628,17 +15647,30 @@ impl<'a> Parser<'a> {
1562815647
None
1562915648
};
1563015649

15631-
self.expect_keyword(Keyword::END)?;
15632-
15633-
Ok(Statement::StartTransaction {
15634-
begin: true,
15635-
statements,
15636-
exception,
15637-
has_end_keyword: true,
15638-
transaction: None,
15639-
modifier: None,
15640-
modes: Default::default(),
15641-
})
15650+
if dialect_of!(self is SnowflakeDialect) {
15651+
// Make END optional for Snowflake. If present, set flag accordingly.
15652+
let has_end = self.parse_keyword(Keyword::END);
15653+
Ok(Statement::StartTransaction {
15654+
begin: true,
15655+
statements,
15656+
exception,
15657+
has_end_keyword: has_end,
15658+
transaction: None,
15659+
modifier: None,
15660+
modes: Default::default(),
15661+
})
15662+
} else {
15663+
self.expect_keyword(Keyword::END)?;
15664+
Ok(Statement::StartTransaction {
15665+
begin: true,
15666+
statements,
15667+
exception,
15668+
has_end_keyword: true,
15669+
transaction: None,
15670+
modifier: None,
15671+
modes: Default::default(),
15672+
})
15673+
}
1564215674
}
1564315675

1564415676
pub fn parse_end(&mut self) -> Result<Statement, ParserError> {

tests/sqlparser_snowflake.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4343,6 +4343,40 @@ fn test_snowflake_fetch_clause_syntax() {
43434343
);
43444344
}
43454345

4346+
#[test]
4347+
fn test_snowflake_begin_standalone() {
4348+
// BEGIN; (no END) should be allowed for Snowflake
4349+
let mut stmts = snowflake().parse_sql_statements("BEGIN;").unwrap();
4350+
assert_eq!(1, stmts.len());
4351+
match stmts.remove(0) {
4352+
Statement::StartTransaction {
4353+
begin,
4354+
has_end_keyword,
4355+
statements,
4356+
..
4357+
} => {
4358+
assert!(begin);
4359+
assert!(!has_end_keyword);
4360+
assert!(statements.is_empty());
4361+
}
4362+
other => panic!("unexpected stmt: {other:?}"),
4363+
}
4364+
}
4365+
4366+
#[test]
4367+
fn test_snowflake_begin_commit_sequence() {
4368+
let mut stmts = snowflake().parse_sql_statements("BEGIN; COMMIT;").unwrap();
4369+
assert_eq!(2, stmts.len());
4370+
match stmts.remove(0) {
4371+
Statement::StartTransaction { begin, .. } => assert!(begin),
4372+
other => panic!("unexpected first stmt: {other:?}"),
4373+
}
4374+
match stmts.remove(0) {
4375+
Statement::Commit { end, .. } => assert!(!end),
4376+
other => panic!("unexpected second stmt: {other:?}"),
4377+
}
4378+
}
4379+
43464380
#[test]
43474381
fn test_snowflake_create_view_with_multiple_column_options() {
43484382
let create_view_with_tag =

0 commit comments

Comments
 (0)