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

Commit 022a1ec

Browse files
authored
Merge pull request ClickHouse#286 from veqryn/master
Fixes: invalid Enum value: 0 for valid null records
2 parents ccf6e1f + 3e3d029 commit 022a1ec

25 files changed

+103
-60
lines changed

lib/column/array.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ type Array struct {
1616
column Column
1717
}
1818

19-
func (array *Array) Read(decoder *binary.Decoder) (interface{}, error) {
19+
func (array *Array) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
2020
return nil, fmt.Errorf("do not use Read method for Array(T) column")
2121
}
2222

@@ -69,7 +69,7 @@ func (array *Array) read(decoder *binary.Decoder, offsets [][]uint64, index uint
6969
err error
7070
)
7171
if level == array.depth-1 {
72-
value, err = array.column.Read(decoder)
72+
value, err = array.column.Read(decoder, false)
7373
} else {
7474
value, err = array.read(decoder, offsets, i, level+1)
7575
}

lib/column/column.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ type Column interface {
1313
Name() string
1414
CHType() string
1515
ScanType() reflect.Type
16-
Read(*binary.Decoder) (interface{}, error)
16+
Read(*binary.Decoder, bool) (interface{}, error)
1717
Write(*binary.Encoder, interface{}) error
1818
defaultValue() interface{}
1919
Depth() int

lib/column/column_test.go

Lines changed: 75 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func Test_Column_Int8(t *testing.T) {
2222
if column, err := columns.Factory("column_name", "Int8", time.Local); assert.NoError(t, err) {
2323
for i := -128; i <= 127; i++ {
2424
if err := column.Write(encoder, int8(i)); assert.NoError(t, err) {
25-
if v, err := column.Read(decoder); assert.NoError(t, err) {
25+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
2626
assert.Equal(t, int8(i), v)
2727
}
2828
}
@@ -47,7 +47,7 @@ func Test_Column_Int16(t *testing.T) {
4747
if column, err := columns.Factory("column_name", "Int16", time.Local); assert.NoError(t, err) {
4848
for i := -32768; i <= 32767; i++ {
4949
if err := column.Write(encoder, int16(i)); assert.NoError(t, err) {
50-
if v, err := column.Read(decoder); assert.NoError(t, err) {
50+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
5151
assert.Equal(t, int16(i), v)
5252
}
5353
}
@@ -72,7 +72,7 @@ func Test_Column_Int32(t *testing.T) {
7272
if column, err := columns.Factory("column_name", "Int32", time.Local); assert.NoError(t, err) {
7373
for i := -2147483648; i <= 2147483648; i += 100000 {
7474
if err := column.Write(encoder, int32(i)); assert.NoError(t, err) {
75-
if v, err := column.Read(decoder); assert.NoError(t, err) {
75+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
7676
assert.Equal(t, int32(i), v)
7777
}
7878
}
@@ -97,7 +97,7 @@ func Test_Column_Int64(t *testing.T) {
9797
if column, err := columns.Factory("column_name", "Int64", time.Local); assert.NoError(t, err) {
9898
for i := -2147483648; i <= 2147483648*2; i += 100000 {
9999
if err := column.Write(encoder, int64(i)); assert.NoError(t, err) {
100-
if v, err := column.Read(decoder); assert.NoError(t, err) {
100+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
101101
assert.Equal(t, int64(i), v)
102102
}
103103
}
@@ -122,7 +122,7 @@ func Test_Column_UInt8(t *testing.T) {
122122
if column, err := columns.Factory("column_name", "UInt8", time.Local); assert.NoError(t, err) {
123123
for i := 0; i <= 255; i++ {
124124
if err := column.Write(encoder, uint8(i)); assert.NoError(t, err) {
125-
if v, err := column.Read(decoder); assert.NoError(t, err) {
125+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
126126
assert.Equal(t, uint8(i), v)
127127
}
128128
}
@@ -147,7 +147,7 @@ func Test_Column_UInt16(t *testing.T) {
147147
if column, err := columns.Factory("column_name", "UInt16", time.Local); assert.NoError(t, err) {
148148
for i := 0; i <= 65535; i++ {
149149
if err := column.Write(encoder, uint16(i)); assert.NoError(t, err) {
150-
if v, err := column.Read(decoder); assert.NoError(t, err) {
150+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
151151
assert.Equal(t, uint16(i), v)
152152
}
153153
}
@@ -172,7 +172,7 @@ func Test_Column_UInt32(t *testing.T) {
172172
if column, err := columns.Factory("column_name", "UInt32", time.Local); assert.NoError(t, err) {
173173
for i := 0; i <= 4294967295; i += 100000 {
174174
if err := column.Write(encoder, uint32(i)); assert.NoError(t, err) {
175-
if v, err := column.Read(decoder); assert.NoError(t, err) {
175+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
176176
assert.Equal(t, uint32(i), v)
177177
}
178178
}
@@ -197,7 +197,7 @@ func Test_Column_UInt64(t *testing.T) {
197197
if column, err := columns.Factory("column_name", "UInt64", time.Local); assert.NoError(t, err) {
198198
for i := 0; i <= 4294967295*2; i += 100000 {
199199
if err := column.Write(encoder, uint64(i)); assert.NoError(t, err) {
200-
if v, err := column.Read(decoder); assert.NoError(t, err) {
200+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
201201
assert.Equal(t, uint64(i), v)
202202
}
203203
}
@@ -222,7 +222,7 @@ func Test_Column_Float32(t *testing.T) {
222222
if column, err := columns.Factory("column_name", "Float32", time.Local); assert.NoError(t, err) {
223223
for i := -2147483648; i <= 2147483648; i += 100000 {
224224
if err := column.Write(encoder, float32(i)); assert.NoError(t, err) {
225-
if v, err := column.Read(decoder); assert.NoError(t, err) {
225+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
226226
assert.Equal(t, float32(i), v)
227227
}
228228
}
@@ -247,7 +247,7 @@ func Test_Column_Float64(t *testing.T) {
247247
if column, err := columns.Factory("column_name", "Float64", time.Local); assert.NoError(t, err) {
248248
for i := -2147483648; i <= 2147483648*2; i += 100000 {
249249
if err := column.Write(encoder, float64(i)); assert.NoError(t, err) {
250-
if v, err := column.Read(decoder); assert.NoError(t, err) {
250+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
251251
assert.Equal(t, float64(i), v)
252252
}
253253
}
@@ -275,22 +275,22 @@ func Test_Column_String(t *testing.T) {
275275
)
276276
if column, err := columns.Factory("column_name", "String", time.Local); assert.NoError(t, err) {
277277
if err := column.Write(encoder, str); assert.NoError(t, err) {
278-
if v, err := column.Read(decoder); assert.NoError(t, err) {
278+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
279279
assert.Equal(t, str, v)
280280
}
281281
}
282282
if err := column.Write(encoder, strP); assert.NoError(t, err) {
283-
if v, err := column.Read(decoder); assert.NoError(t, err) {
283+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
284284
assert.Equal(t, str, v)
285285
}
286286
}
287287
if err := column.Write(encoder, b); assert.NoError(t, err) {
288-
if v, err := column.Read(decoder); assert.NoError(t, err) {
288+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
289289
assert.Equal(t, str, v)
290290
}
291291
}
292292
if err := column.Write(encoder, bp); assert.NoError(t, err) {
293-
if v, err := column.Read(decoder); assert.NoError(t, err) {
293+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
294294
assert.Equal(t, str, v)
295295
}
296296
}
@@ -314,7 +314,7 @@ func Test_Column_FixedString(t *testing.T) {
314314
)
315315
if column, err := columns.Factory("column_name", "FixedString(14)", time.Local); assert.NoError(t, err) {
316316
if err := column.Write(encoder, str); assert.NoError(t, err) {
317-
if v, err := column.Read(decoder); assert.NoError(t, err) {
317+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
318318
assert.Equal(t, str, v)
319319
}
320320
}
@@ -337,13 +337,13 @@ func Test_Column_Enum8(t *testing.T) {
337337
)
338338
if column, err := columns.Factory("column_name", "Enum8('A'=1,'B'=2,'C'=3)", time.Local); assert.NoError(t, err) {
339339
if err := column.Write(encoder, "B"); assert.NoError(t, err) {
340-
if v, err := column.Read(decoder); assert.NoError(t, err) {
340+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
341341
assert.Equal(t, "B", v)
342342
}
343343
}
344344
if err := column.Write(encoder, int16(3)); assert.Error(t, err) {
345345
if err := column.Write(encoder, int8(3)); assert.NoError(t, err) {
346-
if v, err := column.Read(decoder); assert.NoError(t, err) {
346+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
347347
assert.Equal(t, "C", v)
348348
}
349349
}
@@ -367,13 +367,13 @@ func Test_Column_Enum16(t *testing.T) {
367367
)
368368
if column, err := columns.Factory("column_name", "Enum16('A'=1,'B'=2,'C'=3)", time.Local); assert.NoError(t, err) {
369369
if err := column.Write(encoder, "B"); assert.NoError(t, err) {
370-
if v, err := column.Read(decoder); assert.NoError(t, err) {
370+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
371371
assert.Equal(t, "B", v)
372372
}
373373
}
374374
if err := column.Write(encoder, int8(3)); assert.Error(t, err) {
375375
if err := column.Write(encoder, int16(3)); assert.NoError(t, err) {
376-
if v, err := column.Read(decoder); assert.NoError(t, err) {
376+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
377377
assert.Equal(t, "C", v)
378378
}
379379
}
@@ -404,21 +404,21 @@ func Test_Column_Date(t *testing.T) {
404404

405405
// time.Time type
406406
if err := column.Write(encoder, todayHour); assert.NoError(t, err) {
407-
if v, err := column.Read(decoder); assert.NoError(t, err) {
407+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
408408
assert.Equal(t, today, v)
409409
}
410410
}
411411

412412
// int64 type
413413
if err := column.Write(encoder, todayHour.Unix()); assert.NoError(t, err) {
414-
if v, err := column.Read(decoder); assert.NoError(t, err) {
414+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
415415
assert.Equal(t, today, v)
416416
}
417417
}
418418

419419
// string type
420420
if err := column.Write(encoder, todayHour.Format("2006-01-02")); assert.NoError(t, err) {
421-
if v, err := column.Read(decoder); assert.NoError(t, err) {
421+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
422422
assert.Equal(t, today, v)
423423
}
424424
}
@@ -445,12 +445,12 @@ func Test_Column_DateTime(t *testing.T) {
445445
)
446446
if column, err := columns.Factory("column_name", "DateTime", time.Local); assert.NoError(t, err) {
447447
if err := column.Write(encoder, timeNow); assert.NoError(t, err) {
448-
if v, err := column.Read(decoder); assert.NoError(t, err) {
448+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
449449
assert.Equal(t, timeNow, v)
450450
}
451451
}
452452
if err := column.Write(encoder, timeNow.In(time.UTC).Format("2006-01-02 15:04:05")); assert.NoError(t, err) {
453-
if v, err := column.Read(decoder); assert.NoError(t, err) {
453+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
454454
assert.Equal(t, timeNow, v)
455455
}
456456
}
@@ -474,12 +474,12 @@ func Test_Column_DateTime64(t *testing.T) {
474474
)
475475
if column, err := columns.Factory("column_name", "DateTime64(6)", time.UTC); assert.NoError(t, err) {
476476
if err := column.Write(encoder, timeNow); assert.NoError(t, err) {
477-
if v, err := column.Read(decoder); assert.NoError(t, err) {
477+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
478478
assert.Equal(t, timeNow, v)
479479
}
480480
}
481481
if err := column.Write(encoder, timeNow.In(time.UTC).Format("2006-01-02 15:04:05.999999")); assert.NoError(t, err) {
482-
if v, err := column.Read(decoder); assert.NoError(t, err) {
482+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
483483
assert.Equal(t, timeNow, v)
484484
}
485485
}
@@ -513,12 +513,12 @@ func Test_Column_DateTimeWithTZ(t *testing.T) {
513513
)
514514
if column, err := columns.Factory("column_name", `DateTime("UTC")`, time.Local); assert.NoError(t, err) {
515515
if err := column.Write(encoder, timeNow); assert.NoError(t, err) {
516-
if v, err := column.Read(decoder); assert.NoError(t, err) {
516+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
517517
assert.Equal(t, timeNow, v)
518518
}
519519
}
520520
if err := column.Write(encoder, timeNow.In(time.UTC).Format("2006-01-02 15:04:05")); assert.NoError(t, err) {
521-
if v, err := column.Read(decoder); assert.NoError(t, err) {
521+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
522522
assert.Equal(t, timeNow, v)
523523
}
524524
}
@@ -549,7 +549,7 @@ func Test_Column_UUID(t *testing.T) {
549549
"798c4344-de6c-4c02-95ba-fea4f7d5fafd",
550550
} {
551551
if err := column.Write(encoder, uuid); assert.NoError(t, err) {
552-
if v, err := column.Read(decoder); assert.NoError(t, err) {
552+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
553553
assert.Equal(t, uuid, v)
554554
}
555555
}
@@ -579,7 +579,7 @@ func Test_Column_IP(t *testing.T) {
579579
"127.0.0.1",
580580
} {
581581
if err := column.Write(encoder, ip); assert.NoError(t, err) {
582-
if v, err := column.Read(decoder); assert.NoError(t, err) {
582+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
583583
assert.Equal(t, net.ParseIP(ip), v)
584584
}
585585
}
@@ -602,7 +602,7 @@ func Test_Column_IP(t *testing.T) {
602602
"2001:0db8:0000:0000:0000:ff00:0042:8329",
603603
} {
604604
if err := column.Write(encoder, ip); assert.NoError(t, err) {
605-
if v, err := column.Read(decoder); assert.NoError(t, err) {
605+
if v, err := column.Read(decoder, false); assert.NoError(t, err) {
606606
assert.Equal(t, net.ParseIP(ip), v)
607607
}
608608
}
@@ -651,7 +651,7 @@ func Test_Column_Decimal64(t *testing.T) {
651651
}
652652

653653
if err := columnBase.Write(encoder, float64(1123.12345)); assert.NoError(t, err) {
654-
if v, err := columnBase.Read(decoder); assert.NoError(t, err) {
654+
if v, err := columnBase.Read(decoder, false); assert.NoError(t, err) {
655655
assert.Equal(t, int64(112312345), v)
656656
}
657657
}
@@ -693,3 +693,46 @@ func Test_Column_NullableDecimal64(t *testing.T) {
693693
}
694694
}
695695
}
696+
697+
func Test_Column_NullableEnum8(t *testing.T) {
698+
var (
699+
buf bytes.Buffer
700+
encoder = binary.NewEncoder(&buf)
701+
decoder = binary.NewDecoder(&buf)
702+
)
703+
if columnBase, err := columns.Factory("column_name", "Nullable(Enum8('A'=1,'B'=2,'C'=3))", time.Local); assert.NoError(t, err) {
704+
705+
nullableCol, ok := columnBase.(*columns.Nullable)
706+
if assert.True(t, ok) {
707+
enumCol := nullableCol.GetColumn().(*columns.Enum)
708+
if assert.Equal(t, "column_name", enumCol.Name()) && assert.Equal(t, "Enum8('A'=1,'B'=2,'C'=3)", enumCol.CHType()) {
709+
assert.Equal(t, reflect.String, enumCol.ScanType().Kind())
710+
}
711+
}
712+
713+
if err = nullableCol.WriteNull(encoder, encoder, "B"); assert.NoError(t, err) {
714+
if v, err := nullableCol.ReadNull(decoder, 1); assert.NoError(t, err) {
715+
assert.Equal(t, "B", v[0])
716+
}
717+
}
718+
719+
if err = nullableCol.WriteNull(encoder, encoder, nil); assert.NoError(t, err) {
720+
if v, err := nullableCol.ReadNull(decoder, 1); assert.NoError(t, err) {
721+
assert.Nil(t, v[0])
722+
}
723+
}
724+
725+
// Clickhouse can return a null result with zero value, even if the enum doesn't start at 0
726+
if _, err = encoder.Write([]byte{1}); assert.NoError(t, err) {
727+
if err = encoder.Int8(0); assert.NoError(t, err) {
728+
if v, err := nullableCol.ReadNull(decoder, 1); assert.NoError(t, err) {
729+
assert.Nil(t, v[0])
730+
}
731+
}
732+
}
733+
734+
if assert.Equal(t, "column_name", columnBase.Name()) && assert.Equal(t, "Nullable(Enum8('A'=1,'B'=2,'C'=3))", columnBase.CHType()) {
735+
assert.Equal(t, reflect.String, columnBase.ScanType().Kind())
736+
}
737+
}
738+
}

lib/column/date.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ type Date struct {
1212
offset int64
1313
}
1414

15-
func (dt *Date) Read(decoder *binary.Decoder) (interface{}, error) {
15+
func (dt *Date) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
1616
sec, err := decoder.Int16()
1717
if err != nil {
1818
return nil, err

lib/column/datetime.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ type DateTime struct {
1111
Timezone *time.Location
1212
}
1313

14-
func (dt *DateTime) Read(decoder *binary.Decoder) (interface{}, error) {
14+
func (dt *DateTime) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
1515
sec, err := decoder.Int32()
1616
if err != nil {
1717
return nil, err

lib/column/datetime64.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ type DateTime64 struct {
1414
Timezone *time.Location
1515
}
1616

17-
func (dt *DateTime64) Read(decoder *binary.Decoder) (interface{}, error) {
17+
func (dt *DateTime64) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
1818
value, err := decoder.Int64()
1919
if err != nil {
2020
return nil, err

lib/column/decimal.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ type Decimal struct {
2727
scale int
2828
}
2929

30-
func (d *Decimal) Read(decoder *binary.Decoder) (interface{}, error) {
30+
func (d *Decimal) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
3131
switch d.nobits {
3232
case 32:
3333
return decoder.Int32()

lib/column/enum.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ type Enum struct {
1515
baseType interface{}
1616
}
1717

18-
func (enum *Enum) Read(decoder *binary.Decoder) (interface{}, error) {
18+
func (enum *Enum) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
1919
var (
2020
err error
2121
ident interface{}
@@ -30,7 +30,7 @@ func (enum *Enum) Read(decoder *binary.Decoder) (interface{}, error) {
3030
return nil, err
3131
}
3232
}
33-
if ident, found := enum.vi[ident]; found {
33+
if ident, found := enum.vi[ident]; found || isNull {
3434
return ident, nil
3535
}
3636
return nil, fmt.Errorf("invalid Enum value: %v", ident)

0 commit comments

Comments
 (0)