Summary
When a SQL query contains a {identifier:Type} pattern inside a -- comment, the driver switches the entire query to server-side query-settings mode. Any @name parameter in the actual SQL is then left unsubstituted and reaches ClickHouse as a bare @name token, producing error code 26.
The bug reproduces whether or not the identifier in the comment matches a named parameter.
Environment
- clickhouse-go: v2.43.0
- ClickHouse server: 26.2.5.45
- Go: 1.25.0
- Protocol: native TCP (port 9000)
Reproduction
package main
import (
"context"
"fmt"
"os"
"github.com/ClickHouse/clickhouse-go/v2"
)
func main() {
opts, _ := clickhouse.ParseDSN(os.Getenv("CLICKHOUSE_DSN"))
conn, _ := clickhouse.Open(opts)
defer conn.Close()
ctx := context.Background()
run := func(label, query string, args ...any) {
rows, err := conn.Query(ctx, query, args...)
if err != nil {
fmt.Printf("FAIL %s\n %v\n", label, err)
return
}
rows.Close()
fmt.Printf("PASS %s\n", label)
}
// PASS: @name alone, no {x:T} anywhere in the SQL
run("baseline",
`SELECT number FROM numbers(@limit)`,
clickhouse.Named("limit", uint32(5)),
)
// PASS: @name in a comment is fine when no {x:T} is present
run("@name in comment, no {x:T}",
"-- uses @limit\nSELECT number FROM numbers(@limit)",
clickhouse.Named("limit", uint32(5)),
)
// FAIL: {x:T} in a comment — identifier matches a named param
// Driver forces server-side mode; @limit in SQL is never substituted.
run("{x:T} in comment, identifier matches param",
"-- server-side equivalent: {limit:UInt32}\nSELECT number FROM numbers(@limit)",
clickhouse.Named("limit", uint32(5)),
)
// FAIL: {x:T} in a comment — identifier does not match any param
// Same failure regardless of whether the identifier is in the params map.
run("{x:T} in comment, identifier not in params",
"-- see {name:Type} style for expression positions\nSELECT number FROM numbers(@limit)",
clickhouse.Named("limit", uint32(5)),
)
}
Output:
PASS baseline
PASS @name in comment, no {x:T}
FAIL {x:T} in comment, identifier matches param
code: 26, message: Cannot parse quoted string: expected opening quote ''', got '5'
FAIL {x:T} in comment, identifier not in params
code: 26, message: Cannot parse quoted string: expected opening quote ''', got '5'
Expected behaviour
SQL comments should not be scanned for parameter patterns. {identifier:Type} inside a -- comment should have no effect on how @name parameters in the actual query are processed.
Actual behaviour
Any {identifier:Type} found in a -- comment forces the driver into server-side query-settings mode for the whole query. @name in the SQL is then passed through to ClickHouse unsubstituted, which rejects it (code 62 "Syntax error") or misinterprets the bound value (code 26 "Cannot parse quoted string") depending on the specific query structure.
Suggested fix
Strip or skip SQL comment regions before scanning for {identifier:Type} and @name patterns. Single-line (--) and block (/* */) comments should both be excluded from parameter scanning.
Summary
When a SQL query contains a
{identifier:Type}pattern inside a--comment, the driver switches the entire query to server-side query-settings mode. Any@nameparameter in the actual SQL is then left unsubstituted and reaches ClickHouse as a bare@nametoken, producing error code 26.The bug reproduces whether or not the identifier in the comment matches a named parameter.
Environment
Reproduction
Output:
Expected behaviour
SQL comments should not be scanned for parameter patterns.
{identifier:Type}inside a--comment should have no effect on how@nameparameters in the actual query are processed.Actual behaviour
Any
{identifier:Type}found in a--comment forces the driver into server-side query-settings mode for the whole query.@namein the SQL is then passed through to ClickHouse unsubstituted, which rejects it (code 62 "Syntax error") or misinterprets the bound value (code 26 "Cannot parse quoted string") depending on the specific query structure.Suggested fix
Strip or skip SQL comment regions before scanning for
{identifier:Type}and@namepatterns. Single-line (--) and block (/* */) comments should both be excluded from parameter scanning.