Skip to content
This repository was archived by the owner on Feb 26, 2024. It is now read-only.

Commit ec7b6da

Browse files
committed
Support deserialization of multidimensional arrays
1 parent bb163f6 commit ec7b6da

File tree

2 files changed

+110
-49
lines changed

2 files changed

+110
-49
lines changed

clickhouse_test.go

Lines changed: 66 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,57 +1255,89 @@ func TestArrayArrayT(t *testing.T) {
12551255
const (
12561256
ddl = `
12571257
CREATE TABLE clickhouse_test_array_array_t (
1258-
String Array(Array(String))
1259-
, String2 Array(String)
1260-
, Int32 Array(Int32)
1258+
String1 Array(Array(String)),
1259+
String2 Array(Array(Array(String))),
1260+
Int32 Array(Array(Int32))
12611261
) Engine=Memory
12621262
`
12631263
dml = `
1264-
INSERT INTO clickhouse_test_array_array_t (String, String2, Int32) VALUES (?)
1264+
INSERT INTO clickhouse_test_array_array_t (String1, String2, Int32) VALUES (?)
12651265
`
12661266
query = `
12671267
SELECT
1268-
String
1268+
String1,
1269+
String2,
1270+
Int32
12691271
FROM clickhouse_test_array_array_t
12701272
`
12711273
)
1274+
1275+
items := []struct {
1276+
String1, String2, Int32 interface{}
1277+
}{
1278+
{
1279+
[][]string{
1280+
[]string{"A"},
1281+
[]string{"BC"},
1282+
[]string{"DEF"},
1283+
},
1284+
[][][]string{
1285+
[][]string{
1286+
[]string{"X"},
1287+
[]string{"Y"},
1288+
},
1289+
[][]string{
1290+
[]string{"ZZ"},
1291+
},
1292+
},
1293+
[][]int32{
1294+
[]int32{1},
1295+
[]int32{2, 3},
1296+
},
1297+
},
1298+
{
1299+
[][][]byte{
1300+
[][]byte{[]byte("AA")},
1301+
[][]byte{[]byte("BB")},
1302+
[][]byte{[]byte("C4C")},
1303+
},
1304+
[][][][]byte{
1305+
[][][]byte{
1306+
[][]byte{[]byte("XX"), []byte("YY")},
1307+
},
1308+
},
1309+
[][]int32{
1310+
[]int32{4, 5, 6},
1311+
},
1312+
},
1313+
}
1314+
12721315
if connect, err := sql.Open("clickhouse", "tcp://127.0.0.1:9000?debug=true"); assert.NoError(t, err) && assert.NoError(t, connect.Ping()) {
12731316
if _, err := connect.Exec("DROP TABLE IF EXISTS clickhouse_test_array_array_t"); assert.NoError(t, err) {
12741317
if _, err := connect.Exec(ddl); assert.NoError(t, err) {
12751318
if tx, err := connect.Begin(); assert.NoError(t, err) {
12761319
if stmt, err := tx.Prepare(dml); assert.NoError(t, err) {
1277-
_, err = stmt.Exec([][]string{[]string{"A"}, []string{"B"}, []string{"C"}}, []string{"X", "Y"}, []int32{1, 2, 3})
1278-
if !assert.NoError(t, err) {
1279-
return
1280-
}
1281-
_, err = stmt.Exec([][]string{[]string{"AA"}, []string{"BB"}, []string{"C4C"}}, []string{"XX", "YY"}, []int32{4, 5, 6})
1282-
if !assert.NoError(t, err) {
1283-
return
1284-
}
1285-
_, err = stmt.Exec(
1286-
[][][]byte{
1287-
[][]byte{[]byte("AA")},
1288-
[][]byte{[]byte("BB")},
1289-
[][]byte{[]byte("C4C")},
1290-
},
1291-
[][]byte{[]byte("XX"), []byte("YY")},
1292-
[]int32{4, 5, 6},
1293-
)
1294-
if !assert.NoError(t, err) {
1295-
return
1320+
for _, item := range items {
1321+
_, err = stmt.Exec(item.String1, item.String2, item.Int32)
1322+
if !assert.NoError(t, err) {
1323+
return
1324+
}
12961325
}
1297-
} else {
1298-
return
1326+
12991327
}
13001328
if assert.NoError(t, tx.Commit()) {
1301-
/* var value []string
1302-
if err := connect.QueryRow(query).Scan(&value); assert.NoError(t, err) {
1303-
if !assert.NoError(t, err) {
1304-
return
1305-
}
1306-
}
1307-
assert.Equal(t, []string{"A", "C"}, value)
1308-
*/
1329+
var result struct {
1330+
String1 [][]string
1331+
String2 [][][]string
1332+
Int32 [][]int32
1333+
}
1334+
1335+
row := connect.QueryRow(query)
1336+
if err := row.Scan(&result.String1, &result.String2, &result.Int32); assert.NoError(t, err) {
1337+
assert.Equal(t, items[0].String1, result.String1)
1338+
assert.Equal(t, items[0].String2, result.String2)
1339+
assert.Equal(t, items[0].Int32, result.Int32)
1340+
}
13091341
}
13101342
}
13111343
}

lib/column/array.go

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,32 +26,53 @@ func (array *Array) Write(encoder *binary.Encoder, v interface{}) error {
2626

2727
func (array *Array) ReadArray(decoder *binary.Decoder, rows int) (_ []interface{}, err error) {
2828
var (
29+
offsets = make([][]uint64, array.depth)
2930
values = make([]interface{}, rows)
30-
offsets = make([]uint64, rows)
3131
)
32-
for i := 0; i < rows; i++ {
33-
offset, err := decoder.UInt64()
34-
if err != nil {
35-
return nil, err
32+
33+
// Read offsets
34+
lastOffset := uint64(rows)
35+
for i := 0; i < array.depth; i++ {
36+
offset := make([]uint64, lastOffset)
37+
for j := uint64(0); j < lastOffset; j++ {
38+
if offset[j], err = decoder.UInt64(); err != nil {
39+
return nil, err
40+
}
3641
}
3742
offsets[i] = offset
38-
}
39-
for n, offset := range offsets {
40-
ln := offset
41-
if n != 0 {
42-
ln = ln - offsets[n-1]
43+
lastOffset = 0
44+
if len(offset) > 0 {
45+
lastOffset = offset[len(offset)-1]
4346
}
44-
if values[n], err = array.read(decoder, int(ln)); err != nil {
47+
}
48+
49+
// Read values
50+
for i := 0; i < rows; i++ {
51+
if values[i], err = array.read(decoder, offsets, uint64(i), 0); err != nil {
4552
return nil, err
4653
}
4754
}
4855
return values, nil
4956
}
5057

51-
func (array *Array) read(decoder *binary.Decoder, ln int) (interface{}, error) {
52-
slice := reflect.MakeSlice(array.valueOf.Type(), 0, ln)
53-
for i := 0; i < ln; i++ {
54-
value, err := array.column.Read(decoder)
58+
func (array *Array) read(decoder *binary.Decoder, offsets [][]uint64, index uint64, level int) (interface{}, error) {
59+
end := offsets[level][index]
60+
start := uint64(0)
61+
if index > 0 {
62+
start = offsets[level][index-1]
63+
}
64+
65+
slice := reflect.MakeSlice(array.arrayType(level), 0, int(end-start))
66+
for i := start; i < end; i++ {
67+
var (
68+
value interface{}
69+
err error
70+
)
71+
if level == array.depth-1 {
72+
value, err = array.column.Read(decoder)
73+
} else {
74+
value, err = array.read(decoder, offsets, i, level+1)
75+
}
5576
if err != nil {
5677
return nil, err
5778
}
@@ -60,6 +81,14 @@ func (array *Array) read(decoder *binary.Decoder, ln int) (interface{}, error) {
6081
return slice.Interface(), nil
6182
}
6283

84+
func (array *Array) arrayType(level int) reflect.Type {
85+
t := array.column.ScanType()
86+
for i := 0; i < array.depth-level; i++ {
87+
t = reflect.SliceOf(t)
88+
}
89+
return t
90+
}
91+
6392
func (array *Array) Depth() int {
6493
return array.depth
6594
}

0 commit comments

Comments
 (0)