Implement uint64 logic into eval
Any operation between an int64 and uint64 results in the type becoming a uint64. This is because the most common will usually be an unsigned cursor being modified by an int literal. Even in cases where we were to add an unsigned literal to an integer iterator, that would just result in it being recast back and overflow.pull/8884/head
parent
963cbfd275
commit
f0fb0174b6
239
influxql/ast.go
239
influxql/ast.go
|
@ -3820,6 +3820,8 @@ func Eval(expr Expr, m map[string]interface{}) interface{} {
|
|||
return expr.Val
|
||||
case *NumberLiteral:
|
||||
return expr.Val
|
||||
case *UnsignedLiteral:
|
||||
return expr.Val
|
||||
case *ParenExpr:
|
||||
return Eval(expr.Expr, m)
|
||||
case *RegexLiteral:
|
||||
|
@ -3870,12 +3872,14 @@ func evalBinaryExpr(expr *BinaryExpr, m map[string]interface{}) interface{} {
|
|||
return ok && (lhs != rhs)
|
||||
}
|
||||
case float64:
|
||||
// Try the rhs as a float64 or int64
|
||||
// Try the rhs as a float64, int64, or uint64
|
||||
rhsf, ok := rhs.(float64)
|
||||
if !ok {
|
||||
var rhsi int64
|
||||
if rhsi, ok = rhs.(int64); ok {
|
||||
rhsf = float64(rhsi)
|
||||
switch val := rhs.(type) {
|
||||
case int64:
|
||||
rhsf, ok = float64(val), true
|
||||
case uint64:
|
||||
rhsf, ok = float64(val), true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3923,10 +3927,9 @@ func evalBinaryExpr(expr *BinaryExpr, m map[string]interface{}) interface{} {
|
|||
}
|
||||
case int64:
|
||||
// Try as a float64 to see if a float cast is required.
|
||||
rhsf, ok := rhs.(float64)
|
||||
if ok {
|
||||
switch rhs := rhs.(type) {
|
||||
case float64:
|
||||
lhs := float64(lhs)
|
||||
rhs := rhsf
|
||||
switch expr.Op {
|
||||
case EQ:
|
||||
return lhs == rhs
|
||||
|
@ -3954,64 +3957,209 @@ func evalBinaryExpr(expr *BinaryExpr, m map[string]interface{}) interface{} {
|
|||
case MOD:
|
||||
return math.Mod(lhs, rhs)
|
||||
}
|
||||
} else {
|
||||
rhs, ok := rhs.(int64)
|
||||
case int64:
|
||||
switch expr.Op {
|
||||
case EQ:
|
||||
return ok && (lhs == rhs)
|
||||
return lhs == rhs
|
||||
case NEQ:
|
||||
return ok && (lhs != rhs)
|
||||
return lhs != rhs
|
||||
case LT:
|
||||
return ok && (lhs < rhs)
|
||||
return lhs < rhs
|
||||
case LTE:
|
||||
return ok && (lhs <= rhs)
|
||||
return lhs <= rhs
|
||||
case GT:
|
||||
return ok && (lhs > rhs)
|
||||
return lhs > rhs
|
||||
case GTE:
|
||||
return ok && (lhs >= rhs)
|
||||
return lhs >= rhs
|
||||
case ADD:
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return lhs + rhs
|
||||
case SUB:
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return lhs - rhs
|
||||
case MUL:
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return lhs * rhs
|
||||
case DIV:
|
||||
if !ok {
|
||||
return nil
|
||||
} else if rhs == 0 {
|
||||
if rhs == 0 {
|
||||
return float64(0)
|
||||
}
|
||||
return lhs / rhs
|
||||
case MOD:
|
||||
if !ok {
|
||||
return nil
|
||||
} else if rhs == 0 {
|
||||
if rhs == 0 {
|
||||
return int64(0)
|
||||
}
|
||||
return lhs % rhs
|
||||
case BITWISE_AND:
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return lhs & rhs
|
||||
case BITWISE_OR:
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return lhs | rhs
|
||||
case BITWISE_XOR:
|
||||
if !ok {
|
||||
return nil
|
||||
return lhs ^ rhs
|
||||
}
|
||||
case uint64:
|
||||
switch expr.Op {
|
||||
case EQ:
|
||||
return uint64(lhs) == rhs
|
||||
case NEQ:
|
||||
return uint64(lhs) != rhs
|
||||
case LT:
|
||||
if lhs < 0 {
|
||||
return true
|
||||
}
|
||||
return uint64(lhs) < rhs
|
||||
case LTE:
|
||||
if lhs < 0 {
|
||||
return true
|
||||
}
|
||||
return uint64(lhs) <= rhs
|
||||
case GT:
|
||||
if lhs < 0 {
|
||||
return false
|
||||
}
|
||||
return uint64(lhs) > rhs
|
||||
case GTE:
|
||||
if lhs < 0 {
|
||||
return false
|
||||
}
|
||||
return uint64(lhs) >= rhs
|
||||
case ADD:
|
||||
return uint64(lhs) + rhs
|
||||
case SUB:
|
||||
return uint64(lhs) - rhs
|
||||
case MUL:
|
||||
return uint64(lhs) * rhs
|
||||
case DIV:
|
||||
if rhs == 0 {
|
||||
return uint64(0)
|
||||
}
|
||||
return uint64(lhs) / rhs
|
||||
case MOD:
|
||||
if rhs == 0 {
|
||||
return uint64(0)
|
||||
}
|
||||
return uint64(lhs) % rhs
|
||||
case BITWISE_AND:
|
||||
return uint64(lhs) & rhs
|
||||
case BITWISE_OR:
|
||||
return uint64(lhs) | rhs
|
||||
case BITWISE_XOR:
|
||||
return uint64(lhs) ^ rhs
|
||||
}
|
||||
}
|
||||
case uint64:
|
||||
// Try as a float64 to see if a float cast is required.
|
||||
switch rhs := rhs.(type) {
|
||||
case float64:
|
||||
lhs := float64(lhs)
|
||||
switch expr.Op {
|
||||
case EQ:
|
||||
return lhs == rhs
|
||||
case NEQ:
|
||||
return lhs != rhs
|
||||
case LT:
|
||||
return lhs < rhs
|
||||
case LTE:
|
||||
return lhs <= rhs
|
||||
case GT:
|
||||
return lhs > rhs
|
||||
case GTE:
|
||||
return lhs >= rhs
|
||||
case ADD:
|
||||
return lhs + rhs
|
||||
case SUB:
|
||||
return lhs - rhs
|
||||
case MUL:
|
||||
return lhs * rhs
|
||||
case DIV:
|
||||
if rhs == 0 {
|
||||
return float64(0)
|
||||
}
|
||||
return lhs / rhs
|
||||
case MOD:
|
||||
return math.Mod(lhs, rhs)
|
||||
}
|
||||
case int64:
|
||||
switch expr.Op {
|
||||
case EQ:
|
||||
return lhs == uint64(rhs)
|
||||
case NEQ:
|
||||
return lhs != uint64(rhs)
|
||||
case LT:
|
||||
if rhs < 0 {
|
||||
return false
|
||||
}
|
||||
return lhs < uint64(rhs)
|
||||
case LTE:
|
||||
if rhs < 0 {
|
||||
return false
|
||||
}
|
||||
return lhs <= uint64(rhs)
|
||||
case GT:
|
||||
if rhs < 0 {
|
||||
return true
|
||||
}
|
||||
return lhs > uint64(rhs)
|
||||
case GTE:
|
||||
if rhs < 0 {
|
||||
return true
|
||||
}
|
||||
return lhs >= uint64(rhs)
|
||||
case ADD:
|
||||
return lhs + uint64(rhs)
|
||||
case SUB:
|
||||
return lhs - uint64(rhs)
|
||||
case MUL:
|
||||
return lhs * uint64(rhs)
|
||||
case DIV:
|
||||
if rhs == 0 {
|
||||
return uint64(0)
|
||||
}
|
||||
return lhs / uint64(rhs)
|
||||
case MOD:
|
||||
if rhs == 0 {
|
||||
return uint64(0)
|
||||
}
|
||||
return lhs % uint64(rhs)
|
||||
case BITWISE_AND:
|
||||
return lhs & uint64(rhs)
|
||||
case BITWISE_OR:
|
||||
return lhs | uint64(rhs)
|
||||
case BITWISE_XOR:
|
||||
return lhs ^ uint64(rhs)
|
||||
}
|
||||
case uint64:
|
||||
switch expr.Op {
|
||||
case EQ:
|
||||
return lhs == rhs
|
||||
case NEQ:
|
||||
return lhs != rhs
|
||||
case LT:
|
||||
return lhs < rhs
|
||||
case LTE:
|
||||
return lhs <= rhs
|
||||
case GT:
|
||||
return lhs > rhs
|
||||
case GTE:
|
||||
return lhs >= rhs
|
||||
case ADD:
|
||||
return lhs + rhs
|
||||
case SUB:
|
||||
return lhs - rhs
|
||||
case MUL:
|
||||
return lhs * rhs
|
||||
case DIV:
|
||||
if rhs == 0 {
|
||||
return uint64(0)
|
||||
}
|
||||
return lhs / rhs
|
||||
case MOD:
|
||||
if rhs == 0 {
|
||||
return uint64(0)
|
||||
}
|
||||
return lhs % rhs
|
||||
case BITWISE_AND:
|
||||
return lhs & rhs
|
||||
case BITWISE_OR:
|
||||
return lhs | rhs
|
||||
case BITWISE_XOR:
|
||||
return lhs ^ rhs
|
||||
}
|
||||
}
|
||||
|
@ -4020,29 +4168,36 @@ func evalBinaryExpr(expr *BinaryExpr, m map[string]interface{}) interface{} {
|
|||
case EQ:
|
||||
rhs, ok := rhs.(string)
|
||||
if !ok {
|
||||
return nil
|
||||
return false
|
||||
}
|
||||
return lhs == rhs
|
||||
case NEQ:
|
||||
rhs, ok := rhs.(string)
|
||||
if !ok {
|
||||
return nil
|
||||
return false
|
||||
}
|
||||
return lhs != rhs
|
||||
case EQREGEX:
|
||||
rhs, ok := rhs.(*regexp.Regexp)
|
||||
if !ok {
|
||||
return nil
|
||||
return false
|
||||
}
|
||||
return rhs.MatchString(lhs)
|
||||
case NEQREGEX:
|
||||
rhs, ok := rhs.(*regexp.Regexp)
|
||||
if !ok {
|
||||
return nil
|
||||
return false
|
||||
}
|
||||
return !rhs.MatchString(lhs)
|
||||
}
|
||||
}
|
||||
|
||||
// The types were not comparable. If our operation was an equality operation,
|
||||
// return false instead of true.
|
||||
switch expr.Op {
|
||||
case EQ, NEQ, LT, LTE, GT, GTE:
|
||||
return false
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -995,6 +995,34 @@ func TestEval(t *testing.T) {
|
|||
{in: `0 = 'test'`, out: false},
|
||||
{in: `1.0 = 1`, out: true},
|
||||
{in: `1.2 = 1`, out: false},
|
||||
{in: `-1 = 9223372036854775808`, out: false},
|
||||
{in: `-1 != 9223372036854775808`, out: true},
|
||||
{in: `-1 < 9223372036854775808`, out: true},
|
||||
{in: `-1 <= 9223372036854775808`, out: true},
|
||||
{in: `-1 > 9223372036854775808`, out: false},
|
||||
{in: `-1 >= 9223372036854775808`, out: false},
|
||||
{in: `9223372036854775808 = -1`, out: false},
|
||||
{in: `9223372036854775808 != -1`, out: true},
|
||||
{in: `9223372036854775808 < -1`, out: false},
|
||||
{in: `9223372036854775808 <= -1`, out: false},
|
||||
{in: `9223372036854775808 > -1`, out: true},
|
||||
{in: `9223372036854775808 >= -1`, out: true},
|
||||
{in: `9223372036854775808 = 9223372036854775808`, out: true},
|
||||
{in: `9223372036854775808 != 9223372036854775808`, out: false},
|
||||
{in: `9223372036854775808 < 9223372036854775808`, out: false},
|
||||
{in: `9223372036854775808 <= 9223372036854775808`, out: true},
|
||||
{in: `9223372036854775808 > 9223372036854775808`, out: false},
|
||||
{in: `9223372036854775808 >= 9223372036854775808`, out: true},
|
||||
{in: `9223372036854775809 = 9223372036854775808`, out: false},
|
||||
{in: `9223372036854775809 != 9223372036854775808`, out: true},
|
||||
{in: `9223372036854775809 < 9223372036854775808`, out: false},
|
||||
{in: `9223372036854775809 <= 9223372036854775808`, out: false},
|
||||
{in: `9223372036854775809 > 9223372036854775808`, out: true},
|
||||
{in: `9223372036854775809 >= 9223372036854775808`, out: true},
|
||||
{in: `9223372036854775808 / 0`, out: uint64(0)},
|
||||
{in: `9223372036854775808 + 1`, out: uint64(9223372036854775809)},
|
||||
{in: `9223372036854775808 - 1`, out: uint64(9223372036854775807)},
|
||||
{in: `9223372036854775809 - 9223372036854775808`, out: uint64(1)},
|
||||
|
||||
// Boolean literals.
|
||||
{in: `true AND false`, out: false},
|
||||
|
@ -1004,7 +1032,7 @@ func TestEval(t *testing.T) {
|
|||
// String literals.
|
||||
{in: `'foo' = 'bar'`, out: false},
|
||||
{in: `'foo' = 'foo'`, out: true},
|
||||
{in: `'' = 4`, out: nil},
|
||||
{in: `'' = 4`, out: false},
|
||||
|
||||
// Regex literals.
|
||||
{in: `'foo' =~ /f.*/`, out: true},
|
||||
|
@ -1015,8 +1043,8 @@ func TestEval(t *testing.T) {
|
|||
// Variable references.
|
||||
{in: `foo`, out: "bar", data: map[string]interface{}{"foo": "bar"}},
|
||||
{in: `foo = 'bar'`, out: true, data: map[string]interface{}{"foo": "bar"}},
|
||||
{in: `foo = 'bar'`, out: nil, data: map[string]interface{}{"foo": nil}},
|
||||
{in: `'bar' = foo`, out: nil, data: map[string]interface{}{"foo": nil}},
|
||||
{in: `foo = 'bar'`, out: false, data: map[string]interface{}{"foo": nil}},
|
||||
{in: `'bar' = foo`, out: false, data: map[string]interface{}{"foo": nil}},
|
||||
{in: `foo <> 'bar'`, out: true, data: map[string]interface{}{"foo": "xxx"}},
|
||||
{in: `foo =~ /b.*/`, out: true, data: map[string]interface{}{"foo": "bar"}},
|
||||
{in: `foo !~ /b.*/`, out: false, data: map[string]interface{}{"foo": "bar"}},
|
||||
|
|
Loading…
Reference in New Issue