func (e *Evaluator) handleOrOr(o *ast.BinaryOperationExpr) bool { leftVal := o.L.GetValue() righVal := o.R.GetValue() if !types.IsNil(leftVal) { x, err := types.ToBool(leftVal) if err != nil { e.err = errors.Trace(err) return false } else if x == 1 { // true || any other types is true. o.SetValue(x) return true } } if !types.IsNil(righVal) { y, err := types.ToBool(righVal) if err != nil { e.err = errors.Trace(err) return false } else if y == 1 { o.SetValue(y) return true } } if types.IsNil(leftVal) || types.IsNil(righVal) { o.SetValue(nil) return true } o.SetValue(int64(0)) return true }
func (o *BinaryOperation) evalLogicXor(ctx context.Context, args map[interface{}]interface{}) (interface{}, error) { a, err := o.L.Eval(ctx, args) if err != nil || a == nil { return nil, o.traceErr(err) } x, err := types.ToBool(a) if err != nil { return nil, o.traceErr(err) } b, err := o.R.Eval(ctx, args) if err != nil || b == nil { return nil, o.traceErr(err) } y, err := types.ToBool(b) if err != nil { return nil, o.traceErr(err) } if x == y { return int64(0), nil } return int64(1), nil }
func (e *Evaluator) handleXor(o *ast.BinaryOperationExpr) bool { leftVal := o.L.GetValue() righVal := o.R.GetValue() if types.IsNil(leftVal) || types.IsNil(righVal) { o.SetValue(nil) return true } x, err := types.ToBool(leftVal) if err != nil { e.err = errors.Trace(err) return false } y, err := types.ToBool(righVal) if err != nil { e.err = errors.Trace(err) return false } if x == y { o.SetValue(int64(0)) } else { o.SetValue(int64(1)) } return true }
// Eval implements the Expression Eval interface. func (is *IsTruth) Eval(ctx context.Context, args map[interface{}]interface{}) (v interface{}, err error) { if err := CheckOneColumn(is.Expr); err != nil { return nil, errors.Trace(err) } val, err := is.Expr.Eval(ctx, args) if err != nil { return } if val == nil { // null is true/false -> false // null is not true/false -> true return is.Not, nil } b, err := types.ToBool(val) if err != nil { return } if !is.Not { // true/false is true/false return b == is.True, nil } // true/false is not true/false return b != is.True, nil }
func (n *PatternIn) evalInList(ctx context.Context, args map[interface{}]interface{}, in interface{}, list []expression.Expression) (interface{}, error) { hasNull := false for _, v := range list { b := NewBinaryOperation(opcode.EQ, Value{in}, v) eVal, err := b.Eval(ctx, args) if err != nil { return nil, err } if eVal == nil { hasNull = true continue } r, err := types.ToBool(eVal) if err != nil { return nil, err } if r == 1 { return !n.Not, nil } } if hasNull { // if no matched but we got null in In, return null // e.g 1 in (null, 2, 3) returns null return nil, nil } return n.Not, nil }
// Do implements plan.Plan Do interface. func (r *FilterDefaultPlan) Do(ctx context.Context, f plan.RowIterFunc) (err error) { m := map[interface{}]interface{}{} fields := r.GetFields() return r.Plan.Do(ctx, func(rid interface{}, data []interface{}) (bool, error) { m[expressions.ExprEvalIdentFunc] = func(name string) (interface{}, error) { return getIdentValue(name, fields, data, field.DefaultFieldFlag) } val, err := r.Expr.Eval(ctx, m) if err != nil { return false, err } if val == nil { return true, nil } // Evaluate the expression, if the result is true, go on, otherwise // skip this row. x, err := types.ToBool(val) if err != nil { return false, err } if x == 0 { return true, nil } return f(rid, data) }) }
func (o *BinaryOperation) evalOrOr(ctx context.Context, args map[interface{}]interface{}) (interface{}, error) { a, err := o.L.Eval(ctx, args) if err != nil { return nil, o.traceErr(err) } var ( x int64 y int64 ) if a != nil { x, err = types.ToBool(a) if err != nil { return nil, o.traceErr(err) } else if x == 1 { // true || any other types is true return x, nil } } b, err := o.R.Eval(ctx, args) if err != nil { return nil, o.traceErr(err) } if b != nil { y, err = types.ToBool(b) if err != nil { return nil, o.traceErr(err) } else if y == 1 { return y, nil } } // here x and y are all not true // if a or b is nil if a == nil || b == nil { return nil, nil } return int64(0), nil }
func (r *FilterDefaultPlan) meetCondition(ctx context.Context) (bool, error) { val, err := r.Expr.Eval(ctx, r.evalArgs) if val == nil || err != nil { return false, errors.Trace(err) } x, err := types.ToBool(val) if err != nil { return false, errors.Trace(err) } return x == 1, nil }
func (o *BinaryOperation) evalAndAnd(ctx context.Context, args map[interface{}]interface{}) (interface{}, error) { a, err := o.L.Eval(ctx, args) if err != nil { return nil, o.traceErr(err) } if a != nil { var x int64 x, err = types.ToBool(a) if err != nil { return nil, o.traceErr(err) } else if x == 0 { // false && any other types is false return x, nil } } b, err := o.R.Eval(ctx, args) if err != nil { return nil, o.traceErr(err) } if b != nil { var y int64 y, err = types.ToBool(b) if err != nil { return nil, o.traceErr(err) } else if y == 0 { return y, nil } } // here x and y are all not false // if a or b is nil if a == nil || b == nil { return nil, nil } return int64(1), nil }
// EvalBool evalueates an expression to a boolean value. func EvalBool(ctx context.Context, expr ast.ExprNode) (bool, error) { val, err := Eval(ctx, expr) if err != nil { return false, errors.Trace(err) } if val == nil { return false, nil } i, err := types.ToBool(val) if err != nil { return false, errors.Trace(err) } return i != 0, nil }
// EvalBoolExpr evaluates an expression and convert its return value to bool. func EvalBoolExpr(ctx context.Context, expr expression.Expression, m map[interface{}]interface{}) (bool, error) { val, err := expr.Eval(ctx, m) if err != nil { return false, err } if val == nil { return false, nil } x, err := types.ToBool(val) if err != nil { return false, err } return x != 0, nil }
func (e *Evaluator) isTruth(v *ast.IsTruthExpr) bool { var boolVal bool val := v.Expr.GetValue() if !types.IsNil(val) { ival, err := types.ToBool(val) if err != nil { e.err = errors.Trace(err) return false } if ival == v.True { boolVal = true } } if v.Not { boolVal = !boolVal } v.SetValue(boolToInt64(boolVal)) return true }
// Check if satisified the target condition. // If satisified, the second returned value is true. func (w *WhenClause) evalAndCheck(ctx context.Context, args map[interface{}]interface{}, target interface{}) (interface{}, bool, error) { o := NewBinaryOperation(opcode.EQ, &Value{target}, w.Expr) // types.Compare wil return true/false for NULL // We must use BinaryOperation with opcode.Eq eq, err := o.Eval(ctx, args) if err != nil { return nil, false, err } if eq == nil { return nil, false, err } beq, err := types.ToBool(eq) if beq == 0 || err != nil { return nil, false, err } rv, err := w.Result.Eval(ctx, args) return rv, true, err }
func checkArgs(args ...interface{}) error { for i, v := range args { switch v.(type) { case bool: // We do not handle bool as int8 in tidb. vv, err := types.ToBool(v) if err != nil { return errors.Trace(err) } args[i] = vv case nil, float32, float64, string, int8, int16, int32, int64, int, uint8, uint16, uint32, uint64, uint, []byte, time.Duration, time.Time: default: return errors.Errorf("cannot use arg[%d] (type %T):unsupported type", i, v) } } return nil }
func (r *WhereRset) planStatic(ctx context.Context, e expression.Expression) (plan.Plan, error) { val, err := e.Eval(nil, nil) if err != nil { return nil, err } if val == nil { // like `select * from t where null`. return &plans.NullPlan{Fields: r.Src.GetFields()}, nil } n, err := types.ToBool(val) if err != nil { return nil, err } if n == 0 { // like `select * from t where 0`. return &plans.NullPlan{Fields: r.Src.GetFields()}, nil } return &plans.FilterDefaultPlan{Plan: r.Src, Expr: e}, nil }
// See https://dev.mysql.com/doc/refman/5.7/en/control-flow-functions.html#function_if func builtinIf(args []interface{}, m map[interface{}]interface{}) (interface{}, error) { // if(expr1, expr2, expr3) // if expr1 is true, return expr2, otherwise, return expr3 v1 := args[0] v2 := args[1] v3 := args[2] if types.IsNil(v1) { return v3, nil } b, err := types.ToBool(v1) if err != nil { return nil, err } // TODO: check return type, must be numeric or string if b == 1 { return v2, nil } return v3, nil }
func (s *testBinOpSuite) TestComparisonOp(c *C) { tbl := []struct { lhs interface{} op opcode.Op rhs interface{} result int8 // 0 for false, 1 for true }{ // test EQ {1, opcode.EQ, 2, 0}, {false, opcode.EQ, false, 1}, {false, opcode.EQ, true, 0}, {true, opcode.EQ, true, 1}, {true, opcode.EQ, false, 0}, {"1", opcode.EQ, true, 1}, {"1", opcode.EQ, false, 0}, // test NEQ {1, opcode.NE, 2, 1}, {false, opcode.NE, false, 0}, {false, opcode.NE, true, 1}, {true, opcode.NE, true, 0}, {"1", opcode.NE, true, 0}, {"1", opcode.NE, false, 1}, // test GT, GE {1, opcode.GT, 0, 1}, {1, opcode.GT, 1, 0}, {1, opcode.GE, 1, 1}, {3.14, opcode.GT, 3, 1}, {3.14, opcode.GE, 3.14, 1}, // test LT, LE {1, opcode.LT, 2, 1}, {1, opcode.LT, 1, 0}, {1, opcode.LE, 1, 1}, } for _, t := range tbl { expr := NewBinaryOperation(t.op, Value{t.lhs}, Value{t.rhs}) v, err := expr.Eval(nil, nil) c.Assert(err, IsNil) val, err := types.ToBool(v) c.Assert(err, IsNil) c.Assert(val, Equals, t.result) } // test nil nilTbl := []struct { lhs interface{} op opcode.Op rhs interface{} }{ {nil, opcode.EQ, nil}, {nil, opcode.EQ, 1}, {nil, opcode.NE, nil}, {nil, opcode.NE, 1}, {nil, opcode.LT, nil}, {nil, opcode.LT, 1}, {nil, opcode.LE, nil}, {nil, opcode.LE, 1}, {nil, opcode.GT, nil}, {nil, opcode.GT, 1}, {nil, opcode.GE, nil}, {nil, opcode.GE, 1}, } for _, t := range nilTbl { expr := NewBinaryOperation(t.op, Value{t.lhs}, Value{t.rhs}) v, err := expr.Eval(nil, nil) c.Assert(err, IsNil) c.Assert(v, IsNil) } // test evalCompare function cmpTbl := []struct { lhs interface{} rhs interface{} ret int // 0, 1, -1 }{ {float64(1), float64(1), 0}, {float64(1), "1", 0}, {int64(1), int64(1), 0}, {int64(-1), uint64(1), -1}, {int64(-1), "-1", 0}, {uint64(1), uint64(1), 0}, {uint64(1), int64(-1), 1}, {uint64(1), "1", 0}, {mysql.NewDecimalFromInt(1, 0), mysql.NewDecimalFromInt(1, 0), 0}, {mysql.NewDecimalFromInt(1, 0), "1", 0}, {"1", "1", 0}, {"1", int64(-1), 1}, {"1", float64(2), -1}, {"1", uint64(1), 0}, {"1", mysql.NewDecimalFromInt(1, 0), 0}, {"2011-01-01 11:11:11", mysql.Time{time.Now(), mysql.TypeDatetime, 0}, -1}, {"12:00:00", mysql.ZeroDuration, 1}, {mysql.ZeroDuration, mysql.ZeroDuration, 0}, {mysql.Time{time.Now().Add(time.Second * 10), mysql.TypeDatetime, 0}, mysql.Time{time.Now(), mysql.TypeDatetime, 0}, 1}, } for _, t := range cmpTbl { ret, err := evalCompare(t.lhs, t.rhs) c.Assert(err, IsNil) c.Assert(ret, Equals, t.ret) ret, err = evalCompare(t.rhs, t.lhs) c.Assert(err, IsNil) c.Assert(ret, Equals, -t.ret) } // test error mock := mockExpr{ isStatic: false, err: errors.New("must error"), } errTbl := []struct { arg interface{} op opcode.Op }{ {1, opcode.EQ}, {1.1, opcode.NE}, {mysql.NewDecimalFromInt(1, 0), opcode.LT}, {1, opcode.LE}, {1.1, opcode.GT}, {1, opcode.GE}, } for _, t := range errTbl { expr := NewBinaryOperation(t.op, Value{t.arg}, mock) _, err := expr.Eval(nil, nil) c.Assert(err, NotNil) _, err = expr.Clone() c.Assert(err, NotNil) expr = NewBinaryOperation(t.op, mock, Value{t.arg}) _, err = expr.Eval(nil, nil) c.Assert(err, NotNil) _, err = expr.Clone() c.Assert(err, NotNil) } mock.err = nil mock.val = "abc" for _, t := range errTbl { expr := NewBinaryOperation(t.op, Value{t.arg}, mock) _, err := expr.Eval(nil, nil) c.Assert(err, NotNil) expr = NewBinaryOperation(t.op, mock, Value{t.arg}) _, err = expr.Eval(nil, nil) c.Assert(err, NotNil) } expr := BinaryOperation{Op: opcode.Plus, L: Value{1}, R: Value{1}} _, err := expr.evalComparisonOp(nil, nil) c.Assert(err, NotNil) _, err = evalCompare(1, 1) c.Assert(err, NotNil) }
func (s *testCompSubQuerySuite) TestCompSubQuery(c *C) { tbl := []struct { lhs interface{} op opcode.Op rhs []interface{} all bool result interface{} // 0 for false, 1 for true, nil for nil. }{ // Test any subquery. {nil, opcode.EQ, []interface{}{1, 2}, false, nil}, {0, opcode.EQ, []interface{}{1, 2}, false, 0}, {0, opcode.EQ, []interface{}{1, 2, nil}, false, nil}, {1, opcode.EQ, []interface{}{1, 1}, false, 1}, {1, opcode.EQ, []interface{}{1, 1, nil}, false, 1}, {nil, opcode.NE, []interface{}{1, 2}, false, nil}, {1, opcode.NE, []interface{}{1, 2}, false, 1}, {1, opcode.NE, []interface{}{1, 2, nil}, false, 1}, {1, opcode.NE, []interface{}{1, 1}, false, 0}, {1, opcode.NE, []interface{}{1, 1, nil}, false, nil}, {nil, opcode.GT, []interface{}{1, 2}, false, nil}, {1, opcode.GT, []interface{}{1, 2}, false, 0}, {1, opcode.GT, []interface{}{1, 2, nil}, false, nil}, {2, opcode.GT, []interface{}{1, 2}, false, 1}, {2, opcode.GT, []interface{}{1, 2, nil}, false, 1}, {3, opcode.GT, []interface{}{1, 2}, false, 1}, {3, opcode.GT, []interface{}{1, 2, nil}, false, 1}, {nil, opcode.GE, []interface{}{1, 2}, false, nil}, {0, opcode.GE, []interface{}{1, 2}, false, 0}, {0, opcode.GE, []interface{}{1, 2, nil}, false, nil}, {1, opcode.GE, []interface{}{1, 2}, false, 1}, {1, opcode.GE, []interface{}{1, 2, nil}, false, 1}, {2, opcode.GE, []interface{}{1, 2}, false, 1}, {3, opcode.GE, []interface{}{1, 2}, false, 1}, {nil, opcode.LT, []interface{}{1, 2}, false, nil}, {0, opcode.LT, []interface{}{1, 2}, false, 1}, {0, opcode.LT, []interface{}{1, 2, nil}, false, 1}, {1, opcode.LT, []interface{}{1, 2}, false, 1}, {2, opcode.LT, []interface{}{1, 2}, false, 0}, {2, opcode.LT, []interface{}{1, 2, nil}, false, nil}, {3, opcode.LT, []interface{}{1, 2}, false, 0}, {nil, opcode.LE, []interface{}{1, 2}, false, nil}, {0, opcode.LE, []interface{}{1, 2}, false, 1}, {0, opcode.LE, []interface{}{1, 2, nil}, false, 1}, {1, opcode.LE, []interface{}{1, 2}, false, 1}, {2, opcode.LE, []interface{}{1, 2}, false, 1}, {3, opcode.LE, []interface{}{1, 2}, false, 0}, {3, opcode.LE, []interface{}{1, 2, nil}, false, nil}, // Test all subquery. {nil, opcode.EQ, []interface{}{1, 2}, true, nil}, {0, opcode.EQ, []interface{}{1, 2}, true, 0}, {0, opcode.EQ, []interface{}{1, 2, nil}, true, 0}, {1, opcode.EQ, []interface{}{1, 2}, true, 0}, {1, opcode.EQ, []interface{}{1, 2, nil}, true, 0}, {1, opcode.EQ, []interface{}{1, 1}, true, 1}, {1, opcode.EQ, []interface{}{1, 1, nil}, true, nil}, {nil, opcode.NE, []interface{}{1, 2}, true, nil}, {0, opcode.NE, []interface{}{1, 2}, true, 1}, {1, opcode.NE, []interface{}{1, 2, nil}, true, 0}, {1, opcode.NE, []interface{}{1, 1}, true, 0}, {1, opcode.NE, []interface{}{1, 1, nil}, true, 0}, {nil, opcode.GT, []interface{}{1, 2}, true, nil}, {1, opcode.GT, []interface{}{1, 2}, true, 0}, {1, opcode.GT, []interface{}{1, 2, nil}, true, 0}, {2, opcode.GT, []interface{}{1, 2}, true, 0}, {2, opcode.GT, []interface{}{1, 2, nil}, true, 0}, {3, opcode.GT, []interface{}{1, 2}, true, 1}, {3, opcode.GT, []interface{}{1, 2, nil}, true, nil}, {nil, opcode.GE, []interface{}{1, 2}, true, nil}, {0, opcode.GE, []interface{}{1, 2}, true, 0}, {0, opcode.GE, []interface{}{1, 2, nil}, true, 0}, {1, opcode.GE, []interface{}{1, 2}, true, 0}, {1, opcode.GE, []interface{}{1, 2, nil}, true, 0}, {2, opcode.GE, []interface{}{1, 2}, true, 1}, {3, opcode.GE, []interface{}{1, 2}, true, 1}, {3, opcode.GE, []interface{}{1, 2, nil}, true, nil}, {nil, opcode.LT, []interface{}{1, 2}, true, nil}, {0, opcode.LT, []interface{}{1, 2}, true, 1}, {0, opcode.LT, []interface{}{1, 2, nil}, true, nil}, {1, opcode.LT, []interface{}{1, 2}, true, 0}, {2, opcode.LT, []interface{}{1, 2}, true, 0}, {2, opcode.LT, []interface{}{1, 2, nil}, true, 0}, {3, opcode.LT, []interface{}{1, 2}, true, 0}, {nil, opcode.LE, []interface{}{1, 2}, true, nil}, {0, opcode.LE, []interface{}{1, 2}, true, 1}, {0, opcode.LE, []interface{}{1, 2, nil}, true, nil}, {1, opcode.LE, []interface{}{1, 2}, true, 1}, {2, opcode.LE, []interface{}{1, 2}, true, 0}, {3, opcode.LE, []interface{}{1, 2}, true, 0}, {3, opcode.LE, []interface{}{1, 2, nil}, true, 0}, } for _, t := range tbl { lhs := convert(t.lhs) rhs := make([][]interface{}, 0, len(t.rhs)) for _, v := range t.rhs { rhs = append(rhs, []interface{}{convert(v)}) } sq := newMockSubQuery(rhs, []string{"c"}) expr := NewCompareSubQuery(t.op, Value{lhs}, sq, t.all) c.Assert(expr.IsStatic(), IsFalse) str := expr.String() c.Assert(len(str), Greater, 0) v, err := expr.Eval(nil, nil) c.Assert(err, IsNil) switch x := t.result.(type) { case nil: c.Assert(v, IsNil) case int: val, err := types.ToBool(v) c.Assert(err, IsNil) c.Assert(val, Equals, int64(x)) } } // Test error. sq := newMockSubQuery([][]interface{}{{1, 2}}, []string{"c1", "c2"}) expr := NewCompareSubQuery(opcode.EQ, Value{1}, sq, true) _, err := expr.Eval(nil, nil) c.Assert(err, NotNil) expr = NewCompareSubQuery(opcode.EQ, Value{1}, sq, false) _, err = expr.Eval(nil, nil) c.Assert(err, NotNil) }
func (e *Evaluator) unaryOperation(u *ast.UnaryOperationExpr) bool { defer func() { if er := recover(); er != nil { e.err = errors.Errorf("%v", er) } }() a := u.V.GetValue() a = types.RawData(a) if a == nil { u.SetValue(nil) return true } switch op := u.Op; op { case opcode.Not: n, err := types.ToBool(a) if err != nil { e.err = errors.Trace(err) } else if n == 0 { u.SetValue(int64(1)) } else { u.SetValue(int64(0)) } case opcode.BitNeg: // for bit operation, we will use int64 first, then return uint64 n, err := types.ToInt64(a) if err != nil { e.err = errors.Trace(err) return false } u.SetValue(uint64(^n)) case opcode.Plus: switch x := a.(type) { case bool: u.SetValue(boolToInt64(x)) case float32: u.SetValue(+x) case float64: u.SetValue(+x) case int: u.SetValue(+x) case int8: u.SetValue(+x) case int16: u.SetValue(+x) case int32: u.SetValue(+x) case int64: u.SetValue(+x) case uint: u.SetValue(+x) case uint8: u.SetValue(+x) case uint16: u.SetValue(+x) case uint32: u.SetValue(+x) case uint64: u.SetValue(+x) case mysql.Duration: u.SetValue(x) case mysql.Time: u.SetValue(x) case string: u.SetValue(x) case mysql.Decimal: u.SetValue(x) case []byte: u.SetValue(x) case mysql.Hex: u.SetValue(x) case mysql.Bit: u.SetValue(x) case mysql.Enum: u.SetValue(x) case mysql.Set: u.SetValue(x) default: e.err = ErrInvalidOperation return false } case opcode.Minus: switch x := a.(type) { case bool: if x { u.SetValue(int64(-1)) } else { u.SetValue(int64(0)) } case float32: u.SetValue(-x) case float64: u.SetValue(-x) case int: u.SetValue(-x) case int8: u.SetValue(-x) case int16: u.SetValue(-x) case int32: u.SetValue(-x) case int64: u.SetValue(-x) case uint: u.SetValue(-int64(x)) case uint8: u.SetValue(-int64(x)) case uint16: u.SetValue(-int64(x)) case uint32: u.SetValue(-int64(x)) case uint64: // TODO: check overflow and do more test for unsigned type u.SetValue(-int64(x)) case mysql.Duration: u.SetValue(mysql.ZeroDecimal.Sub(x.ToNumber())) case mysql.Time: u.SetValue(mysql.ZeroDecimal.Sub(x.ToNumber())) case string: f, err := types.StrToFloat(x) e.err = errors.Trace(err) u.SetValue(-f) case mysql.Decimal: f, _ := x.Float64() u.SetValue(mysql.NewDecimalFromFloat(-f)) case []byte: f, err := types.StrToFloat(string(x)) e.err = errors.Trace(err) u.SetValue(-f) case mysql.Hex: u.SetValue(-x.ToNumber()) case mysql.Bit: u.SetValue(-x.ToNumber()) case mysql.Enum: u.SetValue(-x.ToNumber()) case mysql.Set: u.SetValue(-x.ToNumber()) default: e.err = ErrInvalidOperation return false } default: e.err = ErrInvalidOperation return false } return true }
func (s *testEvaluatorSuite) TestBinopComparison(c *C) { ctx := mock.NewContext() tbl := []struct { lhs interface{} op opcode.Op rhs interface{} result int64 // 0 for false, 1 for true }{ // test EQ {1, opcode.EQ, 2, 0}, {false, opcode.EQ, false, 1}, {false, opcode.EQ, true, 0}, {true, opcode.EQ, true, 1}, {true, opcode.EQ, false, 0}, {"1", opcode.EQ, true, 1}, {"1", opcode.EQ, false, 0}, // test NEQ {1, opcode.NE, 2, 1}, {false, opcode.NE, false, 0}, {false, opcode.NE, true, 1}, {true, opcode.NE, true, 0}, {"1", opcode.NE, true, 0}, {"1", opcode.NE, false, 1}, // test GT, GE {1, opcode.GT, 0, 1}, {1, opcode.GT, 1, 0}, {1, opcode.GE, 1, 1}, {3.14, opcode.GT, 3, 1}, {3.14, opcode.GE, 3.14, 1}, // test LT, LE {1, opcode.LT, 2, 1}, {1, opcode.LT, 1, 0}, {1, opcode.LE, 1, 1}, } for _, t := range tbl { expr := &ast.BinaryOperationExpr{Op: t.op, L: ast.NewValueExpr(t.lhs), R: ast.NewValueExpr(t.rhs)} v, err := Eval(ctx, expr) c.Assert(err, IsNil) val, err := types.ToBool(v) c.Assert(err, IsNil) c.Assert(val, Equals, t.result) } // test nil nilTbl := []struct { lhs interface{} op opcode.Op rhs interface{} }{ {nil, opcode.EQ, nil}, {nil, opcode.EQ, 1}, {nil, opcode.NE, nil}, {nil, opcode.NE, 1}, {nil, opcode.LT, nil}, {nil, opcode.LT, 1}, {nil, opcode.LE, nil}, {nil, opcode.LE, 1}, {nil, opcode.GT, nil}, {nil, opcode.GT, 1}, {nil, opcode.GE, nil}, {nil, opcode.GE, 1}, } for _, t := range nilTbl { expr := &ast.BinaryOperationExpr{Op: t.op, L: ast.NewValueExpr(t.lhs), R: ast.NewValueExpr(t.rhs)} v, err := Eval(ctx, expr) c.Assert(err, IsNil) c.Assert(v, IsNil) } }
func (s *testExistsSubQuerySuite) TestExistsSubQuery(c *C) { // Test exists subquery. tbl := []struct { in []interface{} result int64 // 0 for false, 1 for true. }{ {[]interface{}{1}, 1}, {[]interface{}{nil}, 1}, {[]interface{}{}, 0}, } ctx := mock.NewContext() for _, t := range tbl { in := make([][]interface{}, 0, len(t.in)) for _, v := range t.in { in = append(in, []interface{}{convert(v)}) } sq := newMockSubQuery(in, []string{"c"}) expr := expression.NewExistsSubQuery(sq) c.Assert(expr.IsStatic(), IsFalse) exprc := expr.Clone() c.Assert(exprc, NotNil) str := exprc.String() c.Assert(len(str), Greater, 0) v, err := exprc.Eval(ctx, nil) c.Assert(err, IsNil) val, err := types.ToBool(v) c.Assert(err, IsNil) c.Assert(val, Equals, t.result) // test cache v, err = exprc.Eval(ctx, nil) c.Assert(err, IsNil) val, err = types.ToBool(v) c.Assert(err, IsNil) c.Assert(val, Equals, t.result) } // Test not exists subquery. tbl = []struct { in []interface{} result int64 // 0 for false, 1 for true. }{ {[]interface{}{1}, 0}, {[]interface{}{nil}, 0}, {[]interface{}{}, 1}, } for _, t := range tbl { in := make([][]interface{}, 0, len(t.in)) for _, v := range t.in { in = append(in, []interface{}{convert(v)}) } sq := newMockSubQuery(in, []string{"c"}) es := expression.NewExistsSubQuery(sq) c.Assert(es.IsStatic(), IsFalse) str := es.String() c.Assert(len(str), Greater, 0) expr := expression.NewUnaryOperation(opcode.Not, es) exprc := expr.Clone() c.Assert(exprc, NotNil) str = exprc.String() c.Assert(len(str), Greater, 0) v, err := exprc.Eval(ctx, nil) c.Assert(err, IsNil) val, err := types.ToBool(v) c.Assert(err, IsNil) c.Assert(val, Equals, t.result) } }
func (s *testBetweenSuite) TestBetween(c *C) { table := []struct { Expr expression.Expression Left int Right int Not bool Result int64 // 0 for false, 1 for true }{ {Value{1}, 2, 3, false, 0}, {Value{1}, 2, 3, true, 1}, {&Call{ F: "count", Args: []expression.Expression{Value{1}}, }, 2, 3, false, 0}, {&Call{ F: "count", Args: []expression.Expression{Value{1}}, }, 2, 3, true, 1}, } m := map[interface{}]interface{}{ ExprEvalArgAggEmpty: struct{}{}, } for _, t := range table { b, err := NewBetween(t.Expr, Value{t.Left}, Value{t.Right}, t.Not) c.Assert(err, IsNil) c.Assert(len(b.String()), Greater, 0) _, err = b.Clone() c.Assert(err, IsNil) c.Assert(b.IsStatic(), Equals, !ContainAggregateFunc(t.Expr)) v, err := b.Eval(nil, m) val, err := types.ToBool(v) c.Assert(err, IsNil) c.Assert(val, Equals, t.Result) } f := func(isErr bool) expression.Expression { if isErr { return mockExpr{isStatic: true, err: errors.New("test error")} } return mockExpr{isStatic: true, err: nil} } tableError := []struct { Expr expression.Expression Left expression.Expression Right expression.Expression }{ {f(true), f(false), f(false)}, {f(false), f(true), f(false)}, {f(false), f(false), f(true)}, } for _, t := range tableError { _, err := NewBetween(t.Expr, t.Left, t.Right, false) c.Assert(err, NotNil) b := Between{Expr: t.Expr, Left: t.Left, Right: t.Right, Not: false} _, err = b.Clone() c.Assert(err, NotNil) _, err = b.Eval(nil, nil) c.Assert(err, NotNil) } tableError = []struct { Expr expression.Expression Left expression.Expression Right expression.Expression }{ {newTestRow(1, 2), f(false), f(false)}, {f(false), newTestRow(1, 2), f(false)}, {f(false), f(false), newTestRow(1, 2)}, } for _, t := range tableError { _, err := NewBetween(t.Expr, t.Left, t.Right, false) c.Assert(err, NotNil) b := Between{Expr: t.Expr, Left: t.Left, Right: t.Right, Not: false} _, err = b.Eval(nil, nil) c.Assert(err, NotNil) } }
// Eval implements the Expression Eval interface. func (u *UnaryOperation) Eval(ctx context.Context, args map[interface{}]interface{}) (r interface{}, err error) { defer func() { if e := recover(); e != nil { r, err = nil, errors.Errorf("%v", e) } }() switch op := u.Op; op { case opcode.Not: a := Eval(u.V, ctx, args) if a == nil { return } n, err := types.ToBool(a) if err != nil { return types.UndOp(a, op) } else if n == 0 { return int8(1), nil } return int8(0), nil case opcode.BitNeg: a := Eval(u.V, ctx, args) if a == nil { return } // for bit operation, we will use int64 first, then return uint64 n, err := types.ToInt64(a) if err != nil { return types.UndOp(a, op) } return uint64(^n), nil case opcode.Plus: a := Eval(u.V, ctx, args) switch x := a.(type) { case nil: return nil, nil case float32: return +x, nil case float64: return +x, nil case int: return +x, nil case int8: return +x, nil case int16: return +x, nil case int32: return +x, nil case int64: return +x, nil case uint: return +x, nil case uint8: return +x, nil case uint16: return +x, nil case uint32: return +x, nil case uint64: return +x, nil case mysql.Duration: return x, nil case mysql.Time: return x, nil case string: return x, nil case mysql.Decimal: return x, nil default: return types.UndOp(a, op) } case opcode.Minus: a := Eval(u.V, ctx, args) switch x := a.(type) { case nil: return nil, nil case float32: return -x, nil case float64: return -x, nil case int: return -x, nil case int8: return -x, nil case int16: return -x, nil case int32: return -x, nil case int64: return -x, nil case uint: return -int64(x), nil case uint8: return -int64(x), nil case uint16: return -int64(x), nil case uint32: return -int64(x), nil case uint64: // TODO: check overflow and do more test for unsigned type return -int64(x), nil case mysql.Duration: return mysql.ZeroDecimal.Sub(x.ToNumber()), nil case mysql.Time: return mysql.ZeroDecimal.Sub(x.ToNumber()), nil case string: f, err := types.StrToFloat(x) return -f, err case mysql.Decimal: f, _ := x.Float64() return mysql.NewDecimalFromFloat(-f), nil default: return types.UndOp(a, op) } default: panic("should never happen") } }
func (s *testBinOpSuite) TestComparisonOp(c *C) { tbl := []struct { lhs interface{} op opcode.Op rhs interface{} result int64 // 0 for false, 1 for true }{ // test EQ {1, opcode.EQ, 2, 0}, {false, opcode.EQ, false, 1}, {false, opcode.EQ, true, 0}, {true, opcode.EQ, true, 1}, {true, opcode.EQ, false, 0}, {"1", opcode.EQ, true, 1}, {"1", opcode.EQ, false, 0}, // test NEQ {1, opcode.NE, 2, 1}, {false, opcode.NE, false, 0}, {false, opcode.NE, true, 1}, {true, opcode.NE, true, 0}, {"1", opcode.NE, true, 0}, {"1", opcode.NE, false, 1}, // test GT, GE {1, opcode.GT, 0, 1}, {1, opcode.GT, 1, 0}, {1, opcode.GE, 1, 1}, {3.14, opcode.GT, 3, 1}, {3.14, opcode.GE, 3.14, 1}, // test LT, LE {1, opcode.LT, 2, 1}, {1, opcode.LT, 1, 0}, {1, opcode.LE, 1, 1}, } for _, t := range tbl { expr := NewBinaryOperation(t.op, Value{t.lhs}, Value{t.rhs}) v, err := expr.Eval(nil, nil) c.Assert(err, IsNil) val, err := types.ToBool(v) c.Assert(err, IsNil) c.Assert(val, Equals, t.result) } // test nil nilTbl := []struct { lhs interface{} op opcode.Op rhs interface{} }{ {nil, opcode.EQ, nil}, {nil, opcode.EQ, 1}, {nil, opcode.NE, nil}, {nil, opcode.NE, 1}, {nil, opcode.LT, nil}, {nil, opcode.LT, 1}, {nil, opcode.LE, nil}, {nil, opcode.LE, 1}, {nil, opcode.GT, nil}, {nil, opcode.GT, 1}, {nil, opcode.GE, nil}, {nil, opcode.GE, 1}, } for _, t := range nilTbl { expr := NewBinaryOperation(t.op, Value{t.lhs}, Value{t.rhs}) v, err := expr.Eval(nil, nil) c.Assert(err, IsNil) c.Assert(v, IsNil) } // test error mock := mockExpr{ isStatic: false, err: errors.New("must error"), } errTbl := []struct { arg interface{} op opcode.Op }{ {1, opcode.EQ}, {1.1, opcode.NE}, {mysql.NewDecimalFromInt(1, 0), opcode.LT}, {1, opcode.LE}, {1.1, opcode.GT}, {1, opcode.GE}, } for _, t := range errTbl { expr := NewBinaryOperation(t.op, Value{t.arg}, mock) _, err := expr.Eval(nil, nil) c.Assert(err, NotNil) _, err = expr.Clone() c.Assert(err, NotNil) expr = NewBinaryOperation(t.op, mock, Value{t.arg}) _, err = expr.Eval(nil, nil) c.Assert(err, NotNil) _, err = expr.Clone() c.Assert(err, NotNil) } mock.err = nil mock.val = "abc" for _, t := range errTbl { expr := NewBinaryOperation(t.op, Value{t.arg}, mock) _, err := expr.Eval(nil, nil) c.Assert(err, NotNil) expr = NewBinaryOperation(t.op, mock, Value{t.arg}) _, err = expr.Eval(nil, nil) c.Assert(err, NotNil) } expr := BinaryOperation{Op: opcode.Plus, L: Value{1}, R: Value{1}} _, err := expr.evalComparisonOp(nil, nil) c.Assert(err, NotNil) }