Observed
When using server-side query parameters ({name:Type} syntax with clickhouse.Named / clickhouse.DateNamed), the driver serializes several value types into text that ClickHouse cannot parse back, causing the query to fail:
Named("p", time.Time{}) for a {p:Date} parameter is sent as toDateTime('2026-05-15 00:00:00'), which the server rejects as a Date (code 38). The same reuse of the client-side formatter also affects Array(Date) / Array(DateTime) and Array(Bool) (codes 27 / 130).
- String values inside array parameters are escaped with
\', which the parameter parser rejects (code 25). Plain string parameters containing a newline or tab fail under server-side TSV parsing (code 457).
DateNamed formats the timestamp without a timezone, so the server interprets it in its own timezone — the bound instant shifts on any non-UTC server.
Expected behaviour
Values passed via Named / DateNamed for {name:Type} parameters should be serialized in the plain text format ClickHouse's parameter parser expects (e.g. 2026-05-15 for Date, true/false for Bool, unescaped/TSV-correct strings, timezone-anchored timestamps), so that any value valid for the declared type round-trips successfully.
Code example
package main
import (
"context"
"fmt"
"time"
"github.com/ClickHouse/clickhouse-go/v2"
)
func main() {
conn, err := clickhouse.Open(&clickhouse.Options{
Addr: []string{"127.0.0.1:9000"},
Auth: clickhouse.Auth{Database: "default", Username: "default", Password: "pass"},
})
if err != nil {
panic(err)
}
ctx := context.Background()
run := func(name, sql string, args ...any) {
rows, err := conn.Query(ctx, sql, args...)
if err != nil {
fmt.Printf("%s\n ERROR: %v\n", name, err)
return
}
rows.Close()
fmt.Printf("%s\n OK\n", name)
}
d := time.Date(2026, 5, 15, 0, 0, 0, 0, time.UTC)
// 1. Named(time.Time) sends toDateTime('...'), invalid as a Date literal.
run("1. {p:Date} bound with Named(time.Time)",
"SELECT {p:Date}", clickhouse.Named("p", d))
// 1b/1c. Array element formatting reuses the same formatter.
run("1b. {p:Array(Bool)} bound with []bool",
"SELECT {p:Array(Bool)}", clickhouse.Named("p", []bool{true}))
run("1c. {p:Array(Date)} bound with []time.Time",
"SELECT {p:Array(Date)}", clickhouse.Named("p", []time.Time{d}))
// 2a. Single quote in an array element is escaped as \', rejected by the parser.
run("2a. {p:Array(String)} element containing a single quote",
"SELECT {p:Array(String)}", clickhouse.Named("p", []string{"it's"}))
// 2b. String parameters are re-parsed with TSV escaping; newline fails.
run("2b. {p:String} with embedded newline",
"SELECT {p:String}", clickhouse.Named("p", "a\nb"))
// 3. DateNamed formats without a timezone; result shifts on non-UTC servers.
var got time.Time
if err := conn.QueryRow(ctx, "SELECT {p:DateTime64(9)}",
clickhouse.DateNamed("p", d, clickhouse.NanoSeconds)).Scan(&got); err != nil {
fmt.Printf("3. {p:DateTime64(9)} bound with DateNamed\n ERROR: %v\n", err)
} else {
fmt.Printf("3. {p:DateTime64(9)} bound with DateNamed\n bound unix=%d, got unix=%d (differs when server TZ is not UTC)\n",
d.Unix(), got.Unix())
}
}
Error log
1. {p:Date} bound with Named(time.Time)
ERROR: code: 38, message: Cannot parse date here: toDateTime: value toDateTime('2026-05-15 00:00:00') cannot be parsed as Date for query parameter 'p'
1b. {p:Array(Bool)} bound with []bool
ERROR: code: 130, message: Cannot read array from text, expected comma or end of array, found '1': value [1] cannot be parsed as Array(Bool) for query parameter 'p'
1c. {p:Array(Date)} bound with []time.Time
ERROR: code: 27, message: Cannot parse input: expected '\'' before: 'toDateTime(\'2026-05-15 00:00:00\')]': value [toDateTime('2026-05-15 00:00:00')] cannot be parsed as Array(Date) for query parameter 'p'
2a. {p:Array(String)} element containing a single quote
ERROR: code: 25, message: Cannot parse escape sequence: value ['it\ cannot be parsed as Array(String) for query parameter 'p'
2b. {p:String} with embedded newline
ERROR: code: 457, message: Value a
b cannot be parsed as String for query parameter 'p' because it isn't parsed completely: only 1 of 3 bytes was parsed: a
Details
Environment
Observed
When using server-side query parameters (
{name:Type}syntax withclickhouse.Named/clickhouse.DateNamed), the driver serializes several value types into text that ClickHouse cannot parse back, causing the query to fail:Named("p", time.Time{})for a{p:Date}parameter is sent astoDateTime('2026-05-15 00:00:00'), which the server rejects as aDate(code 38). The same reuse of the client-side formatter also affectsArray(Date)/Array(DateTime)andArray(Bool)(codes 27 / 130).\', which the parameter parser rejects (code 25). Plain string parameters containing a newline or tab fail under server-side TSV parsing (code 457).DateNamedformats the timestamp without a timezone, so the server interprets it in its own timezone — the bound instant shifts on any non-UTC server.Expected behaviour
Values passed via
Named/DateNamedfor{name:Type}parameters should be serialized in the plain text format ClickHouse's parameter parser expects (e.g.2026-05-15forDate,true/falseforBool, unescaped/TSV-correct strings, timezone-anchored timestamps), so that any value valid for the declared type round-trips successfully.Code example
Error log
Details
Environment
clickhouse-goversion: v2.45.0clickhouse/clickhouse-server:24.8)TZ=Australia/Sydneyto observe the shift)CREATE TABLEstatements for tables involved: n/a — reproduces withSELECT {p:Type}, no tables