8000 Fix cast operation from numeric type to string type by goccy · Pull Request #40 · goccy/go-zetasqlite · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Fix cast operation from numeric type to string type #40

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 15 additions & 14 deletions internal/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,21 @@ package internal
type ValueType string

const (
IntValueType ValueType = "int64"
StringValueType ValueType = "string"
BytesValueType ValueType = "bytes"
FloatValueType ValueType = "float"
NumericValueType ValueType = "numeric"
BoolValueType ValueType = "bool"
JsonValueType ValueType = "json"
ArrayValueType ValueType = "array"
StructValueType ValueType = "struct"
DateValueType ValueType = "date"
DatetimeValueType ValueType = "datetime"
TimeValueType ValueType = "time"
TimestampValueType ValueType = "timestamp"
IntervalValueType ValueType = "interval"
IntValueType ValueType = "int64"
StringValueType ValueType = "string"
BytesValueType ValueType = "bytes"
FloatValueType ValueType = "float"
NumericValueType ValueType = "numeric"
BigNumericValueType ValueType = "bignumeric"
BoolValueType ValueType = "bool"
JsonValueType ValueType = "json"
ArrayValueType ValueType = "array"
StructValueType ValueType = "struct"
DateValueType ValueType = "date"
DatetimeValueType ValueType = "datetime"
TimeValueType ValueType = "time"
TimestampValueType ValueType = "timestamp"
IntervalValueType ValueType = "interval"
)

type ValueLayout struct {
Expand Down
6 changes: 5 additions & 1 deletion internal/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@ func decodeFromValueLayout(layout *ValueLayout) (Value, error) {
case NumericValueType:
r := new(big.Rat)
r.SetString(layout.Body)
return (*NumericValue)(r), nil
return &NumericValue{Rat: r}, nil
case BigNumericValueType:
r := new(big.Rat)
r.SetString(layout.Body)
return &NumericValue{Rat: r, isBigNumeric: true}, nil
case DateValueType:
t, err := parseDate(layout.Body)
if err != nil {
Expand Down
23 changes: 19 additions & 4 deletions internal/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,10 @@ func numericValueFromLiteral(lit string) (*NumericValue, error) {
numericLit := matches[0][1]
r := new(big.Rat)
r.SetString(numericLit)
return (*NumericValue)(r), nil
if strings.Contains("BIGNUMERIC", lit) {
return &NumericValue{Rat: r, isBigNumeric: true}, nil
}
return &NumericValue{Rat: r}, nil
}

func jsonValueFromLiteral(lit string) (JsonValue, error) {
Expand Down Expand Up @@ -471,12 +474,18 @@ func CastValue(t types.Type, v Value) (Value, error) {
ret.m[key] = casted
}
return ret, nil
case types.NUMERIC, types.BIG_NUMERIC:
case types.NUMERIC:
r, err := v.ToRat()
if err != nil {
return nil, err
}
return (*NumericValue)(r), nil
return &NumericValue{Rat: r}, nil
case types.BIG_NUMERIC:
r, err := v.ToRat()
if err != nil {
return nil, err
}
return &NumericValue{Rat: r, isBigNumeric: true}, nil
case types.JSON:
j, err := v.ToJSON()
if err != nil {
Expand Down Expand Up @@ -591,10 +600,16 @@ func valueLayoutFromValue(v Value) (*ValueLayout, error) {
Body: base64.StdEncoding.EncodeToString([]byte(vv)),
}, nil
case *NumericValue:
b, err := (*big.Rat)(vv).MarshalText()
b, err := vv.Rat.MarshalText()
if err != nil {
return nil, err
}
if vv.isBigNumeric {
return &ValueLayout{
Header: BigNumericValueType,
Body: string(b),
}, nil
}
return &ValueLayout{
Header: NumericValueType,
Body: string(b),
Expand Down
2 changes: 1 addition & 1 deletion internal/function_bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,7 @@ func bindParseBigNumeric(args ...Value) (Value, error) {
if err != nil {
return nil, err
}
return PARSE_NUMERIC(numeric)
return PARSE_BIGNUMERIC(numeric)
}

func bindFarmFingerprint(args ...Value) (Value, error) {
Expand Down
10 changes: 9 additions & 1 deletion internal/function_numeric.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,13 @@ func PARSE_NUMERIC(numeric string) (Value, error) {
if _, ok := r.SetString(numeric); !ok {
return nil, fmt.Errorf("unexpected numeric literal: %s", numeric)
}
return (*NumericValue)(r), nil
return &NumericValue{Rat: r}, nil
}

func PARSE_BIGNUMERIC(numeric string) (Value, error) {
r := new(big.Rat)
if _, ok := r.SetString(numeric); !ok {
return nil, fmt.Errorf("unexpected numeric literal: %s", numeric)
}
return &NumericValue{Rat: r, isBigNumeric: true}, nil
}
20 changes: 2 additions & 18 deletions internal/rows.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import (
"database/sql/driver"
"fmt"
"io"
"math/big"
"reflect"
"strings"
"time"

"github.com/goccy/go-json"
Expand Down Expand Up @@ -221,27 +219,13 @@ func (r *Rows) assignInterfaceValue(src Value, dst reflect.Value, typ *Type) err
if err != nil {
return err
}
r := new(big.Rat)
if _, ok := r.SetString(s); !ok {
return fmt.Errorf("unexpected numeric value: %s", s)
}
f := r.FloatString(9)
f = strings.TrimRight(f, "0")
f = strings.TrimRight(f, ".")
dst.Set(reflect.ValueOf(f))
dst.Set(reflect.ValueOf(s))
case types.BIG_NUMERIC:
s, err := src.ToString()
if err != nil {
return err
}
r := new(big.Rat)
if _, ok := r.SetString(s); !ok {
return fmt.Errorf("unexpected bignumeric value: %s", s)
}
f := r.FloatString(38)
f = strings.TrimRight(f, "0")
f = strings.TrimRight(f, ".")
dst.Set(reflect.ValueOf(f))
dst.Set(reflect.ValueOf(s))
case types.DATE:
date, err := src.ToJSON()
if err != nil {
Expand Down
65 changes: 42 additions & 23 deletions internal/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -587,37 +587,43 @@ func (fv FloatValue) Interface() interface{} {
return float64(fv)
}

type NumericValue big.Rat
type NumericValue struct {
*big.Rat
isBigNumeric bool
}

func (nv *NumericValue) Add(v Value) (Value, error) {
z := new(big.Rat)
x := (*big.Rat)(nv)
x := nv.Rat
y, err := v.ToRat()
if err != nil {
return nil, err
}
return (*NumericValue)(z.Add(x, y)), nil
nv.Rat = z.Add(x, y)
return nv, nil
}

func (nv *NumericValue) Sub(v Value) (Value, error) {
z := new(big.Rat)
x := (*big.Rat)(nv)
x := nv.Rat
y, err := v.ToRat()
if err != nil {
return nil, err
}
zy := new(big.Rat)
return (*NumericValue)(z.Add(x, zy.Neg(y))), nil
nv.Rat = z.Add(x, zy.Neg(y))
return nv, nil
}

func (nv *NumericValue) Mul(v Value) (Value, error) {
z := new(big.Rat)
x := (*big.Rat)(nv)
x := nv.Rat
y, err := v.ToRat()
if err != nil {
return nil, err
}
return (*NumericValue)(z.Mul(x, y)), nil
nv.Rat = z.Mul(x, y)
return nv, nil
}

func (nv *NumericValue) Div(v Value) (ret Value, e error) {
Expand All @@ -627,17 +633,18 @@ func (nv *NumericValue) Div(v Value) (ret Value, e error) {
}
}()
z := new(big.Rat)
x := (*big.Rat)(nv)
x := nv.Rat
y, err := v.ToRat()
if err != nil {
return nil, err
}
zy := new(big.Rat)
return (*NumericValue)(z.Mul(x, zy.Inv(y))), nil
nv.Rat = z.Mul(x, zy.Inv(y))
return nv, nil
}

func (nv *NumericValue) EQ(v Value) (bool, error) {
x := (*big.Rat)(nv)
x := nv.Rat
y, err := v.ToRat()
if err != nil {
return false, err
Expand All @@ -646,7 +653,7 @@ func (nv *NumericValue) EQ(v Value) (bool, error) {
}

func (nv *NumericValue) GT(v Value) (bool, error) {
x := (*big.Rat)(nv)
x := nv.Rat
y, err := v.ToRat()
if err != nil {
return false, err
Expand All @@ -655,7 +662,7 @@ func (nv *NumericValue) GT(v Value) (bool, error) {
}

func (nv *NumericValue) GTE(v Value) (bool, error) {
x := (*big.Rat)(nv)
x := nv.Rat
y, err := v.ToRat()
if err != nil {
return false, err
Expand All @@ -664,7 +671,7 @@ func (nv *NumericValue) GTE(v Value) (bool, error) {
}

func (nv *NumericValue) LT(v Value) (bool, error) {
x := (*big.Rat)(nv)
x := nv.Rat
y, err := v.ToRat()
if err != nil {
return false, err
Expand All @@ -673,7 +680,7 @@ func (nv *NumericValue) LT(v Value) (bool, error) {
}

func (nv *NumericValue) LTE(v Value) (bool, error) {
x := (*big.Rat)(nv)
x := nv.Rat
y, err := v.ToRat()
if err != nil {
return false, err
Expand All @@ -682,24 +689,36 @@ func (nv *NumericValue) LTE(v Value) (bool, error) {
}

func (nv *NumericValue) ToInt64() (int64, error) {
return (*big.Rat)(nv).Num().Int64(), nil
return nv.Rat.Num().Int64(), nil
}

func (nv *NumericValue) toString() string {
var v string
if nv.isBigNumeric {
v = nv.Rat.FloatString(38)
} else {
v = nv.Rat.FloatString(9)
}
v = strings.TrimRight(v, "0")
v = strings.TrimRight(v, ".")
return v
}

func (nv *NumericValue) ToString() (string, error) {
return (*big.Rat)(nv).RatString(), nil
return nv.toString(), nil
}

func (nv *NumericValue) ToBytes() ([]byte, error) {
return []byte((*big.Rat)(nv).RatString()), nil
return []byte(nv.toString()), nil
}

func (nv *NumericValue) ToFloat64() (float64, error) {
f, _ := (*big.Rat)(nv).Float64()
f, _ := nv.Rat.Float64()
return f, nil
}

func (nv *NumericValue) ToBool() (bool, error) {
v := (*big.Rat)(nv).Num().Int64()
v := nv.Rat.Num().Int64()
if v == 1 {
return true, nil
} else if v == 0 {
Expand All @@ -717,23 +736,23 @@ func (nv *NumericValue) ToStruct() (*StructValue, error) {
}

func (nv *NumericValue) ToJSON() (string, error) {
return (*big.Rat)(nv).RatString(), nil
return nv.toString(), nil
}

func (nv *NumericValue) ToTime() (time.Time, error) {
return time.Time{}, fmt.Errorf("failed to convert time.Time from numeric value")
}

func (nv *NumericValue) ToRat() (*big.Rat, error) {
return (*big.Rat)(nv), nil
return nv.Rat, nil
}

func (nv *NumericValue) Format(verb rune) string {
return (*big.Rat)(nv).RatString()
return nv.toString()
}

func (nv *NumericValue) Interface() interface{} {
f, _ := (*big.Rat)(nv).Float64()
f, _ := nv.Rat.Float64()
return f
}

Expand Down
5 changes: 5 additions & 0 deletions query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3087,6 +3087,11 @@ SELECT
query: `SELECT PARSE_BIGNUMERIC("123.45"), PARSE_BIGNUMERIC("123.456E37"), PARSE_BIGNUMERIC("1.123456789012345678901234567890123456789")`,
expectedRows: [][]interface{}{{"123.45", "1234560000000000000000000000000000000000", "1.12345678901234567890123456789012345679"}},
},
{
name: "cast numeric and bignumeric to string",
query: `SELECT cast(PARSE_NUMERIC("123.456") as STRING), cast(PARSE_BIGNUMERIC("123.456") as STRING)`,
expectedRows: [][]interface{}{{"123.456", "123.456"}},
},

// uuid functions
{
Expand Down
0