Conversation
`(r"'(''|\\'|[^'])*'", tokens.String.Single)` is ambiguous: once `[^']`
has consumed the first backslash of `\\`, the `\\'` alternative pairs the
second backslash up with the closing quote and swallows it, so the
literal runs on into the rest of the statement.
`SELECT '\\', '\\'` therefore lexed as one string token covering
`'\\', '`, followed by three error tokens.
An escape is really either a doubled quote or a backslash followed by
any character, and a plain character is neither a quote nor a
backslash, which makes the match unambiguous. The double quoted rule
carried the same ambiguity and is fixed the same way; it reports
String.Symbol, so `SELECT "\\", "\\"` was broken identically.
Closes andialbrecht#814
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #814
Problem
The string literal rules in
sqlparse/keywords.pyare ambiguous:Once
[^']has consumed the first backslash of a\\pair, the\\'alternative pairs the second backslash up with the closing quote and swallows it, so the literal runs on into the rest of the statement:The last three tokens are
Token.Error, so every downstream consumer — formatting, splitting, identifier detection — sees garbage after the first literal.An escape is really either a doubled quote or a backslash followed by any character, and a plain character is neither a quote nor a backslash:
That makes the match unambiguous. The escaping forms that already worked are unaffected:
'it\'s'and'it''s'still lex as one literal, so does a literal ending in an escaped backslash ('a\\'), multiline literals still match, and an unterminated literal still fails to match (and is reported as error tokens, as before).The double quoted rule carried the exact same ambiguity —
SELECT "\\", "\\"was mis-tokenized the same way — so it is fixed the same way. It reportsString.Symbol, hence a separate test. Happy to split that line into its own pull request if you would rather review it separately.Tests
In
tests/test_regressions.py:test_issue814— the reproducer from the issuetest_issue814_quoted_identifier— the same bug in the double quoted ruletest_issue814_keeps_escaping_forms— parametrized over'it\'s','it''s','a\\','plain', all of which must keep lexing as a singleString.Singletest_issue814_unterminated_string_still_unmatched—'abcmust keep failing to matchWithout the source change,
test_issue814andtest_issue814_quoted_identifierfail; the other two pass before and after, so they guard the fix rather than reproduce the bug.Executed before submitting:
pytest→ 513 passed, 2 xfailed, 1 xpassed (506 before, plus the 7 new cases)ruff check sqlparse/(the command behindmake lint) → cleanmasterAI assistance disclosure
The investigation and the patch were prepared with AI assistance. Everything above was verified by running the lexer directly on current
master, by running the full test suite both with and without the change, and by runningruff check; the changelog entry and this description are written from those results.