Skip to content

Commit

Permalink
Merge branch 'master' into hotfix-1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
bgaifullin committed Aug 14, 2018
2 parents 4e13d24 + 8c19f6f commit 7c1f87a
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 2 deletions.
12 changes: 10 additions & 2 deletions encoder.go
Expand Up @@ -99,9 +99,17 @@ func (d *textDecoder) Decode(t string, value []byte) (driver.Value, error) {
v := string(value)
switch t {
case "Date":
return time.ParseInLocation(dateFormat, unquote(v), d.location)
uv := unquote(v)
if uv == "0000-00-00" {
return time.Date(0, 0, 0, 0, 0, 0, 0, time.UTC), nil
}
return time.ParseInLocation(dateFormat, uv, d.location)
case "DateTime":
return time.ParseInLocation(timeFormat, unquote(v), d.location)
uv := unquote(v)
if uv == "0000-00-00 00:00:00" {
return time.Date(0, 0, 0, 0, 0, 0, 0, time.UTC), nil
}
return time.ParseInLocation(timeFormat, uv, d.location)
case "UInt8":
vv, err := strconv.ParseUint(v, 10, 8)
return uint8(vv), err
Expand Down
3 changes: 3 additions & 0 deletions encoder_test.go
Expand Up @@ -47,6 +47,7 @@ func TestTextEncoder(t *testing.T) {
func TestTextDecoder(t *testing.T) {
dt := time.Date(2011, 3, 6, 6, 20, 0, 0, time.UTC)
d := time.Date(2012, 5, 31, 0, 0, 0, 0, time.UTC)
zerodt := time.Date(0, 0, 0, 0, 0, 0, 0, time.UTC)
testCases := []struct {
tt string
value string
Expand All @@ -63,7 +64,9 @@ func TestTextDecoder(t *testing.T) {
{"Float32", "1", float32(1)},
{"Float64", "1", float64(1)},
{"Date", "'2012-05-31'", d},
{"Date", "'0000-00-00'", zerodt},
{"DateTime", "'2011-03-06 06:20:00'", dt},
{"DateTime", "'0000-00-00 00:00:00'", zerodt},
{"DateTime(\\'Europe/Moscow\\')", "'2011-03-06 06:20:00'", dt},
{"String", "'hello'", "hello"},
{"String", `'\\\\\'hello'`, `\\'hello`},
Expand Down
47 changes: 47 additions & 0 deletions value_converter.go
@@ -0,0 +1,47 @@
package clickhouse

import (
"database/sql/driver"
"reflect"
"strconv"
)

func (stmt *stmt) ColumnConverter(idx int) driver.ValueConverter {
return converter{}
}

func (c *conn) CheckNamedValue(nv *driver.NamedValue) (err error) {
nv.Value, err = converter{}.ConvertValue(nv.Value)
return
}

type converter struct{}

const maxAllowedUInt64 = 1<<63 - 1

func (c converter) ConvertValue(v interface{}) (driver.Value, error) {
if driver.IsValue(v) {
return v, nil
}

rv := reflect.ValueOf(v)
switch rv.Kind() {
case reflect.Ptr:
// indirect pointers
if rv.IsNil() {
return nil, nil
}
return c.ConvertValue(rv.Elem().Interface())
case reflect.Uint64:
u64 := rv.Uint()
if u64 > maxAllowedUInt64 {
s := strconv.FormatUint(u64, 10)
bytes := []byte(s)
return bytes, nil
}
// default behaviour to convert uint64 to int64
return int64(u64), nil
}

return driver.DefaultParameterConverter.ConvertValue(v)
}
31 changes: 31 additions & 0 deletions value_converter_test.go
@@ -0,0 +1,31 @@
package clickhouse

import (
"database/sql/driver"
"reflect"
"testing"

"github.com/stretchr/testify/assert"
)

func TestConverter(t *testing.T) {
testCases := []struct {
value interface{}
expected driver.Value
msg string
}{
{int64(maxAllowedUInt64), int64(9223372036854775807), "int64(maxAllowedUInt64)"},
{uint64(maxAllowedUInt64 + 1), []byte("9223372036854775808"), "uint64(maxAllowedUInt64+1)"},
{uint64(maxAllowedUInt64*2 + 1), []byte("18446744073709551615"), "uint64(maxUInt64)"},
}

for _, tc := range testCases {
dv, err := converter{}.ConvertValue(tc.value)
if assert.NoError(t, err) {
// assert.ElementsMatch(t, dv, tc.expected, "failed to convert "+tc.msg)
if !reflect.DeepEqual(tc.expected, dv) {
t.Errorf("failed to convert %s", tc.msg)
}
}
}
}

0 comments on commit 7c1f87a

Please sign in to comment.