-
Notifications
You must be signed in to change notification settings - Fork 629
Open
Labels
Description
Observed
- Create a table with a single
Nullable(Decimal64(2)) - Insert
(NULL), (NULL), (NULL), (123.1), (NULL), (124.1), (NULL), (NULL), (NULL), (NULL) - Read back the rows and observe the pointer not being reset when encountering a null value. The previous row's value is returned instead.
NULL, NULL, NULL, 123.1, 123.1, 124.1, 124.1, 124.1, 124.1, 124.1returned
Expected behaviour
The pointer should be reset when encountering NULL and not return the previous row's value.
Code example
Reproduction example from the original issue modified for decimal.Decimal.
examples/clickhouse_api/dynamic_scan_types.go
package clickhouse_api
import (
"context"
"fmt"
"reflect"
"github.com/shopspring/decimal"
)
func DynamicScan() error {
conn, err := GetNativeConnection(nil, nil, nil)
if err != nil {
return err
}
if err := conn.Exec(context.Background(), "CREATE TABLE IF NOT EXISTS dynamic_scan_table (Col1 Nullable(Decimal64(2))) ENGINE = Memory"); err != nil {
return err
}
if err := conn.Exec(context.Background(), "INSERT INTO dynamic_scan_table VALUES (NULL), (NULL), (NULL), (123.1), (NULL), (124.1), (NULL), (NULL), (NULL), (NULL)"); err != nil {
return err
}
rows, err := conn.Query(context.Background(), "SELECT Col1 FROM dynamic_scan_table")
if err != nil {
return err
}
var (
columnTypes = rows.ColumnTypes()
vars = make([]interface{}, len(columnTypes))
)
for i := range columnTypes {
vars[i] = reflect.New(columnTypes[i].ScanType()).Interface()
}
for rows.Next() {
if err := rows.Scan(vars...); err != nil {
return err
}
for _, v := range vars {
switch v := v.(type) {
case **decimal.Decimal:
if *v == nil {
fmt.Println("NULL")
continue
}
fmt.Println(**v)
}
}
}
return nil
}$ go test ./... -v -run DynamicScan
...
=== RUN TestDynamicScan
NULL
NULL
NULL
123.1
123.1
124.1
124.1
124.1
124.1
124.1
--- PASS: TestDynamicScan (0.06s)
Details
- Related to The results obtained were unexpected #955
- Should a
casefordecimal.Decimalhave been implemented in https://github.com/ClickHouse/clickhouse-go/blob/main/lib/column/nullable.go#L78-L103 ?
Note: seems to be working as expected if I implement a similar test for TestStdDynamicScan, in examples/std/dynamic_scan_types.go
=== RUN TestStdDynamicScan
NULL
NULL
NULL
123.1
NULL
124.1
NULL
NULL
NULL
NULL
--- PASS: TestStdDynamicScan (0.02s)
Environment
-
clickhouse-goversion: 2.40.3 - Interface: ClickHouse API
- Go version: 1.25.4
- Operating system: macOS
- ClickHouse version: 25.11 (latest)
- Is it a ClickHouse Cloud? No
- ClickHouse Server non-default settings, if any:
-
CREATE TABLEstatements for tables involved: - Sample data for all these tables, use clickhouse-obfuscator if necessary