111 lines
2.2 KiB
Go
111 lines
2.2 KiB
Go
package column
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
|
"reflect"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
type Tuple struct {
|
|
base
|
|
columns []Column
|
|
}
|
|
|
|
func (tuple *Tuple) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
|
|
return nil, fmt.Errorf("do not use Read method for Tuple(T) column")
|
|
}
|
|
|
|
func (tuple *Tuple) ReadTuple(decoder *binary.Decoder, rows int) ([]interface{}, error) {
|
|
var values = make([][]interface{}, rows)
|
|
|
|
for _, c := range tuple.columns {
|
|
|
|
switch column := c.(type) {
|
|
case *Array:
|
|
cols, err := column.ReadArray(decoder, rows)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for i := 0; i < rows; i++ {
|
|
values[i] = append(values[i], cols[i])
|
|
}
|
|
|
|
case *Nullable:
|
|
cols, err := column.ReadNull(decoder, rows)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for i := 0; i < rows; i++ {
|
|
values[i] = append(values[i], cols[i])
|
|
}
|
|
|
|
case *Tuple:
|
|
cols, err := column.ReadTuple(decoder, rows)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for i := 0; i < rows; i++ {
|
|
values[i] = append(values[i], cols[i])
|
|
}
|
|
|
|
default:
|
|
for i := 0; i < rows; i++ {
|
|
value, err := c.Read(decoder, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
values[i] = append(values[i], value)
|
|
}
|
|
}
|
|
}
|
|
|
|
var ret = make([]interface{}, rows)
|
|
for i := range values {
|
|
ret[i] = values[i]
|
|
}
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
func (tuple *Tuple) Write(encoder *binary.Encoder, v interface{}) (err error) {
|
|
return fmt.Errorf("unsupported Tuple(T) type [%T]", v)
|
|
}
|
|
|
|
func parseTuple(name, chType string, timezone *time.Location) (Column, error) {
|
|
var columnType = chType
|
|
|
|
chType = chType[6 : len(chType)-1]
|
|
var types []string
|
|
var last, diff int
|
|
for i, b := range chType + "," {
|
|
if b == '(' {
|
|
diff++
|
|
} else if b == ')' {
|
|
diff--
|
|
} else if b == ',' && diff == 0 {
|
|
types = append(types, chType[last:i])
|
|
last = i + 2
|
|
}
|
|
}
|
|
|
|
var columns = make([]Column, 0, len(types))
|
|
for i, chType := range types {
|
|
column, err := Factory(name+"."+strconv.Itoa(i+1), chType, timezone)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%s: %v", chType, err)
|
|
}
|
|
columns = append(columns, column)
|
|
}
|
|
|
|
return &Tuple{
|
|
base: base{
|
|
name: name,
|
|
chType: columnType,
|
|
valueOf: reflect.ValueOf([]interface{}{}),
|
|
},
|
|
columns: columns,
|
|
}, nil
|
|
}
|