aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/ClickHouse/clickhouse-go/lib/column/nullable.go
blob: 9dd88b546ad997b7190bcfe344ab7371e0d19442 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package column

import (
	"fmt"
	"reflect"
	"time"

	"github.com/ClickHouse/clickhouse-go/lib/binary"
)

type Nullable struct {
	base
	column Column
}

func (null *Nullable) ScanType() reflect.Type {
	return reflect.PtrTo(null.column.ScanType())
}

func (null *Nullable) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
	return null.column.Read(decoder, isNull)
}

func (null *Nullable) Write(encoder *binary.Encoder, v interface{}) error {
	return nil
}

func (null *Nullable) ReadNull(decoder *binary.Decoder, rows int) (_ []interface{}, err error) {
	var (
		isNull byte
		value  interface{}
		nulls  = make([]byte, rows)
		values = make([]interface{}, rows)
	)
	for i := 0; i < rows; i++ {
		if isNull, err = decoder.ReadByte(); err != nil {
			return nil, err
		}
		nulls[i] = isNull
	}
	for i, isNull := range nulls {
		switch value, err = null.column.Read(decoder, isNull != 0); true {
		case err != nil:
			return nil, err
		case isNull == 0:
			values[i] = value
		default:
			values[i] = nil
		}
	}
	return values, nil
}
func (null *Nullable) WriteNull(nulls, encoder *binary.Encoder, v interface{}) error {
	if isNil(v) {
		if _, err := nulls.Write([]byte{1}); err != nil {
			return err
		}
		return null.column.Write(encoder, null.column.defaultValue())
	}
	if _, err := nulls.Write([]byte{0}); err != nil {
		return err
	}
	return null.column.Write(encoder, v)
}

func parseNullable(name, chType string, timezone *time.Location) (*Nullable, error) {
	if len(chType) < 14 {
		return nil, fmt.Errorf("invalid Nullable column type: %s", chType)
	}
	column, err := Factory(name, chType[9:][:len(chType)-10], timezone)
	if err != nil {
		return nil, fmt.Errorf("Nullable(T): %v", err)
	}
	return &Nullable{
		base: base{
			name:   name,
			chType: chType,
		},
		column: column,
	}, nil
}

func (null *Nullable) GetColumn() Column {
	return null.column
}

func isNil(v interface{}) bool {
	if v == nil {
		return true
	}
	switch val := reflect.ValueOf(v); val.Type().Kind() {
	case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice:
		return val.IsNil()
	}
	return false
}