示例#1
0
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
}
示例#2
0
文件: binop.go 项目: nengwang/tidb
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
}
示例#3
0
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
}
示例#4
0
文件: istruth.go 项目: no2key/tidb
// 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
}
示例#5
0
文件: in.go 项目: szctop/tidb
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
}
示例#6
0
文件: where.go 项目: ninefive/tidb
// 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)
	})
}
示例#7
0
文件: binop.go 项目: nengwang/tidb
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
}
示例#8
0
文件: where.go 项目: hxiaodon/tidb
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
}
示例#9
0
文件: binop.go 项目: nengwang/tidb
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
}
示例#10
0
文件: evaluator.go 项目: mrtoms/tidb
// 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
}
示例#11
0
// 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
}
示例#12
0
文件: evaluator.go 项目: mrtoms/tidb
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
}
示例#13
0
文件: case.go 项目: kingland/tidb
// 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
}
示例#14
0
文件: session.go 项目: ninefive/tidb
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
}
示例#15
0
文件: where.go 项目: netroby/tidb
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
}
示例#16
0
文件: control.go 项目: lovedboy/tidb
// 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
}
示例#17
0
文件: binop_test.go 项目: npk/tidb
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)
}
示例#18
0
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)
}
示例#19
0
文件: evaluator.go 项目: mrtoms/tidb
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
}
示例#20
0
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)
	}
}
示例#21
0
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)
	}
}
示例#22
0
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)
	}
}
示例#23
0
文件: unary.go 项目: npk/tidb
// 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")
	}
}
示例#24
0
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)
}