Skip to content

Commit 9dffd58

Browse files
committed
custom types converter
1 parent ea12e61 commit 9dffd58

14 files changed

+273
-50
lines changed

.travis.yml

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ sudo: required
22
language: go
33
go:
44
- 1.8.x
5+
- 1.9.x
56
- master
67
go_import_path: github.com/kshvakov/clickhouse
78
services:

clickhouse.go

+41-2
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@ import (
77
"database/sql/driver"
88
"errors"
99
"fmt"
10+
"net"
11+
"reflect"
1012
"regexp"
1113
"sync"
1214
"time"
1315

1416
"github.com/kshvakov/clickhouse/lib/binary"
1517
"github.com/kshvakov/clickhouse/lib/data"
1618
"github.com/kshvakov/clickhouse/lib/protocol"
19+
"github.com/kshvakov/clickhouse/lib/types"
1720
)
1821

1922
var (
@@ -109,7 +112,7 @@ func (ch *clickhouse) beginTx(ctx context.Context, opts txOptions) (*clickhouse,
109112
case ch.conn.closed:
110113
return nil, driver.ErrBadConn
111114
}
112-
if finish := ch.watchCancel(ctx, ch.writeTimeout); finish != nil {
115+
if finish := ch.watchCancel(ctx); finish != nil {
113116
defer finish()
114117
}
115118
ch.block = nil
@@ -164,6 +167,42 @@ func (ch *clickhouse) CheckNamedValue(nv *driver.NamedValue) error {
164167
nv.Value = v.convert()
165168
case DateTime:
166169
nv.Value = v.convert()
170+
case IP, *types.Array, UUID:
171+
nv.Value = v
172+
case net.IP:
173+
nv.Value = IP(v)
174+
default:
175+
switch value := reflect.ValueOf(nv.Value); value.Kind() {
176+
case reflect.Bool:
177+
nv.Value = uint8(0)
178+
if value.Bool() {
179+
nv.Value = uint8(1)
180+
}
181+
case reflect.Int8:
182+
nv.Value = int8(value.Int())
183+
case reflect.Int16:
184+
nv.Value = int16(value.Int())
185+
case reflect.Int32:
186+
nv.Value = int32(value.Int())
187+
case reflect.Int64:
188+
nv.Value = value.Int()
189+
case reflect.Uint8:
190+
nv.Value = uint8(value.Uint())
191+
case reflect.Uint16:
192+
nv.Value = uint16(value.Uint())
193+
case reflect.Uint32:
194+
nv.Value = uint32(value.Uint())
195+
case reflect.Uint64:
196+
nv.Value = uint64(value.Uint())
197+
case reflect.Float32:
198+
nv.Value = float32(value.Float())
199+
case reflect.Float64:
200+
nv.Value = float64(value.Float())
201+
case reflect.String:
202+
nv.Value = value.String()
203+
case reflect.Slice:
204+
nv.Value = types.NewArray(value.Interface())
205+
}
167206
}
168207
return nil
169208
}
@@ -229,7 +268,7 @@ func (ch *clickhouse) cancel() error {
229268
return ch.conn.Close()
230269
}
231270

232-
func (ch *clickhouse) watchCancel(ctx context.Context, timeout time.Duration) func() {
271+
func (ch *clickhouse) watchCancel(ctx context.Context) func() {
233272
if done := ctx.Done(); done != nil {
234273
finished := make(chan struct{})
235274
go func() {

clickhouse_custom_types_test.go

+161
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
package clickhouse_test
2+
3+
import (
4+
"database/sql"
5+
"fmt"
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func Test_Custom_Types(t *testing.T) {
12+
type (
13+
T_Int8 int8
14+
T_Int16 int16
15+
T_Int32 int32
16+
T_Int64 int64
17+
T_UInt8 uint8
18+
T_UInt16 uint16
19+
T_UInt32 uint32
20+
T_UInt64 uint64
21+
T_Float32 float32
22+
T_Float64 float64
23+
T_String string
24+
T_FixedString string
25+
)
26+
const (
27+
ddl = `
28+
CREATE TABLE clickhouse_test_custom_types (
29+
int8 Int8,
30+
int16 Int16,
31+
int32 Int32,
32+
int64 Int64,
33+
uint8 UInt8,
34+
uint16 UInt16,
35+
uint32 UInt32,
36+
uint64 UInt64,
37+
float32 Float32,
38+
float64 Float64,
39+
string String,
40+
fString FixedString(2)
41+
) Engine=Memory
42+
`
43+
dml = `
44+
INSERT INTO clickhouse_test_custom_types (
45+
int8,
46+
int16,
47+
int32,
48+
int64,
49+
uint8,
50+
uint16,
51+
uint32,
52+
uint64,
53+
float32,
54+
float64,
55+
string,
56+
fString
57+
) VALUES (
58+
?,
59+
?,
60+
?,
61+
?,
62+
?,
63+
?,
64+
?,
65+
?,
66+
?,
67+
?,
68+
?,
69+
?
70+
)
71+
`
72+
query = `
73+
SELECT
74+
int8,
75+
int16,
76+
int32,
77+
int64,
78+
uint8,
79+
uint16,
80+
uint32,
81+
uint64,
82+
float32,
83+
float64,
84+
string,
85+
fString
86+
FROM clickhouse_test_custom_types
87+
`
88+
)
89+
if connect, err := sql.Open("clickhouse", "tcp://127.0.0.1:9000?debug=true"); assert.NoError(t, err) && assert.NoError(t, connect.Ping()) {
90+
if _, err := connect.Exec("DROP TABLE IF EXISTS clickhouse_test_custom_types"); assert.NoError(t, err) {
91+
if _, err := connect.Exec(ddl); assert.NoError(t, err) {
92+
if tx, err := connect.Begin(); assert.NoError(t, err) {
93+
if stmt, err := tx.Prepare(dml); assert.NoError(t, err) {
94+
for i := 1; i <= 10; i++ {
95+
_, err = stmt.Exec(
96+
T_Int8(-1*i),
97+
T_Int16(-2*i),
98+
T_Int32(-4*i),
99+
T_Int64(-8*i), // int
100+
T_UInt8(1*i),
101+
T_UInt16(2*i),
102+
T_UInt32(4*i),
103+
T_UInt64(8*i), // uint
104+
T_Float32(1.32*float32(i)),
105+
T_Float64(1.64*float64(i)), //float
106+
T_String(fmt.Sprintf("string %d", i)), // string
107+
T_FixedString("RU"), //fixedstring,
108+
109+
)
110+
if !assert.NoError(t, err) {
111+
return
112+
}
113+
}
114+
} else {
115+
return
116+
}
117+
if assert.NoError(t, tx.Commit()) {
118+
var item struct {
119+
Int8 T_Int8
120+
Int16 T_Int16
121+
Int32 T_Int32
122+
Int64 T_Int64
123+
UInt8 T_UInt8
124+
UInt16 T_UInt16
125+
UInt32 T_UInt32
126+
UInt64 T_UInt64
127+
Float32 T_Float32
128+
Float64 T_Float64
129+
String T_String
130+
FixedString T_FixedString
131+
}
132+
if rows, err := connect.Query(query); assert.NoError(t, err) {
133+
var count int
134+
for rows.Next() {
135+
count++
136+
err := rows.Scan(
137+
&item.Int8,
138+
&item.Int16,
139+
&item.Int32,
140+
&item.Int64,
141+
&item.UInt8,
142+
&item.UInt16,
143+
&item.UInt32,
144+
&item.UInt64,
145+
&item.Float32,
146+
&item.Float64,
147+
&item.String,
148+
&item.FixedString,
149+
)
150+
if !assert.NoError(t, err) {
151+
return
152+
}
153+
}
154+
assert.Equal(t, int(10), count)
155+
}
156+
}
157+
}
158+
}
159+
}
160+
}
161+
}

clickhouse_send_query.go

+9-8
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,15 @@ func (ch *clickhouse) sendQuery(query string) error {
1919
if err := ch.encoder.String(""); err != nil {
2020
return err
2121
}
22-
23-
ch.encoder.Uvarint(1)
24-
ch.encoder.String("")
25-
ch.encoder.String("") //initial_query_id
26-
ch.encoder.String("[::ffff:127.0.0.1]:0")
27-
ch.encoder.Uvarint(1) // iface type TCP
28-
ch.encoder.String(hostname)
29-
ch.encoder.String(hostname)
22+
{ // client info
23+
ch.encoder.Uvarint(1)
24+
ch.encoder.String("")
25+
ch.encoder.String("") //initial_query_id
26+
ch.encoder.String("[::ffff:127.0.0.1]:0")
27+
ch.encoder.Uvarint(1) // iface type TCP
28+
ch.encoder.String(hostname)
29+
ch.encoder.String(hostname)
30+
}
3031
if err := ch.ClientInfo.Write(ch.encoder); err != nil {
3132
return err
3233
}

clickhouse_test.go

+27-27
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ func Test_InsertBatch(t *testing.T) {
256256
"RU", //fixedstring,
257257
time.Now(), //date
258258
time.Now(), //datetime
259-
clickhouse.Array([]string{"A", "B", "C"}),
259+
[]string{"A", "B", "C"},
260260
)
261261
if !assert.NoError(t, err) {
262262
return
@@ -497,43 +497,43 @@ func Test_ArrayT(t *testing.T) {
497497
if stmt, err := tx.Prepare(dml); assert.NoError(t, err) {
498498
for i := 1; i <= 10; i++ {
499499
_, err = stmt.Exec(
500-
clickhouse.Array([]int8{1, 2, 3}),
501-
clickhouse.Array([]int16{5, 6, 7}),
502-
clickhouse.Array([]int32{8, 9, 10}),
503-
clickhouse.Array([]int64{11, 12, 13}),
500+
[]int8{1, 2, 3},
501+
[]int16{5, 6, 7},
502+
[]int32{8, 9, 10},
503+
[]int64{11, 12, 13},
504504
clickhouse.Array([]uint8{14, 15, 16}),
505-
clickhouse.Array([]uint16{17, 18, 19}),
506-
clickhouse.Array([]uint32{20, 21, 22}),
507-
clickhouse.Array([]uint64{23, 24, 25}),
508-
clickhouse.Array([]float32{32.1, 32.2}),
509-
clickhouse.Array([]float64{64.1, 64.2}),
510-
clickhouse.Array([]string{fmt.Sprintf("A_%d", i), "B", "C"}),
505+
[]uint16{17, 18, 19},
506+
[]uint32{20, 21, 22},
507+
[]uint64{23, 24, 25},
508+
[]float32{32.1, 32.2},
509+
[]float64{64.1, 64.2},
510+
[]string{fmt.Sprintf("A_%d", i), "B", "C"},
511511
clickhouse.ArrayFixedString(2, []string{"RU", "EN", "DE"}),
512512
clickhouse.ArrayDate([]time.Time{time.Now(), time.Now()}),
513513
clickhouse.ArrayDateTime([]time.Time{time.Now(), time.Now()}),
514-
clickhouse.Array([]string{"a", "b"}),
515-
clickhouse.Array([]string{"c", "d"}),
514+
[]string{"a", "b"},
515+
[]string{"c", "d"},
516516
)
517517
if !assert.NoError(t, err) {
518518
return
519519
}
520520
_, err = stmt.Exec(
521-
clickhouse.Array([]int8{100, 101, 102, 103, 104, 105}),
522-
clickhouse.Array([]int16{200, 201}),
523-
clickhouse.Array([]int32{300, 301, 302, 303}),
524-
clickhouse.Array([]int64{400, 401, 402}),
521+
[]int8{100, 101, 102, 103, 104, 105},
522+
[]int16{200, 201},
523+
[]int32{300, 301, 302, 303},
524+
[]int64{400, 401, 402},
525525
clickhouse.Array([]uint8{250, 251, 252, 253, 254}),
526-
clickhouse.Array([]uint16{1000, 1001, 1002, 1003, 1004}),
527-
clickhouse.Array([]uint32{2001, 2002}),
528-
clickhouse.Array([]uint64{3000}),
529-
clickhouse.Array([]float32{1000.1, 100.1, 2000}),
530-
clickhouse.Array([]float64{640, 8, 650.9, 703.5, 800}),
531-
clickhouse.Array([]string{fmt.Sprintf("D_%d", i), "E", "F", "G"}),
526+
[]uint16{1000, 1001, 1002, 1003, 1004},
527+
[]uint32{2001, 2002},
528+
[]uint64{3000},
529+
[]float32{1000.1, 100.1, 2000},
530+
[]float64{640, 8, 650.9, 703.5, 800},
531+
[]string{fmt.Sprintf("D_%d", i), "E", "F", "G"},
532532
clickhouse.ArrayFixedString(2, []string{"UA", "GB"}),
533533
clickhouse.ArrayDate([]time.Time{time.Now(), time.Now(), time.Now(), time.Now()}),
534534
clickhouse.ArrayDateTime([]time.Time{time.Now(), time.Now()}),
535-
clickhouse.Array([]string{"a", "b"}),
536-
clickhouse.Array([]string{"c", "d"}),
535+
[]string{"a", "b"},
536+
[]string{"c", "d"},
537537
)
538538
if !assert.NoError(t, err) {
539539
return
@@ -811,10 +811,10 @@ func Test_Enum(t *testing.T) {
811811
if _, err := connect.Exec(ddl); assert.NoError(t, err) {
812812
if tx, err := connect.Begin(); assert.NoError(t, err) {
813813
if stmt, err := tx.Prepare(dml); assert.NoError(t, err) {
814-
if _, err := stmt.Exec("a", "c", clickhouse.Array([]string{"a", "b"}), clickhouse.Array([]string{"c", "d"})); !assert.NoError(t, err) {
814+
if _, err := stmt.Exec("a", "c", []string{"a", "b"}, []string{"c", "d"}); !assert.NoError(t, err) {
815815
return
816816
}
817-
if _, err := stmt.Exec("b", "d", clickhouse.Array([]string{"b", "a"}), clickhouse.Array([]string{"d", "c"})); !assert.NoError(t, err) {
817+
if _, err := stmt.Exec("b", "d", []string{"b", "a"}, []string{"d", "c"}); !assert.NoError(t, err) {
818818
return
819819
}
820820
}

examples/multiple.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func main() {
4949
"RU",
5050
10+i,
5151
100+i,
52-
clickhouse.Array([]int16{1, 2, 3}),
52+
[]int16{1, 2, 3},
5353
time.Now(),
5454
time.Now(),
5555
); err != nil {

examples/simple.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func main() {
4343
"RU",
4444
10+i,
4545
100+i,
46-
clickhouse.Array([]int16{1, 2, 3}),
46+
[]int16{1, 2, 3},
4747
time.Now(),
4848
time.Now(),
4949
); err != nil {

examples/sqlx.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func main() {
4242
"RU",
4343
10+i,
4444
100+i,
45-
clickhouse.Array([]int16{1, 2, 3}),
45+
[]int16{1, 2, 3},
4646
time.Now(),
4747
time.Now(),
4848
); err != nil {

0 commit comments

Comments
 (0)