Skip to content

Commit

Permalink
Add sql.Valuer support for all types (#1144)
Browse files Browse the repository at this point in the history
The existing implementation of strings value.Valuer only checked if the
return type was a `string` and none of the other supported types and so
changed to send it back through AppendRow again for those supported
types to be checked again.
  • Loading branch information
deankarn authored Dec 1, 2023
1 parent 05ce897 commit fb3a5ca
Show file tree
Hide file tree
Showing 47 changed files with 2,183 additions and 33 deletions.
2 changes: 1 addition & 1 deletion contributors/list
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ Chao Wang <chaowang@uber.com>
Chris Duncan <veqryn@hotmail.com>
Daguang <28806852+DGuang21@users.noreply.github.com>
Dale McDiarmid <dale@clickhouse.com>
Dale Mcdiarmid <dale@clickhouse.com>
Damir Sayfutdinov <sayfutdinov@selectel.ru>
Dan Walters <dan@walters.io>
Daniel Bershatsky <daniel.bershatsky@skolkovotech.ru>
Danila Migalin <miga@uber.com>
Danny.Dunn <danny@DannyDunndeMBP.lan>
Darío <dgrripoll@gmail.com>
Dave Josephsen <dave.josephsen@gmail.com>
Dean Karn <dean.karn@gmail.com>
Denis Gukov <denguk@gmail.com>
Denis Krivak <dokrivak@avito.ru>
Denys <drimd@ukr.net>
Expand Down
20 changes: 15 additions & 5 deletions lib/column/array.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,13 +191,23 @@ func appendNullableRowPlain[T any](col *Array, arr []*T) error {

func (col *Array) append(elem reflect.Value, level int) error {
if level < col.depth {
col.appendOffset(level, uint64(elem.Len()))
for i := 0; i < elem.Len(); i++ {
if err := col.append(elem.Index(i), level+1); err != nil {
return err
switch elem.Kind() {
// reflect.Value.Len() & reflect.Value.Index() is called in `append` method which is only valid for
// Slice, Array and String that make sense here.
case reflect.Slice, reflect.Array, reflect.String:
col.appendOffset(level, uint64(elem.Len()))
for i := 0; i < elem.Len(); i++ {
if err := col.append(elem.Index(i), level+1); err != nil {
return err
}
}
return nil
}
return &ColumnConverterError{
Op: "AppendRow",
To: "Array",
From: fmt.Sprintf("%T", elem),
}
return nil
}
if elem.Kind() == reflect.Ptr && elem.IsNil() {
return col.values.AppendRow(nil)
Expand Down
14 changes: 14 additions & 0 deletions lib/column/array_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions lib/column/bigint.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package column

import (
"database/sql/driver"
"encoding/binary"
"fmt"
"github.com/ClickHouse/ch-go/proto"
Expand Down Expand Up @@ -97,6 +98,18 @@ func (col *BigInt) Append(v any) (nulls []uint8, err error) {
}
}
default:
if valuer, ok := v.(driver.Valuer); ok {
val, err := valuer.Value()
if err != nil {
return nil, &ColumnConverterError{
Op: "Append",
To: string(col.chType),
From: fmt.Sprintf("%T", v),
Hint: "could not get driver.Valuer value",
}
}
return col.Append(val)
}
return nil, &ColumnConverterError{
Op: "Append",
To: string(col.chType),
Expand All @@ -120,6 +133,18 @@ func (col *BigInt) AppendRow(v any) error {
case nil:
col.append(big.NewInt(0))
default:
if valuer, ok := v.(driver.Valuer); ok {
val, err := valuer.Value()
if err != nil {
return &ColumnConverterError{
Op: "AppendRow",
To: string(col.chType),
From: fmt.Sprintf("%T", v),
Hint: "could not get driver.Valuer value",
}
}
return col.AppendRow(val)
}
return &ColumnConverterError{
Op: "AppendRow",
To: string(col.chType),
Expand Down
25 changes: 25 additions & 0 deletions lib/column/bool.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package column

import (
"database/sql"
"database/sql/driver"
"fmt"
"github.com/ClickHouse/ch-go/proto"
"reflect"
Expand Down Expand Up @@ -110,6 +111,18 @@ func (col *Bool) Append(v any) (nulls []uint8, err error) {
col.Append(v[i])
}
default:
if valuer, ok := v.(driver.Valuer); ok {
val, err := valuer.Value()
if err != nil {
return nil, &ColumnConverterError{
Op: "Append",
To: "Bool",
From: fmt.Sprintf("%T", v),
Hint: "could not get driver.Valuer value",
}
}
return col.Append(val)
}
return nil, &ColumnConverterError{
Op: "Append",
To: "Bool",
Expand Down Expand Up @@ -140,6 +153,18 @@ func (col *Bool) AppendRow(v any) error {
}
case nil:
default:
if valuer, ok := v.(driver.Valuer); ok {
val, err := valuer.Value()
if err != nil {
return &ColumnConverterError{
Op: "AppendRow",
To: "Bool",
From: fmt.Sprintf("%T", v),
Hint: "could not get driver.Valuer value",
}
}
return col.AppendRow(val)
}
return &ColumnConverterError{
Op: "AppendRow",
To: "Bool",
Expand Down
14 changes: 14 additions & 0 deletions lib/column/codegen/array.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ package column

import (
"database/sql"
"database/sql/driver"
"github.com/ClickHouse/ch-go/proto"
"github.com/google/uuid"
"github.com/paulmach/orb"
Expand All @@ -30,6 +31,7 @@ import (
"net"
"net/netip"
"time"
"fmt"
)

// appendRowPlain is a reflection-free realisation of append for plain arrays.
Expand All @@ -42,6 +44,18 @@ func (col *Array) appendRowPlain(v any) error {
return appendNullableRowPlain(col, tv)
{{- end }}
default:
if valuer, ok := v.(driver.Valuer); ok {
val, err := valuer.Value()
if err != nil {
return &ColumnConverterError{
Op: "AppendRow",
To: "Array",
From: fmt.Sprintf("%T", v),
Hint: "could not get driver.Valuer value",
}
}
return col.appendRowPlain(val)
}
return col.appendRowDefault(v)
}
}
29 changes: 29 additions & 0 deletions lib/column/codegen/column.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/paulmach/orb"
"github.com/shopspring/decimal"
"database/sql"
"database/sql/driver"
"github.com/ClickHouse/ch-go/proto"
)

Expand Down Expand Up @@ -315,6 +316,20 @@ func (col *{{ .ChType }}) Append(v any) (nulls []uint8,err error) {
}
{{- end }}
default:

if valuer, ok := v.(driver.Valuer); ok {
val, err := valuer.Value()
if err != nil {
return nil, &ColumnConverterError{
Op: "Append",
To: "{{ .ChType }}",
From: fmt.Sprintf("%T", v),
Hint: "could not get driver.Valuer value",
}
}
return col.Append(val)
}

return nil, &ColumnConverterError{
Op: "Append",
To: "{{ .ChType }}",
Expand Down Expand Up @@ -382,6 +397,20 @@ func (col *{{ .ChType }}) AppendRow(v any) error {
col.col.Append(val)
{{- end }}
default:

if valuer, ok := v.(driver.Valuer); ok {
val, err := valuer.Value()
if err != nil {
return &ColumnConverterError{
Op: "AppendRow",
To: "{{ .ChType }}",
From: fmt.Sprintf("%T", v),
Hint: "could not get driver.Valuer value",
}
}
return col.AppendRow(val)
}

if rv := reflect.ValueOf(v); rv.Kind() == col.ScanType().Kind() || rv.CanConvert(col.ScanType()) {
col.col.Append(rv.Convert(col.ScanType()).Interface().({{ .GoType }}))
} else {
Expand Down
Loading

0 comments on commit fb3a5ca

Please sign in to comment.