mirror of
https://github.com/chaisql/chai.git
synced 2025-10-08 09:00:08 +08:00
Handle integer conversion errors (#425)
When converting a double larger or equal to math.MaxInt64 to an integer, it previously overflowed silently. It now returns an explicit error. This fixes along the way, the math.abs(-9223372036854775808) issue.
This commit is contained in:

committed by
GitHub

parent
daf4f79e9f
commit
01c87d1bf7
@@ -14,11 +14,6 @@ func CastAs(v types.Value, t types.ValueType) (types.Value, error) {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// Null values always remain null.
|
||||
if v.Type() == types.NullValue {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
switch t {
|
||||
case types.BoolValue:
|
||||
return CastAsBool(v)
|
||||
@@ -45,6 +40,11 @@ func CastAs(v types.Value, t types.ValueType) (types.Value, error) {
|
||||
// it fails if the text doesn't contain a valid boolean.
|
||||
// Any other type is considered an invalid cast.
|
||||
func CastAsBool(v types.Value) (types.Value, error) {
|
||||
// Null values always remain null.
|
||||
if v.Type() == types.NullValue {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
switch v.Type() {
|
||||
case types.BoolValue:
|
||||
return v, nil
|
||||
@@ -70,6 +70,11 @@ func CastAsBool(v types.Value) (types.Value, error) {
|
||||
// It fails if the text doesn't contain a valid float value.
|
||||
// Any other type is considered an invalid cast.
|
||||
func CastAsInteger(v types.Value) (types.Value, error) {
|
||||
// Null values always remain null.
|
||||
if v.Type() == types.NullValue {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
switch v.Type() {
|
||||
case types.IntegerValue:
|
||||
return v, nil
|
||||
@@ -79,7 +84,11 @@ func CastAsInteger(v types.Value) (types.Value, error) {
|
||||
}
|
||||
return types.NewIntegerValue(0), nil
|
||||
case types.DoubleValue:
|
||||
return types.NewIntegerValue(int64(v.V().(float64))), nil
|
||||
f := v.V().(float64)
|
||||
if f > 0 && int64(f) < 0 {
|
||||
return nil, stringutil.Errorf("integer out of range")
|
||||
}
|
||||
return types.NewIntegerValue(int64(f)), nil
|
||||
case types.TextValue:
|
||||
i, err := strconv.ParseInt(v.V().(string), 10, 64)
|
||||
if err != nil {
|
||||
@@ -102,6 +111,11 @@ func CastAsInteger(v types.Value) (types.Value, error) {
|
||||
// it fails if the text doesn't contain a valid float value.
|
||||
// Any other type is considered an invalid cast.
|
||||
func CastAsDouble(v types.Value) (types.Value, error) {
|
||||
// Null values always remain null.
|
||||
if v.Type() == types.NullValue {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
switch v.Type() {
|
||||
case types.DoubleValue:
|
||||
return v, nil
|
||||
@@ -121,6 +135,11 @@ func CastAsDouble(v types.Value) (types.Value, error) {
|
||||
// CastAsText returns a JSON representation of v.
|
||||
// If the representation is a string, it gets unquoted.
|
||||
func CastAsText(v types.Value) (types.Value, error) {
|
||||
// Null values always remain null.
|
||||
if v.Type() == types.NullValue {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
switch v.Type() {
|
||||
case types.TextValue:
|
||||
return v, nil
|
||||
@@ -142,6 +161,11 @@ func CastAsText(v types.Value) (types.Value, error) {
|
||||
// Text: decodes a base64 string, otherwise fails.
|
||||
// Any other type is considered an invalid cast.
|
||||
func CastAsBlob(v types.Value) (types.Value, error) {
|
||||
// Null values always remain null.
|
||||
if v.Type() == types.NullValue {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
if v.Type() == types.BlobValue {
|
||||
return v, nil
|
||||
}
|
||||
@@ -164,6 +188,11 @@ func CastAsBlob(v types.Value) (types.Value, error) {
|
||||
// Text: decodes a JSON array, otherwise fails.
|
||||
// Any other type is considered an invalid cast.
|
||||
func CastAsArray(v types.Value) (types.Value, error) {
|
||||
// Null values always remain null.
|
||||
if v.Type() == types.NullValue {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
if v.Type() == types.ArrayValue {
|
||||
return v, nil
|
||||
}
|
||||
@@ -185,6 +214,11 @@ func CastAsArray(v types.Value) (types.Value, error) {
|
||||
// Text: decodes a JSON object, otherwise fails.
|
||||
// Any other type is considered an invalid cast.
|
||||
func CastAsDocument(v types.Value) (types.Value, error) {
|
||||
// Null values always remain null.
|
||||
if v.Type() == types.NullValue {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
if v.Type() == types.DocumentValue {
|
||||
return v, nil
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package document
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/genjidb/genji/types"
|
||||
@@ -70,6 +71,7 @@ func TestCastAs(t *testing.T) {
|
||||
{blobV, nil, true},
|
||||
{arrayV, nil, true},
|
||||
{docV, nil, true},
|
||||
{types.NewDoubleValue(math.MaxInt64 + 1), nil, true},
|
||||
})
|
||||
})
|
||||
|
||||
|
@@ -17,6 +17,8 @@ NULL
|
||||
2.0
|
||||
! math.abs('foo')
|
||||
'cannot cast "foo" as double'
|
||||
! math.abs(-9223372036854775808)
|
||||
'integer out of range'
|
||||
|
||||
-- test: math.acos
|
||||
> math.acos(NULL)
|
||||
|
@@ -152,7 +152,7 @@ func ExprRunner(t *testing.T, testfile string) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// eval it to get a proper Value
|
||||
want, err := e.Eval(emptyEnv)
|
||||
want, err := e.Eval(environment.New(nil))
|
||||
require.NoError(t, err)
|
||||
|
||||
// parse the given expr
|
||||
@@ -160,7 +160,7 @@ func ExprRunner(t *testing.T, testfile string) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// eval it to get a proper Value
|
||||
got, err := e.Eval(emptyEnv)
|
||||
got, err := e.Eval(environment.New(nil))
|
||||
require.NoError(t, err)
|
||||
|
||||
// finally, compare those two
|
||||
@@ -170,12 +170,14 @@ func ExprRunner(t *testing.T, testfile string) {
|
||||
t.Run("NOK "+stmt.Expr, func(t *testing.T) {
|
||||
// parse the given epxr
|
||||
e, err := parser.NewParser(strings.NewReader(stmt.Expr)).ParseExpr()
|
||||
require.NoError(t, err)
|
||||
|
||||
if err != nil {
|
||||
require.Regexp(t, regexp.MustCompile(regexp.QuoteMeta(stmt.Res)), err.Error())
|
||||
} else {
|
||||
// eval it, it should return an error
|
||||
_, err = e.Eval(emptyEnv)
|
||||
_, err = e.Eval(environment.New(nil))
|
||||
require.NotNilf(t, err, "expected expr `%s` to return an error, got nil", stmt.Expr)
|
||||
require.Regexp(t, regexp.MustCompile(regexp.QuoteMeta(stmt.Res)), err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user