One function

StatementSplitter in andialbrecht/sqlparse

The author described this change as Fix handling of semicolons inside BEGIN...END blocks (fixes #809).. It counts as a record because the check below fails on the code as it stood at e92a032c8 and passes on 1a3bfbd50, with nothing else changed between the two runs.

Fix saved2025-11-28
Sharing licenceBSD-3-Clause · LICENSE
Change size+19 2

What the code was meant to do, written into the code itself as a docstring

Filter that split stream at individual statements

The change

1010 self._in_case = False
1111 self._is_create = False
1212 self._begin_depth = 0
13+ self._seen_begin = False
1314
1415 self.consume_ws = False
1516 self.tokens = []
4445
4546 if unified == 'BEGIN':
4647 self._begin_depth += 1
48+ self._seen_begin = True
4749 if self._is_create:
4850 # FIXME(andi): This makes no sense. ## this comment neither
4951 return 1
9698 # When implementing a language toggle, it's not only to add
9799 # keywords it's also to change some rules, like this splitting
98100 # rule.
99- if (self.level <= 0 and ttype is T.Punctuation and value == ';') \
100- or (ttype is T.Keyword and value.split()[0] == 'GO'):
101+ # Issue809: Ignore semicolons inside BEGIN...END blocks, but handle
102+ # standalone BEGIN; as a transaction statement
103+ if ttype is T.Punctuation and value == ';':
104+ # If we just saw BEGIN; then this is a transaction BEGIN,
105+ # not a BEGIN...END block, so decrement depth
106+ if self._seen_begin:
107+ self._begin_depth = max(0, self._begin_depth - 1)
108+ self._seen_begin = False
109+ # Split on semicolon if not inside a BEGIN...END block
110+ if self.level <= 0 and self._begin_depth == 0:
111+ self.consume_ws = True
112+ elif ttype is T.Keyword and value.split()[0] == 'GO':
101113 self.consume_ws = True
114+ elif (ttype not in (T.Whitespace, T.Comment.Single, T.Comment.Multiline)
115+ and not (ttype is T.Keyword and value.upper() == 'BEGIN')):
116+ # Reset _seen_begin if we see a non-whitespace, non-comment token
117+ # but not for BEGIN itself (which just set the flag)
118+ self._seen_begin = False
102119
103120 # Yield pending statement (if any)
104121 if self.tokens and not all(t.is_whitespace for t in self.tokens):

The check that tells the two apart

failpass·tests/test_split.py::test_split_begin_end_semicolons

Check file tests/test_split.py, taken without changes from the fix and copied onto the older code, so the exact same check runs against both versions.

Origin and history

The code before ite92a032c81d51a6645b4f8c32470481894818ba0
Broken version dated2025-11-27
Modulesqlparse.engine.statement_splitter
Units changedStatementSplitter
Fingerprintfde960d6e0f0debb
Checked2026-08-18 by goldset/0.1

Every field above is generated by our program. None of it is written by hand.

Other bugs found in andialbrecht/sqlparse