Fix query type detection: scan comments with the server lexer rules - #926
Closed
polyglotAI-bot wants to merge 1 commit into
Closed
Fix query type detection: scan comments with the server lexer rules#926polyglotAI-bot wants to merge 1 commit into
polyglotAI-bot wants to merge 1 commit into
Conversation
remove_sql_comments only understood "--" line comments, non-nested "/* */" block comments and '' / "" quoting, so a "//" or "# " comment, the tail of a nested block comment, a backtick quoted identifier, a "$tag$" heredoc or a backslash escaped quote all left the classification string wrong. That string drives is_select, has_limit, is_insert, is_command and the columns-only probe, so the client side query_limit was silently dropped, a commented out LIMIT 0 routed the query to the metadata probe, and a "--" inside a quoted token made the client append a second LIMIT that the server rejects with code 62. Comments are now removed with a single linear scan that follows the server lexer, so the search cannot backtrack either. Fixes: #925
polyglotAI-bot
requested review from
joe-clickhouse and
peter-leonov-ch
as code owners
August 3, 2026 20:56
7 tasks
7 tasks
Contributor
|
Closing. The reported misclassifications are indeed valid. However, The |
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.
Description
Fixes #925.
remove_sql_commentsinclickhouse_connect/driver/query.pystripped comments with asingle regex that only understood
--line comments, non-nested/* */block commentsand
'/"quoting. The ClickHouse lexer also accepts//,#and#!linecomments, nests
/* */, and has backtick quoted identifiers, backslash and doubled quoteescapes, and
$tag$heredocs. Its output feedsQueryContext.is_select,has_limit,is_insert,is_command, thecolumns_only_reprobe in_backend/httpcommon.pyand_backend/chdb_backend.py, and DB-API insert detection, so any comment form the clientdid not understand silently changed how the query was handled. With
query_limit=2andClickHouse 26.5.1.882:
SELECT number FROM numbers(5) // LIMIT 5returned 5 rows, the client sidequery_limitwas dropped because the commented outLIMITlooked real. Same for#and#!.SELECT number FROM numbers(5) // LIMIT 0returned 0 rows, the query was routed tothe columns-only metadata probe.
SELECT number FROM numbers(5) /* a /* LIMIT 0 */ b */returned 0 rows, the inner*/ended the comment and leftLIMIT 0behind.SELECT number AS `a--b` FROM numbers(9) LIMIT 1,SELECT number, $$--$$ AS tag FROM numbers(9) LIMIT 1andSELECT ... != 'a\'b-- LIMIT 0' LIMIT 1all failed withDatabaseErrorcode 62: the--inside the quoted token truncated the classificationstring, the real trailing
LIMITwas lost, and the client appended a second one.Changes
clickhouse_connect/driver/query.py:remove_sql_commentsnow scans the query once,left to right, following the server lexer:
--,//,#and#!line comments,nested
/* */block comments,'',""and`` quoting with backslash anddoubled quote escapes, and
$tag$heredocs. The scan jumps from one such token to thenext, so it is linear in the length of the query and the regex it uses is a plain
alternation of literals that cannot backtrack, unlike the `.*?` pattern it replaces.
A `$` is a word character for the server lexer, so a heredoc tag only opens at the
start of a token and an unclosed tag is treated as a bare word, matching the server
(`SELECT 13 AS a$b$c -- x` and `SELECT 13
An unterminated comment or quote leaves the remainder untouched, since the server
rejects the query anyway. Comment removal itself is unchanged for the forms the old
regex already handled, including the surrounding whitespace.
CHANGELOG.md: entry under UNRELEASED.Behavior of the SQL actually sent to the server is untouched. This only corrects the
classification copy of the query.
Test
tests/unit_tests/test_driver/test_parser.py::test_remove_comments_lexer_forms,parametrized over the comment and quoting forms: the three line comment forms, a bare
#and#plus tab which are not comments, nested block comments, comment markersinside backtick identifiers, doubled and backslash escaped strings and heredocs,
$inside a word, an unclosed heredoc tag, and unterminated comments and quotes. 12 of
the 20 cases fail on
main.tests/integration_tests/test_client.py::test_query_limit_with_comments, parametrizedand run against both the sync and async clients through the
param_clientandcallfixtures. It pins the observable behavior end to end: a
LIMITinside a comment doesnot suppress
query_limit, and a comment marker inside a quoted token or heredoc doesnot eat the real trailing
LIMIT. 14 of the 24 cases fail onmain, the rest arecontrast cases (
--and plain/* */comments, plain string quoting) that must keeptheir current behavior.
the server directly.
tests/unit_testsis green (1074 passed),ruff format --check,ruff checkandmypyare clean. Two pre-existing integration failures intest_client.py(
test_session_params,test_query_id_in_query_logs) fail identically onmaininthis environment (no
system.session_log).Pre-PR validation gate
Note for reviewers
Open PR #924 (issue #903) adds a very similar linear scan in
clickhouse_connect/driver/binding.pyfor finding the query-final;. The two do notoverlap textually and each is useful on its own, but whichever lands second is a good
opportunity to share the
_skip/_end_ofprimitives between the two modules. Happy todo that consolidation in a follow-up.