fix: query parameter detection in quoted SQL - #1938
Conversation
Signed-off-by: Minh Vu <vuhoangminh97@gmail.com>
|
|
||
| func isQueryParameter(query string) bool { | ||
| nameEnd := 0 | ||
| for nameEnd < len(query) && isNameChar(query[nameEnd]) { |
There was a problem hiding this comment.
ClickHouse parses {name:Type} from tokens with whitespace already dropped, so SELECT { p : String } is valid SQL — it used to match hasQueryParamsRe, but this scan requires the name to sit flush against { and :, so such a query now falls through to bind, which leaves the braces in the text and sends no parameters. The server then fails with Substitution 'p' is not set.
- The same scan accepts a digit-leading name, so a map literal such as
SELECT {1:'a'}, ?still takes the parameter path and reportsunsupported query parameter type— ClickHouse lexes a leading digit as a number, never as a substitution name. Pre-existing, but cheap to close here.
- nameEnd := 0
- for nameEnd < len(query) && isNameChar(query[nameEnd]) {
+ nameStart := skipSpace(query, 0) // small helper: advances over ' ', '\t', '\r', '\n'
+ if nameStart >= len(query) || isDigit(query[nameStart]) {
+ return false
+ }
+ nameEnd := nameStart
+ for nameEnd < len(query) && isNameChar(query[nameEnd]) {
nameEnd++
}
- if nameEnd == 0 || nameEnd >= len(query) || query[nameEnd] != ':' {
+ colon := skipSpace(query, nameEnd)
+ if nameEnd == nameStart || colon >= len(query) || query[colon] != ':' {
return false
}The type scan then starts at colon+1 and its guard becomes i > colon+1. Two table cases would lock this down: { p : String } detected, {1:'a'} not.
| return bind(timezone, query, args...) | ||
| } | ||
|
|
||
| func hasQueryParameters(query string) bool { |
There was a problem hiding this comment.
💡 Nit — nit: document the two new scanner helpers
bind.go documents every scanner helper it owns (bindQuoteState, inProtectedContext, isNameChar) and the rest of this file carries dense rationale comments; these two functions carry none. One line each — what shape counts as a parameter, and why quoted/commented regions are skipped — keeps the invariant discoverable for whoever next touches the scanner.
🤖 Claude reviewReplaces the The new detector is strictly narrower than the old regex in every direction except multi-line types, so the risk in this PR is false negatives, not false positives. Key concern:
Blind spots:
Verdict: Inline comments are attached to the relevant lines. This summary updates in place on re-review. |
Signed-off-by: Minh Vu <vuhoangminh97@gmail.com>
Summary
Server-side query parameter detection currently applies a regular expression to the complete SQL query. Parameter-like text inside a string, quoted identifier, or comment can therefore select the native parameter path and reject ordinary positional arguments with "unsupported query parameter type".
Detect parameter syntax only outside quoted and commented contexts by reusing the existing binding scanner. The detection also requires a nonempty parameter name and type. Regression tests cover strings, quoted identifiers, line and block comments, and a real native parameter with a quoted Enum type.
Checklist
Testing