| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 |
- package column
- import (
- b "encoding/binary"
- "errors"
- "fmt"
- "math"
- "reflect"
- "strconv"
- "strings"
- "github.com/ClickHouse/clickhouse-go/lib/binary"
- )
- // Table of powers of 10 for fast casting from floating types to decimal type
- // representations.
- var factors10 = []float64{
- 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13,
- 1e14, 1e15, 1e16, 1e17, 1e18,
- }
- // Decimal represents Decimal(P, S) ClickHouse. Decimal is represented as
- // integral. Also floating-point types are supported for query parameters.
- //
- // Since there is no support for int128 in Golang, decimals with precision 19
- // through 38 are represented as 16 little-endian bytes.
- type Decimal struct {
- base
- nobits int // its domain is {32, 64}
- precision int
- scale int
- }
- func (d *Decimal) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
- switch d.nobits {
- case 32:
- return decoder.Int32()
- case 64:
- return decoder.Int64()
- case 128:
- return decoder.Decimal128()
- default:
- return nil, errors.New("unachievable execution path")
- }
- }
- func (d *Decimal) Write(encoder *binary.Encoder, v interface{}) error {
- switch d.nobits {
- case 32:
- return d.write32(encoder, v)
- case 64:
- return d.write64(encoder, v)
- case 128:
- return d.write128(encoder, v)
- default:
- return errors.New("unachievable execution path")
- }
- }
- func (d *Decimal) float2int32(floating float64) int32 {
- fixed := int32(floating * factors10[d.scale])
- return fixed
- }
- func (d *Decimal) float2int64(floating float64) int64 {
- fixed := int64(floating * factors10[d.scale])
- return fixed
- }
- func (d *Decimal) write32(encoder *binary.Encoder, v interface{}) error {
- switch v := v.(type) {
- case int8:
- return encoder.Int32(int32(v))
- case int16:
- return encoder.Int32(int32(v))
- case int32:
- return encoder.Int32(int32(v))
- case int64:
- if v > math.MaxInt32 || v < math.MinInt32 {
- return errors.New("overflow when narrowing type conversion from int64 to int32")
- }
- return encoder.Int32(int32(v))
- case uint8:
- return encoder.Int32(int32(v))
- case uint16:
- return encoder.Int32(int32(v))
- case uint32:
- if v > math.MaxInt32 {
- return errors.New("overflow when narrowing type conversion from uint32 to int32")
- }
- return encoder.Int32(int32(v))
- case uint64:
- if v > math.MaxInt32 {
- return errors.New("overflow when narrowing type conversion from uint64 to int32")
- }
- return encoder.Int32(int32(v))
- case float32:
- fixed := d.float2int32(float64(v))
- return encoder.Int32(fixed)
- case float64:
- fixed := d.float2int32(float64(v))
- return encoder.Int32(fixed)
- // this relies on Nullable never sending nil values through
- case *int8:
- return encoder.Int32(int32(*v))
- case *int16:
- return encoder.Int32(int32(*v))
- case *int32:
- return encoder.Int32(int32(*v))
- case *int64:
- if *v > math.MaxInt32 || *v < math.MinInt32 {
- return errors.New("overflow when narrowing type conversion from int64 to int32")
- }
- return encoder.Int32(int32(*v))
- case *uint8:
- return encoder.Int32(int32(*v))
- case *uint16:
- return encoder.Int32(int32(*v))
- case *uint32:
- if *v > math.MaxInt32 {
- return errors.New("overflow when narrowing type conversion from uint34 to int32")
- }
- return encoder.Int32(int32(*v))
- case *uint64:
- if *v > math.MaxInt32 {
- return errors.New("overflow when narrowing type conversion from uint64 to int32")
- }
- return encoder.Int32(int32(*v))
- case *float32:
- fixed := d.float2int32(float64(*v))
- return encoder.Int32(fixed)
- case *float64:
- fixed := d.float2int32(float64(*v))
- return encoder.Int32(fixed)
- }
- return &ErrUnexpectedType{
- T: v,
- Column: d,
- }
- }
- func (d *Decimal) write64(encoder *binary.Encoder, v interface{}) error {
- switch v := v.(type) {
- case int:
- return encoder.Int64(int64(v))
- case int8:
- return encoder.Int64(int64(v))
- case int16:
- return encoder.Int64(int64(v))
- case int32:
- return encoder.Int64(int64(v))
- case int64:
- return encoder.Int64(int64(v))
- case uint8:
- return encoder.Int64(int64(v))
- case uint16:
- return encoder.Int64(int64(v))
- case uint32:
- return encoder.Int64(int64(v))
- case uint64:
- if v > math.MaxInt64 {
- return errors.New("overflow when narrowing type conversion from uint64 to int64")
- }
- return encoder.Int64(int64(v))
- case float32:
- fixed := d.float2int64(float64(v))
- return encoder.Int64(fixed)
- case float64:
- fixed := d.float2int64(float64(v))
- return encoder.Int64(fixed)
- // this relies on Nullable never sending nil values through
- case *int:
- return encoder.Int64(int64(*v))
- case *int8:
- return encoder.Int64(int64(*v))
- case *int16:
- return encoder.Int64(int64(*v))
- case *int32:
- return encoder.Int64(int64(*v))
- case *int64:
- return encoder.Int64(int64(*v))
- case *uint8:
- return encoder.Int64(int64(*v))
- case *uint16:
- return encoder.Int64(int64(*v))
- case *uint32:
- return encoder.Int64(int64(*v))
- case *uint64:
- if *v > math.MaxInt64 {
- return errors.New("overflow when narrowing type conversion from uint64 to int64")
- }
- return encoder.Int64(int64(*v))
- case *float32:
- fixed := d.float2int64(float64(*v))
- return encoder.Int64(fixed)
- case *float64:
- fixed := d.float2int64(float64(*v))
- return encoder.Int64(fixed)
- }
- return &ErrUnexpectedType{
- T: v,
- Column: d,
- }
- }
- // Turns an int64 into 16 little-endian bytes.
- func int64ToDecimal128(v int64) []byte {
- bytes := make([]byte, 16)
- b.LittleEndian.PutUint64(bytes[:8], uint64(v))
- sign := 0
- if v < 0 {
- sign = -1
- }
- b.LittleEndian.PutUint64(bytes[8:], uint64(sign))
- return bytes
- }
- // Turns a uint64 into 16 little-endian bytes.
- func uint64ToDecimal128(v uint64) []byte {
- bytes := make([]byte, 16)
- b.LittleEndian.PutUint64(bytes[:8], uint64(v))
- return bytes
- }
- func (d *Decimal) write128(encoder *binary.Encoder, v interface{}) error {
- switch v := v.(type) {
- case int:
- return encoder.Decimal128(int64ToDecimal128(int64(v)))
- case int8:
- return encoder.Decimal128(int64ToDecimal128(int64(v)))
- case int16:
- return encoder.Decimal128(int64ToDecimal128(int64(v)))
- case int32:
- return encoder.Decimal128(int64ToDecimal128(int64(v)))
- case int64:
- return encoder.Decimal128(int64ToDecimal128(v))
- case uint8:
- return encoder.Decimal128(uint64ToDecimal128(uint64(v)))
- case uint16:
- return encoder.Decimal128(uint64ToDecimal128(uint64(v)))
- case uint32:
- return encoder.Decimal128(uint64ToDecimal128(uint64(v)))
- case uint64:
- return encoder.Decimal128(uint64ToDecimal128(v))
- case float32:
- fixed := d.float2int64(float64(v))
- return encoder.Decimal128(int64ToDecimal128(fixed))
- case float64:
- fixed := d.float2int64(float64(v))
- return encoder.Decimal128(int64ToDecimal128(fixed))
- case []byte:
- if len(v) != 16 {
- return errors.New("expected 16 bytes")
- }
- return encoder.Decimal128(v)
- // this relies on Nullable never sending nil values through
- case *int:
- return encoder.Decimal128(int64ToDecimal128(int64(*v)))
- case *int8:
- return encoder.Decimal128(int64ToDecimal128(int64(*v)))
- case *int16:
- return encoder.Decimal128(int64ToDecimal128(int64(*v)))
- case *int32:
- return encoder.Decimal128(int64ToDecimal128(int64(*v)))
- case *int64:
- return encoder.Decimal128(int64ToDecimal128(*v))
- case *uint8:
- return encoder.Decimal128(uint64ToDecimal128(uint64(*v)))
- case *uint16:
- return encoder.Decimal128(uint64ToDecimal128(uint64(*v)))
- case *uint32:
- return encoder.Decimal128(uint64ToDecimal128(uint64(*v)))
- case *uint64:
- return encoder.Decimal128(uint64ToDecimal128(*v))
- case *float32:
- fixed := d.float2int64(float64(*v))
- return encoder.Decimal128(int64ToDecimal128(fixed))
- case *float64:
- fixed := d.float2int64(float64(*v))
- return encoder.Decimal128(int64ToDecimal128(fixed))
- case *[]byte:
- if len(*v) != 16 {
- return errors.New("expected 16 bytes")
- }
- return encoder.Decimal128(*v)
- }
- return &ErrUnexpectedType{
- T: v,
- Column: d,
- }
- }
- func parseDecimal(name, chType string) (Column, error) {
- switch {
- case len(chType) < 12:
- fallthrough
- case !strings.HasPrefix(chType, "Decimal"):
- fallthrough
- case chType[7] != '(':
- fallthrough
- case chType[len(chType)-1] != ')':
- return nil, fmt.Errorf("invalid Decimal format: '%s'", chType)
- }
- var params = strings.Split(chType[8:len(chType)-1], ",")
- if len(params) != 2 {
- return nil, fmt.Errorf("invalid Decimal format: '%s'", chType)
- }
- params[0] = strings.TrimSpace(params[0])
- params[1] = strings.TrimSpace(params[1])
- var err error
- var decimal = &Decimal{
- base: base{
- name: name,
- chType: chType,
- },
- }
- if decimal.precision, err = strconv.Atoi(params[0]); err != nil {
- return nil, fmt.Errorf("'%s' is not Decimal type: %s", chType, err)
- } else if decimal.precision < 1 {
- return nil, errors.New("wrong precision of Decimal type")
- }
- if decimal.scale, err = strconv.Atoi(params[1]); err != nil {
- return nil, fmt.Errorf("'%s' is not Decimal type: %s", chType, err)
- } else if decimal.scale < 0 || decimal.scale > decimal.precision {
- return nil, errors.New("wrong scale of Decimal type")
- }
- switch {
- case decimal.precision <= 9:
- decimal.nobits = 32
- decimal.valueOf = columnBaseTypes[int32(0)]
- case decimal.precision <= 18:
- decimal.nobits = 64
- decimal.valueOf = columnBaseTypes[int64(0)]
- case decimal.precision <= 38:
- decimal.nobits = 128
- decimal.valueOf = reflect.ValueOf([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
- default:
- return nil, errors.New("precision of Decimal exceeds max bound")
- }
- return decimal, nil
- }
- func (d *Decimal) GetPrecision() int {
- return d.precision
- }
- func (d *Decimal) GetScale() int {
- return d.scale
- }
|