Skip to content

Commit 5ca50a2

Browse files
committed
Fix splitting of BEGIN TRANSACTION statements (fixes #826).
1 parent acd8e58 commit 5ca50a2

File tree

3 files changed

+45
-2
lines changed

3 files changed

+45
-2
lines changed

CHANGELOG

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
Development Version
22
-------------------
33

4-
Nothing yet.
4+
Bug Fixes
5+
6+
* Fix splitting of BEGIN TRANSACTION statements (issue826).
57

68

79
Release 0.5.4 (Nov 28, 2025)

sqlparse/engine/statement_splitter.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,17 @@ def _change_splitlevel(self, ttype, value):
6161
return 1
6262
return 0
6363

64+
# Issue826: If we see a transaction keyword after BEGIN,
65+
# it's a transaction statement, not a block.
66+
if self._seen_begin and \
67+
(ttype is T.Keyword or ttype is T.Name) and \
68+
unified in ('TRANSACTION', 'WORK', 'TRAN',
69+
'DISTRIBUTED', 'DEFERRED',
70+
'IMMEDIATE', 'EXCLUSIVE'):
71+
self._begin_depth = max(0, self._begin_depth - 1)
72+
self._seen_begin = False
73+
return 0
74+
6475
# BEGIN and CASE/WHEN both end with END
6576
if unified == 'END':
6677
if not self._in_case:
@@ -121,7 +132,7 @@ def process(self, stream):
121132
self.consume_ws = True
122133
elif ttype is T.Keyword and value.split()[0] == 'GO':
123134
self.consume_ws = True
124-
elif (ttype not in (T.Whitespace, T.Comment.Single,
135+
elif (ttype not in (T.Whitespace, T.Newline, T.Comment.Single,
125136
T.Comment.Multiline)
126137
and not (ttype is T.Keyword and value.upper() == 'BEGIN')):
127138
# Reset _seen_begin if we see a non-whitespace, non-comment

tests/test_split.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,3 +254,33 @@ def test_split_begin_end_procedure(): # issue809
254254
stmts = sqlparse.split(sql)
255255
assert len(stmts) == 1
256256
assert 'CREATE OR REPLACE PROCEDURE' in stmts[0]
257+
258+
259+
def test_split_begin_transaction(): # issue826
260+
# BEGIN TRANSACTION should not be treated as a block start
261+
sql = """BEGIN TRANSACTION;
262+
DELETE FROM "schema"."table_a" USING "table_a_temp" WHERE "schema"."table_a"."id" = "table_a_temp"."id";
263+
INSERT INTO "schema"."table_a" SELECT * FROM "table_a_temp";
264+
END TRANSACTION;"""
265+
stmts = sqlparse.split(sql)
266+
assert len(stmts) == 4
267+
assert stmts[0] == 'BEGIN TRANSACTION;'
268+
assert stmts[1].startswith('DELETE')
269+
assert stmts[2].startswith('INSERT')
270+
assert stmts[3] == 'END TRANSACTION;'
271+
272+
273+
def test_split_begin_transaction_formatted(): # issue826
274+
# Test with formatted SQL (newlines between BEGIN and TRANSACTION)
275+
sql = """BEGIN
276+
TRANSACTION;
277+
DELETE FROM "schema"."table_a" USING "table_a_temp" WHERE "schema"."table_a"."id" = "table_a_temp"."id";
278+
INSERT INTO "schema"."table_a" SELECT * FROM "table_a_temp";
279+
END
280+
TRANSACTION;"""
281+
stmts = sqlparse.split(sql)
282+
assert len(stmts) == 4
283+
assert stmts[0] == 'BEGIN\nTRANSACTION;'
284+
assert stmts[1].startswith('DELETE')
285+
assert stmts[2].startswith('INSERT')
286+
assert stmts[3] == 'END\nTRANSACTION;'

0 commit comments

Comments
 (0)