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.
Projectandialbrecht/sqlparse
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
| 10 | 10 | self._in_case = False | |
| 11 | 11 | self._is_create = False | |
| 12 | 12 | self._begin_depth = 0 | |
| 13 | + | self._seen_begin = False | |
| 13 | 14 | ||
| 14 | 15 | self.consume_ws = False | |
| 15 | 16 | self.tokens = [] | |
| ⋯ | |||
| 44 | 45 | ||
| 45 | 46 | if unified == 'BEGIN': | |
| 46 | 47 | self._begin_depth += 1 | |
| 48 | + | self._seen_begin = True | |
| 47 | 49 | if self._is_create: | |
| 48 | 50 | # FIXME(andi): This makes no sense. ## this comment neither | |
| 49 | 51 | return 1 | |
| ⋯ | |||
| 96 | 98 | # When implementing a language toggle, it's not only to add | |
| 97 | 99 | # keywords it's also to change some rules, like this splitting | |
| 98 | 100 | # 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': | |
| 101 | 113 | 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 | |
| 102 | 119 | ||
| 103 | 120 | # Yield pending statement (if any) | |
| 104 | 121 | if self.tokens and not all(t.is_whitespace for t in self.tokens): | |
The check that tells the two apart
fail→pass·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
- 2026-07-25Fix get_real_name for names with more than two dotted parts (#332)
- 2026-07-22Fix function grouping skipped for lowercase 'as' in CREATE TABLE AS SELECT
- 2025-11-29StatementSplitter
- 2024-07-15StatementSplitter
- 2024-04-13Raise SQLParseError instead of RecursionError.
- 2024-04-13Fix Function.get_parameters(), add Funtion.get_window()