Skip to content

Treat the GO batch separator case-insensitively when splitting - #882

Open
Gares95 wants to merge 1 commit into
andialbrecht:masterfrom
Gares95:fix/go-batch-separator-case-insensitive
Open

Treat the GO batch separator case-insensitively when splitting#882
Gares95 wants to merge 1 commit into
andialbrecht:masterfrom
Gares95:fix/go-batch-separator-case-insensitive

Conversation

@Gares95

@Gares95 Gares95 commented Aug 23, 2026

Copy link
Copy Markdown

Description

sqlparse.split() only recognises the T-SQL batch separator when it is written
in uppercase. A script using the equally valid lowercase go has its batches
merged instead of separated.

>>> import sqlparse
>>> len(sqlparse.split("USE foo;\nGO\nSELECT 1;\nGO"))
4
>>> len(sqlparse.split("USE foo;\ngo\nSELECT 1;\ngo"))
3
>>> sqlparse.split("USE foo;\ngo\nSELECT 1;\ngo")
['USE foo;', 'go\nSELECT 1;', 'go']

GO 2 behaves the same way: it splits, while go 2 does not.

The cause is in StatementSplitter.process, which compares the raw token value
against an uppercase literal:

elif ttype is T.Keyword and value.split()[0] == 'GO':

The lexer compiles every pattern with re.IGNORECASE and is_keyword uppercases
only for the dictionary lookup, returning the original spelling, so go arrives
as (T.Keyword, 'go') and the comparison fails. Every other keyword comparison
in this class already normalises through unified = value.upper(); this is the
one place that does not.

The fix matches that existing convention:

elif ttype is T.Keyword and value.upper().split()[0] == 'GO':

Tests: test_split_go is extended with lowercase and mixed-case spellings of
both GO and GO 2, so the separator is pinned as case-insensitive.

Validation: the suite is 506 passed, 2 xfailed, 1 xpassed before the change
and 510 passed, 2 xfailed, 1 xpassed after it, the four extra cases being the
new parameters. ruff check sqlparse/ passes. After the fix all of GO, go,
Go, gO, GO 2 and go 2 split identically.

The lexer compiles every pattern with re.IGNORECASE, and is_keyword
uppercases only for the dictionary lookup and returns the original
spelling, so a lowercase "go" reaches the splitter as (T.Keyword, 'go').
StatementSplitter.process compared that raw value against 'GO', so
lowercase and mixed-case batch separators did not split and their
batches were merged into the following statement.

Every other keyword comparison in the class normalises through
value.upper(). This makes that one consistent, and adds case-varied
parameters to test_split_go.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant