diff --git a/influxql/ast.go b/influxql/ast.go index ca77e4df41..341b9a5297 100644 --- a/influxql/ast.go +++ b/influxql/ast.go @@ -3520,6 +3520,8 @@ func CloneExpr(expr Expr) Expr { return &DurationLiteral{Val: expr.Val} case *IntegerLiteral: return &IntegerLiteral{Val: expr.Val} + case *UnsignedLiteral: + return &UnsignedLiteral{Val: expr.Val} case *NumberLiteral: return &NumberLiteral{Val: expr.Val} case *ParenExpr: @@ -4407,6 +4409,8 @@ func reduceBinaryExpr(expr *BinaryExpr, valuer Valuer) Expr { return reduceBinaryExprDurationLHS(op, lhs, rhs, loc) case *IntegerLiteral: return reduceBinaryExprIntegerLHS(op, lhs, rhs, loc) + case *UnsignedLiteral: + return reduceBinaryExprUnsignedLHS(op, lhs, rhs) case *NilLiteral: return reduceBinaryExprNilLHS(op, lhs, rhs) case *NumberLiteral: @@ -4550,6 +4554,19 @@ func reduceBinaryExprIntegerLHS(op Token, lhs *IntegerLiteral, rhs Expr, loc *ti case LTE: return &BooleanLiteral{Val: lhs.Val <= rhs.Val} } + case *UnsignedLiteral: + // Comparisons between an unsigned and integer literal will not involve + // a cast if the integer is negative as that will have an improper result. + // Look for those situations here. + if lhs.Val < 0 { + switch op { + case LT, LTE: + return &BooleanLiteral{Val: true} + case GT, GTE: + return &BooleanLiteral{Val: false} + } + } + return reduceBinaryExprUnsignedLHS(op, &UnsignedLiteral{Val: uint64(lhs.Val)}, rhs) case *DurationLiteral: // Treat the integer as a timestamp. switch op { @@ -4580,6 +4597,58 @@ func reduceBinaryExprIntegerLHS(op Token, lhs *IntegerLiteral, rhs Expr, loc *ti return &BinaryExpr{Op: op, LHS: lhs, RHS: rhs} } +func reduceBinaryExprUnsignedLHS(op Token, lhs *UnsignedLiteral, rhs Expr) Expr { + switch rhs := rhs.(type) { + case *NumberLiteral: + return reduceBinaryExprNumberLHS(op, &NumberLiteral{Val: float64(lhs.Val)}, rhs) + case *IntegerLiteral: + // Comparisons between an unsigned and integer literal will not involve + // a cast if the integer is negative as that will have an improper result. + // Look for those situations here. + if rhs.Val < 0 { + switch op { + case LT, LTE: + return &BooleanLiteral{Val: false} + case GT, GTE: + return &BooleanLiteral{Val: true} + } + } + return reduceBinaryExprUnsignedLHS(op, lhs, &UnsignedLiteral{Val: uint64(rhs.Val)}) + case *UnsignedLiteral: + switch op { + case ADD: + return &UnsignedLiteral{Val: lhs.Val + rhs.Val} + case SUB: + return &UnsignedLiteral{Val: lhs.Val - rhs.Val} + case MUL: + return &UnsignedLiteral{Val: lhs.Val * rhs.Val} + case DIV: + if rhs.Val == 0 { + return &UnsignedLiteral{Val: 0} + } + return &UnsignedLiteral{Val: lhs.Val / rhs.Val} + case MOD: + if rhs.Val == 0 { + return &UnsignedLiteral{Val: 0} + } + return &UnsignedLiteral{Val: lhs.Val % rhs.Val} + case EQ: + return &BooleanLiteral{Val: lhs.Val == rhs.Val} + case NEQ: + return &BooleanLiteral{Val: lhs.Val != rhs.Val} + case GT: + return &BooleanLiteral{Val: lhs.Val > rhs.Val} + case GTE: + return &BooleanLiteral{Val: lhs.Val >= rhs.Val} + case LT: + return &BooleanLiteral{Val: lhs.Val < rhs.Val} + case LTE: + return &BooleanLiteral{Val: lhs.Val <= rhs.Val} + } + } + return &BinaryExpr{Op: op, LHS: lhs, RHS: rhs} +} + func reduceBinaryExprNilLHS(op Token, lhs *NilLiteral, rhs Expr) Expr { switch op { case EQ, NEQ: @@ -4646,6 +4715,8 @@ func reduceBinaryExprNumberLHS(op Token, lhs *NumberLiteral, rhs Expr) Expr { case LTE: return &BooleanLiteral{Val: lhs.Val <= float64(rhs.Val)} } + case *UnsignedLiteral: + return reduceBinaryExprNumberLHS(op, lhs, &NumberLiteral{Val: float64(rhs.Val)}) case *NilLiteral: return &BooleanLiteral{Val: false} } diff --git a/influxql/ast_test.go b/influxql/ast_test.go index 59e5b2ed5f..b00fc6aed4 100644 --- a/influxql/ast_test.go +++ b/influxql/ast_test.go @@ -1178,6 +1178,34 @@ func TestReduce(t *testing.T) { {in: `4 < 6`, out: `true`}, {in: `4 <= 4`, out: `true`}, {in: `4 AND 5`, out: `4 AND 5`}, + {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: `0`}, + {in: `9223372036854775808 + 1`, out: `9223372036854775809`}, + {in: `9223372036854775808 - 1`, out: `9223372036854775807`}, + {in: `9223372036854775809 - 9223372036854775808`, out: `1`}, // Boolean literals. {in: `true AND false`, out: `false`},