Summary
clickhouse_connect/driver/query.py remove_sql_comments strips comments with a single
regex that only understands -- line comments, non-nested /* */ block comments and
'/" quoting. The ClickHouse lexer also accepts //, # and #! line comments,
nests /* */, and has backtick-quoted identifiers, backslash escapes and $tag$
heredocs. The result feeds QueryContext.is_select, has_limit, is_insert,
is_command, the columns_only_re probe in _backend/httpcommon.py, and
dbapi.Cursor insert detection, so a comment the client does not understand
silently changes how the query is handled.
Verified against ClickHouse 26.5.1.882 and clickhouse-connect main (1.6.0).
Observed
With query_limit=2:
| query |
expected rows |
actual |
SELECT number FROM numbers(5) -- LIMIT 5 |
2 |
2 (correct) |
SELECT number FROM numbers(5) // LIMIT 5 |
2 |
5, query_limit silently not applied |
SELECT number FROM numbers(5) # LIMIT 5 |
2 |
5, query_limit silently not applied |
SELECT number FROM numbers(5) // LIMIT 0 |
2 |
0 rows, the query is routed to the columns-only metadata probe |
SELECT number FROM numbers(5) /* a /* b */ LIMIT 0 */ |
2 |
0 rows, the inner */ ends the comment and leaves LIMIT 0 behind |
SELECT number AS + 'a--b' + FROM numbers(9) LIMIT 1 |
1 |
DatabaseError code 62, the real LIMIT 1 is eaten as a comment so the client appends a second LIMIT |
SELECT number, $$--$$ AS tag FROM numbers(9) LIMIT 1 |
1 |
DatabaseError code 62, same cause |
SELECT number FROM numbers(9) WHERE toString(number) != 'a\'b-- LIMIT 0' LIMIT 1 |
1 |
DatabaseError code 62, the backslash escaped quote ends the string early |
Server side confirmation that all of these are comments or quoted tokens:
SELECT 1 //x -> 1
SELECT 1 # x -> 1
SELECT 1 #!x -> 1
SELECT 1 #x -> code 62, `#` alone is not a comment marker
SELECT 1 /* a /* b */ still comment */ -> 1
SELECT $$--$$ -> --
SELECT 'a\'b' -> a\'b
Cause
comment_re = re.compile(r"(\".*?\"|\'.*?\')|(/\*.*?\*/|(--)[^\n]*$)", re.MULTILINE | re.DOTALL)
is both incomplete and, being built from .*?, the same backtracking shape that was
rejected in #906.
Suggested fix
Replace the regex with a single linear left to right scan that follows the server lexer:
--, //, # and #! line comments, nested /* */ block comments, '', "" and
backtick quoting with backslash and doubled quote escapes, and $tag$ heredocs. An
unterminated comment or quote can be passed through unchanged, since the server rejects
the query anyway.
Summary
clickhouse_connect/driver/query.pyremove_sql_commentsstrips comments with a singleregex that only understands
--line comments, non-nested/* */block comments and'/"quoting. The ClickHouse lexer also accepts//,#and#!line comments,nests
/* */, and has backtick-quoted identifiers, backslash escapes and$tag$heredocs. The result feeds
QueryContext.is_select,has_limit,is_insert,is_command, thecolumns_only_reprobe in_backend/httpcommon.py, anddbapi.Cursorinsert detection, so a comment the client does not understandsilently changes how the query is handled.
Verified against ClickHouse 26.5.1.882 and clickhouse-connect main (1.6.0).
Observed
With
query_limit=2:SELECT number FROM numbers(5) -- LIMIT 5SELECT number FROM numbers(5) // LIMIT 5query_limitsilently not appliedSELECT number FROM numbers(5) # LIMIT 5query_limitsilently not appliedSELECT number FROM numbers(5) // LIMIT 0SELECT number FROM numbers(5) /* a /* b */ LIMIT 0 */*/ends the comment and leavesLIMIT 0behindSELECT number AS+ 'a--b' +FROM numbers(9) LIMIT 1DatabaseErrorcode 62, the realLIMIT 1is eaten as a comment so the client appends a secondLIMITSELECT number, $$--$$ AS tag FROM numbers(9) LIMIT 1DatabaseErrorcode 62, same causeSELECT number FROM numbers(9) WHERE toString(number) != 'a\'b-- LIMIT 0' LIMIT 1DatabaseErrorcode 62, the backslash escaped quote ends the string earlyServer side confirmation that all of these are comments or quoted tokens:
Cause
comment_re = re.compile(r"(\".*?\"|\'.*?\')|(/\*.*?\*/|(--)[^\n]*$)", re.MULTILINE | re.DOTALL)is both incomplete and, being built from
.*?, the same backtracking shape that wasrejected in #906.
Suggested fix
Replace the regex with a single linear left to right scan that follows the server lexer:
--,//,#and#!line comments, nested/* */block comments,'',""andbacktick quoting with backslash and doubled quote escapes, and
$tag$heredocs. Anunterminated comment or quote can be passed through unchanged, since the server rejects
the query anyway.