func arithmeticFuncFactory(op opcode.Op) BuiltinFunc { return func(args []types.Datum, _ context.Context) (d types.Datum, err error) { a, err := types.CoerceArithmetic(args[0]) if err != nil { return d, errors.Trace(err) } b, err := types.CoerceArithmetic(args[1]) if err != nil { return d, errors.Trace(err) } a, b = types.CoerceDatum(a, b) if a.IsNull() || b.IsNull() { return } switch op { case opcode.Plus: return types.ComputePlus(a, b) case opcode.Minus: return types.ComputeMinus(a, b) case opcode.Mul: return types.ComputeMul(a, b) case opcode.Div: return types.ComputeDiv(a, b) case opcode.Mod: return types.ComputeMod(a, b) case opcode.IntDiv: return types.ComputeIntDiv(a, b) default: return d, ErrInvalidOperation.Gen("invalid op %v in arithmetic operation", op) } } }
// ComputeBit computes the bitwise operation on two datums. func ComputeBit(op tipb.ExprType, left, right types.Datum) (types.Datum, error) { var result types.Datum a, err := types.CoerceArithmetic(left) if err != nil { return result, errors.Trace(err) } b, err := types.CoerceArithmetic(right) if err != nil { return result, errors.Trace(err) } a, b, err = types.CoerceDatum(a, b) if err != nil { return result, errors.Trace(err) } if a.IsNull() || b.IsNull() { return result, nil } switch op { case tipb.ExprType_BitAnd: return types.ComputeBitAnd(a, b) case tipb.ExprType_BitOr: return types.ComputeBitOr(a, b) case tipb.ExprType_BitXor: return types.ComputeBitXor(a, b) case tipb.ExprType_LeftShift: return types.ComputeLeftShift(a, b) case tipb.ExprType_RighShift: return types.ComputeRightShift(a, b) default: return result, errors.Errorf("Unknown binop type: %v", op) } }
// See http://dev.mysql.com/doc/refman/5.7/en/any-in-some-subqueries.html func builtinIn(args []types.Datum, _ context.Context) (d types.Datum, err error) { if args[0].IsNull() { return } var hasNull bool for _, v := range args[1:] { if v.IsNull() { hasNull = true continue } a, b := types.CoerceDatum(args[0], v) ret, err := a.CompareDatum(b) if err != nil { return d, errors.Trace(err) } if ret == 0 { d.SetInt64(1) return d, nil } } if hasNull { // If it's no matched but we get null in In, returns null. // e.g 1 in (null, 2, 3) returns null. return } d.SetInt64(0) return }
func bitOpFactory(op opcode.Op) BuiltinFunc { return func(args []types.Datum, _ context.Context) (d types.Datum, err error) { a, b := types.CoerceDatum(args[0], args[1]) if a.IsNull() || b.IsNull() { return } x, err := a.ToInt64() if err != nil { return d, errors.Trace(err) } y, err := b.ToInt64() if err != nil { return d, errors.Trace(err) } // use a int64 for bit operator, return uint64 switch op { case opcode.And: d.SetUint64(uint64(x & y)) case opcode.Or: d.SetUint64(uint64(x | y)) case opcode.Xor: d.SetUint64(uint64(x ^ y)) case opcode.RightShift: d.SetUint64(uint64(x) >> uint64(y)) case opcode.LeftShift: d.SetUint64(uint64(x) << uint64(y)) default: return d, ErrInvalidOperation.Gen("invalid op %v in bit operation", op) } return } }
// ComputeArithmetic computes the arithmetic operation on two datums. func ComputeArithmetic(op tipb.ExprType, left types.Datum, right types.Datum) (types.Datum, error) { var result types.Datum a, err := types.CoerceArithmetic(left) if err != nil { return result, errors.Trace(err) } b, err := types.CoerceArithmetic(right) if err != nil { return result, errors.Trace(err) } a, b = types.CoerceDatum(a, b) if a.IsNull() || b.IsNull() { return result, nil } switch op { case tipb.ExprType_Plus: return types.ComputePlus(a, b) case tipb.ExprType_Div: return types.ComputeDiv(a, b) default: return result, errors.Errorf("Unknown binop type: %v", op) } }
func (e *Evaluator) evalArithmetic(expr *tipb.Expr) (types.Datum, error) { var result types.Datum left, right, err := e.evalTwoChildren(expr) if err != nil { return result, errors.Trace(err) } a, err := types.CoerceArithmetic(left) if err != nil { return result, errors.Trace(err) } b, err := types.CoerceArithmetic(right) if err != nil { return result, errors.Trace(err) } a, b = types.CoerceDatum(a, b) if a.IsNull() || b.IsNull() { return result, nil } switch expr.GetTp() { case tipb.ExprType_Plus: return types.ComputePlus(a, b) case tipb.ExprType_Div: return types.ComputeDiv(a, b) default: return result, errors.Errorf("Unknown binop type: %v", expr.GetTp()) } }
func compareFuncFactory(op opcode.Op) BuiltinFunc { return func(args []types.Datum, _ context.Context) (d types.Datum, err error) { var a, b = args[0], args[1] if op != opcode.NullEQ { a, b, err = types.CoerceDatum(a, b) if err != nil { return d, errors.Trace(err) } } if a.IsNull() || b.IsNull() { // for <=>, if a and b are both nil, return true. // if a or b is nil, return false. if op == opcode.NullEQ { if a.IsNull() && b.IsNull() { d.SetInt64(oneI64) } else { d.SetInt64(zeroI64) } } return } n, err := a.CompareDatum(b) if err != nil { return d, errors.Trace(err) } var result bool switch op { case opcode.LT: result = n < 0 case opcode.LE: result = n <= 0 case opcode.EQ, opcode.NullEQ: result = n == 0 case opcode.GT: result = n > 0 case opcode.GE: result = n >= 0 case opcode.NE: result = n != 0 default: return d, ErrInvalidOperation.Gen("invalid op %v in comparison operation", op) } if result { d.SetInt64(oneI64) } else { d.SetInt64(zeroI64) } return } }
func (e *Evaluator) handleComparisonOp(o *ast.BinaryOperationExpr) bool { var a, b = *o.L.GetDatum(), *o.R.GetDatum() var err error if o.Op != opcode.NullEQ { a, b, err = types.CoerceDatum(e.sc, *o.L.GetDatum(), *o.R.GetDatum()) if err != nil { e.err = errors.Trace(err) return false } } if a.IsNull() || b.IsNull() { // for <=>, if a and b are both nil, return true. // if a or b is nil, return false. if o.Op == opcode.NullEQ { if a.IsNull() && b.IsNull() { o.SetInt64(oneI64) } else { o.SetInt64(zeroI64) } } else { o.SetNull() } return true } n, err := a.CompareDatum(e.sc, b) if err != nil { e.err = errors.Trace(err) return false } r, err := getCompResult(o.Op, n) if err != nil { e.err = errors.Trace(err) return false } if r { o.SetInt64(oneI64) } else { o.SetInt64(zeroI64) } return true }
func (e *Evaluator) handleArithmeticOp(o *ast.BinaryOperationExpr) bool { a, err := types.CoerceArithmetic(e.sc, *o.L.GetDatum()) if err != nil { e.err = errors.Trace(err) return false } b, err := types.CoerceArithmetic(e.sc, *o.R.GetDatum()) if err != nil { e.err = errors.Trace(err) return false } a, b, err = types.CoerceDatum(e.sc, a, b) if err != nil { e.err = errors.Trace(err) return false } if a.IsNull() || b.IsNull() { o.SetNull() return true } var result types.Datum switch o.Op { case opcode.Plus: result, e.err = types.ComputePlus(a, b) case opcode.Minus: result, e.err = types.ComputeMinus(a, b) case opcode.Mul: result, e.err = types.ComputeMul(a, b) case opcode.Div: result, e.err = types.ComputeDiv(e.sc, a, b) case opcode.Mod: result, e.err = types.ComputeMod(e.sc, a, b) case opcode.IntDiv: result, e.err = types.ComputeIntDiv(e.sc, a, b) default: e.err = ErrInvalidOperation.Gen("invalid op %v in arithmetic operation", o.Op) return false } o.SetDatum(result) return e.err == nil }
func (e *Evaluator) handleBitOp(o *ast.BinaryOperationExpr) bool { a, b, err := types.CoerceDatum(e.sc, *o.L.GetDatum(), *o.R.GetDatum()) if err != nil { e.err = errors.Trace(err) return false } if a.IsNull() || b.IsNull() { o.SetNull() return true } x, err := a.ToInt64(e.sc) if err != nil { e.err = errors.Trace(err) return false } y, err := b.ToInt64(e.sc) if err != nil { e.err = errors.Trace(err) return false } // use a int64 for bit operator, return uint64 switch o.Op { case opcode.And: o.SetUint64(uint64(x & y)) case opcode.Or: o.SetUint64(uint64(x | y)) case opcode.Xor: o.SetUint64(uint64(x ^ y)) case opcode.RightShift: o.SetUint64(uint64(x) >> uint64(y)) case opcode.LeftShift: o.SetUint64(uint64(x) << uint64(y)) default: e.err = ErrInvalidOperation.Gen("invalid op %v in bit operation", o.Op) return false } return true }
func (e *Evaluator) checkInList(not bool, in types.Datum, list []types.Datum) (d types.Datum) { hasNull := false for _, v := range list { if v.IsNull() { hasNull = true continue } a, b, err := types.CoerceDatum(in, v) if err != nil { e.err = errors.Trace(err) return d } r, err := a.CompareDatum(b) if err != nil { e.err = errors.Trace(err) return d } if r == 0 { if !not { d.SetInt64(1) return d } d.SetInt64(0) return d } } if hasNull { // If no matched but we got null in In, return null. // e.g 1 in (null, 2, 3) returns null. return d } if not { d.SetInt64(1) return d } d.SetInt64(0) return d }
// ComputeArithmetic computes the arithmetic operation on two datums. func ComputeArithmetic(sc *variable.StatementContext, op tipb.ExprType, left types.Datum, right types.Datum) (types.Datum, error) { var result types.Datum a, err := types.CoerceArithmetic(sc, left) if err != nil { return result, errors.Trace(err) } b, err := types.CoerceArithmetic(sc, right) if err != nil { return result, errors.Trace(err) } a, b, err = types.CoerceDatum(sc, a, b) if err != nil { return result, errors.Trace(err) } if a.IsNull() || b.IsNull() { return result, nil } switch op { case tipb.ExprType_Plus: return types.ComputePlus(a, b) case tipb.ExprType_Div: return types.ComputeDiv(sc, a, b) case tipb.ExprType_Minus: return types.ComputeMinus(a, b) case tipb.ExprType_Mul: return types.ComputeMul(a, b) case tipb.ExprType_IntDiv: return types.ComputeIntDiv(sc, a, b) case tipb.ExprType_Mod: return types.ComputeMod(sc, a, b) default: return result, errors.Errorf("Unknown binop type: %v", op) } }