// ConvertDatumToDecimal converts datum to decimal. func ConvertDatumToDecimal(d Datum) (mysql.Decimal, error) { switch d.Kind() { case KindInt64: return mysql.NewDecimalFromInt(d.GetInt64(), 0), nil case KindUint64: return mysql.NewDecimalFromUint(d.GetUint64(), 0), nil case KindFloat32: return mysql.NewDecimalFromFloat(float64(d.GetFloat32())), nil case KindFloat64: return mysql.NewDecimalFromFloat(d.GetFloat64()), nil case KindString: return mysql.ParseDecimal(d.GetString()) case KindMysqlDecimal: return d.GetMysqlDecimal(), nil case KindMysqlHex: return mysql.NewDecimalFromInt(int64(d.GetMysqlHex().Value), 0), nil case KindMysqlBit: return mysql.NewDecimalFromUint(uint64(d.GetMysqlBit().Value), 0), nil case KindMysqlEnum: return mysql.NewDecimalFromUint(uint64(d.GetMysqlEnum().Value), 0), nil case KindMysqlSet: return mysql.NewDecimalFromUint(uint64(d.GetMysqlSet().Value), 0), nil default: return mysql.Decimal{}, fmt.Errorf("can't convert %v to decimal", d.GetValue()) } }
func (s *testDecimalSuite) TestDecimalCodec(c *C) { inputs := []struct { Input float64 }{ {float64(123400)}, {float64(1234)}, {float64(12.34)}, {float64(0.1234)}, {float64(0.01234)}, {float64(-0.1234)}, {float64(-0.01234)}, {float64(12.3400)}, {float64(-12.34)}, {float64(0.00000)}, {float64(0)}, {float64(-0.0)}, {float64(-0.000)}, } for _, input := range inputs { v := mysql.NewDecimalFromFloat(input.Input) b := EncodeDecimal([]byte{}, v) _, d, err := DecodeDecimal(b) c.Assert(err, IsNil) c.Assert(v.Equals(d), IsTrue) } }
func (s *testDecimalSuite) TestFrac(c *C) { defer testleak.AfterTest(c)() inputs := []struct { Input mysql.Decimal }{ {mysql.NewDecimalFromInt(int64(3), 0)}, {mysql.NewDecimalFromFloat(float64(0.03))}, } for _, v := range inputs { testFrac(c, v.Input) } }
func (d *Datum) convertToMysqlDecimal(target *FieldType) (Datum, error) { var ret Datum var dec mysql.Decimal switch d.k { case KindInt64: dec = mysql.NewDecimalFromInt(d.GetInt64(), 0) case KindUint64: dec = mysql.NewDecimalFromUint(d.GetUint64(), 0) case KindFloat32, KindFloat64: dec = mysql.NewDecimalFromFloat(d.GetFloat64()) case KindString, KindBytes: var err error dec, err = mysql.ParseDecimal(d.GetString()) if err != nil { return ret, errors.Trace(err) } case KindMysqlDecimal: dec = d.GetMysqlDecimal() case KindMysqlTime: dec = d.GetMysqlTime().ToNumber() case KindMysqlDuration: dec = d.GetMysqlDuration().ToNumber() case KindMysqlBit: dec = mysql.NewDecimalFromFloat(d.GetMysqlBit().ToNumber()) case KindMysqlEnum: dec = mysql.NewDecimalFromFloat(d.GetMysqlEnum().ToNumber()) case KindMysqlHex: dec = mysql.NewDecimalFromFloat(d.GetMysqlHex().ToNumber()) case KindMysqlSet: dec = mysql.NewDecimalFromFloat(d.GetMysqlSet().ToNumber()) default: return invalidConv(d, target.Tp) } if target.Decimal != UnspecifiedLength { dec = dec.Round(int32(target.Decimal)) } ret.SetValue(dec) return ret, nil }
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 unaryOpFactory(op opcode.Op) BuiltinFunc { return func(args []types.Datum, _ context.Context) (d types.Datum, err error) { defer func() { if er := recover(); er != nil { err = errors.Errorf("%v", er) } }() aDatum := args[0] if aDatum.IsNull() { return } switch op { case opcode.Not: var n int64 n, err = aDatum.ToBool() if err != nil { err = errors.Trace(err) } else if n == 0 { d.SetInt64(1) } else { d.SetInt64(0) } case opcode.BitNeg: var n int64 // for bit operation, we will use int64 first, then return uint64 n, err = aDatum.ToInt64() if err != nil { return d, errors.Trace(err) } d.SetUint64(uint64(^n)) case opcode.Plus: switch aDatum.Kind() { case types.KindInt64, types.KindUint64, types.KindFloat64, types.KindFloat32, types.KindMysqlDuration, types.KindMysqlTime, types.KindString, types.KindMysqlDecimal, types.KindBytes, types.KindMysqlHex, types.KindMysqlBit, types.KindMysqlEnum, types.KindMysqlSet: d = aDatum default: return d, ErrInvalidOperation.Gen("Unsupported type %v for op.Plus", aDatum.Kind()) } case opcode.Minus: switch aDatum.Kind() { case types.KindInt64: d.SetInt64(-aDatum.GetInt64()) case types.KindUint64: d.SetInt64(-int64(aDatum.GetUint64())) case types.KindFloat64: d.SetFloat64(-aDatum.GetFloat64()) case types.KindFloat32: d.SetFloat32(-aDatum.GetFloat32()) case types.KindMysqlDuration: d.SetMysqlDecimal(mysql.ZeroDecimal.Sub(aDatum.GetMysqlDuration().ToNumber())) case types.KindMysqlTime: d.SetMysqlDecimal(mysql.ZeroDecimal.Sub(aDatum.GetMysqlTime().ToNumber())) case types.KindString, types.KindBytes: f, err1 := types.StrToFloat(aDatum.GetString()) err = errors.Trace(err1) d.SetFloat64(-f) case types.KindMysqlDecimal: f, _ := aDatum.GetMysqlDecimal().Float64() d.SetMysqlDecimal(mysql.NewDecimalFromFloat(-f)) case types.KindMysqlHex: d.SetFloat64(-aDatum.GetMysqlHex().ToNumber()) case types.KindMysqlBit: d.SetFloat64(-aDatum.GetMysqlBit().ToNumber()) case types.KindMysqlEnum: d.SetFloat64(-aDatum.GetMysqlEnum().ToNumber()) case types.KindMysqlSet: d.SetFloat64(-aDatum.GetMysqlSet().ToNumber()) default: return d, ErrInvalidOperation.Gen("Unsupported type %v for op.Minus", aDatum.Kind()) } default: return d, ErrInvalidOperation.Gen("Unsupported op %v for unary op", op) } return } }
func (s *testAggFuncSuite) TestXAPIAvg(c *C) { defer testleak.AfterTest(c)() // Compose aggregate exec for "select avg(c2) from t groupby c1"; // // Data in region1: // c1 c2 // 1 11 // 2 21 // 1 1 // 3 2 // // Partial aggregate result for region1: // groupkey cnt sum // 1 2 12 // 2 1 21 // 3 1 2 // // Data in region2: // 1 nil // 1 3 // 3 31 // // Partial aggregate result for region2: // groupkey cnt sum // 1 1 3 // 3 1 31 // // Expected final aggregate result: // avg(c2) // 5 // 21 // 16.500000 c1 := ast.NewValueExpr([]byte{0}) rf1 := &ast.ResultField{Expr: c1} c2 := ast.NewValueExpr(0) rf2 := &ast.ResultField{Expr: c2} c3 := ast.NewValueExpr(0) rf3 := &ast.ResultField{Expr: c3} col2 := &ast.ColumnNameExpr{Refer: rf2} fc := &ast.AggregateFuncExpr{ F: ast.AggFuncAvg, Args: []ast.ExprNode{col2}, } // Return row: // GroupKey, Sum // Partial result from region1 row1 := types.MakeDatums([]byte{1}, 2, 12) row2 := types.MakeDatums([]byte{2}, 1, 21) row3 := types.MakeDatums([]byte{3}, 1, 2) // Partial result from region2 row4 := types.MakeDatums([]byte{1}, 1, 3) row5 := types.MakeDatums([]byte{3}, 1, 31) data := []([]types.Datum){row1, row2, row3, row4, row5} rows := make([]*Row, 0, 5) for _, d := range data { rows = append(rows, &Row{Data: d}) } src := &mockExec{ rows: rows, fields: []*ast.ResultField{rf1, rf2, rf3}, // groupby, cnt, sum } agg := &XAggregateExec{ AggFuncs: []*ast.AggregateFuncExpr{fc}, Src: src, } ast.SetFlag(fc) // First row: 5 row, err := agg.Next() c.Assert(err, IsNil) c.Assert(row, NotNil) ctx := mock.NewContext() val, err := evaluator.Eval(ctx, fc) c.Assert(err, IsNil) c.Assert(val, testutil.DatumEquals, types.NewDecimalDatum(mysql.NewDecimalFromInt(int64(5), 0))) // Second row: 21 row, err = agg.Next() c.Assert(err, IsNil) c.Assert(row, NotNil) val, err = evaluator.Eval(ctx, fc) c.Assert(err, IsNil) c.Assert(val, testutil.DatumEquals, types.NewDecimalDatum(mysql.NewDecimalFromInt(int64(21), 0))) // Third row: 16.5000 row, err = agg.Next() c.Assert(err, IsNil) c.Assert(row, NotNil) val, err = evaluator.Eval(ctx, fc) c.Assert(err, IsNil) d := mysql.NewDecimalFromFloat(float64(16.5)) d.SetFracDigits(4) // For div operator, default frac is 4. c.Assert(val, testutil.DatumEquals, types.NewDecimalDatum(d)) // Forth row: nil row, err = agg.Next() c.Assert(err, IsNil) c.Assert(row, IsNil) // Close executor err = agg.Close() c.Assert(err, IsNil) }
func (e *Evaluator) unaryOperation(u *ast.UnaryOperationExpr) bool { defer func() { if er := recover(); er != nil { e.err = errors.Errorf("%v", er) } }() aDatum := u.V.GetDatum() if aDatum.Kind() == types.KindNull { u.SetNull() return true } switch op := u.Op; op { case opcode.Not: n, err := aDatum.ToBool() if err != nil { e.err = errors.Trace(err) } else if n == 0 { u.SetInt64(1) } else { u.SetInt64(0) } case opcode.BitNeg: // for bit operation, we will use int64 first, then return uint64 n, err := aDatum.ToInt64() if err != nil { e.err = errors.Trace(err) return false } u.SetUint64(uint64(^n)) case opcode.Plus: switch aDatum.Kind() { case types.KindInt64, types.KindUint64, types.KindFloat64, types.KindFloat32, types.KindMysqlDuration, types.KindMysqlTime, types.KindString, types.KindMysqlDecimal, types.KindBytes, types.KindMysqlHex, types.KindMysqlBit, types.KindMysqlEnum, types.KindMysqlSet: u.SetDatum(*aDatum) default: e.err = ErrInvalidOperation return false } case opcode.Minus: switch aDatum.Kind() { case types.KindInt64: u.SetInt64(-aDatum.GetInt64()) case types.KindUint64: u.SetInt64(-int64(aDatum.GetUint64())) case types.KindFloat64: u.SetFloat64(-aDatum.GetFloat64()) case types.KindFloat32: u.SetFloat32(-aDatum.GetFloat32()) case types.KindMysqlDuration: u.SetMysqlDecimal(mysql.ZeroDecimal.Sub(aDatum.GetMysqlDuration().ToNumber())) case types.KindMysqlTime: u.SetMysqlDecimal(mysql.ZeroDecimal.Sub(aDatum.GetMysqlTime().ToNumber())) case types.KindString, types.KindBytes: f, err := types.StrToFloat(aDatum.GetString()) e.err = errors.Trace(err) u.SetFloat64(-f) case types.KindMysqlDecimal: f, _ := aDatum.GetMysqlDecimal().Float64() u.SetMysqlDecimal(mysql.NewDecimalFromFloat(-f)) case types.KindMysqlHex: u.SetFloat64(-aDatum.GetMysqlHex().ToNumber()) case types.KindMysqlBit: u.SetFloat64(-aDatum.GetMysqlBit().ToNumber()) case types.KindMysqlEnum: u.SetFloat64(-aDatum.GetMysqlEnum().ToNumber()) case types.KindMysqlSet: u.SetFloat64(-aDatum.GetMysqlSet().ToNumber()) default: e.err = ErrInvalidOperation return false } default: e.err = ErrInvalidOperation return false } return true }
func (s *testCodecSuite) TestDecimal(c *C) { defer testleak.AfterTest(c)() tbl := []string{ "1234.00", "1234", "12.34", "12.340", "0.1234", "0.0", "0", "-0.0", "-0.0000", "-1234.00", "-1234", "-12.34", "-12.340", "-0.1234"} for _, t := range tbl { m, err := mysql.ParseDecimal(t) c.Assert(err, IsNil) b, err := EncodeKey(nil, types.NewDatum(m)) c.Assert(err, IsNil) v, err := Decode(b) c.Assert(err, IsNil) c.Assert(v, HasLen, 1) vv := v[0].GetMysqlDecimal() c.Assert(vv.Equals(m), IsTrue) } tblCmp := []struct { Arg1 interface{} Arg2 interface{} Ret int }{ // Test for float type decimal. {"1234", "123400", -1}, {"12340", "123400", -1}, {"1234", "1234.5", -1}, {"1234", "1234.0000", 0}, {"1234", "12.34", 1}, {"12.34", "12.35", -1}, {"0.12", "0.1234", -1}, {"0.1234", "12.3400", -1}, {"0.1234", "0.1235", -1}, {"0.123400", "12.34", -1}, {"12.34000", "12.34", 0}, {"0.01234", "0.01235", -1}, {"0.1234", "0", 1}, {"0.0000", "0", 0}, {"0.0001", "0", 1}, {"0.0001", "0.0000", 1}, {"0", "-0.0000", 0}, {"-0.0001", "0", -1}, {"-0.1234", "0", -1}, {"-0.1234", "-0.12", -1}, {"-0.12", "-0.1234", 1}, {"-0.12", "-0.1200", 0}, {"-0.1234", "0.1234", -1}, {"-1.234", "-12.34", 1}, {"-0.1234", "-12.34", 1}, {"-12.34", "1234", -1}, {"-12.34", "-12.35", 1}, {"-0.01234", "-0.01235", 1}, {"-1234", "-123400", 1}, {"-12340", "-123400", 1}, // Test for int type decimal. {int64(-1), int64(1), -1}, {int64(math.MaxInt64), int64(math.MinInt64), 1}, {int64(math.MaxInt64), int64(math.MaxInt32), 1}, {int64(math.MinInt32), int64(math.MaxInt16), -1}, {int64(math.MinInt64), int64(math.MaxInt8), -1}, {int64(0), int64(math.MaxInt8), -1}, {int64(math.MinInt8), int64(0), -1}, {int64(math.MinInt16), int64(math.MaxInt16), -1}, {int64(1), int64(-1), 1}, {int64(1), int64(0), 1}, {int64(-1), int64(0), -1}, {int64(0), int64(0), 0}, {int64(math.MaxInt16), int64(math.MaxInt16), 0}, // Test for uint type decimal. {uint64(0), uint64(0), 0}, {uint64(1), uint64(0), 1}, {uint64(0), uint64(1), -1}, {uint64(math.MaxInt8), uint64(math.MaxInt16), -1}, {uint64(math.MaxUint32), uint64(math.MaxInt32), 1}, {uint64(math.MaxUint8), uint64(math.MaxInt8), 1}, {uint64(math.MaxUint16), uint64(math.MaxInt32), -1}, {uint64(math.MaxUint64), uint64(math.MaxInt64), 1}, {uint64(math.MaxInt64), uint64(math.MaxUint32), 1}, {uint64(math.MaxUint64), uint64(0), 1}, {uint64(0), uint64(math.MaxUint64), -1}, } for _, t := range tblCmp { m1, err := mysql.ConvertToDecimal(t.Arg1) c.Assert(err, IsNil) m2, err := mysql.ConvertToDecimal(t.Arg2) c.Assert(err, IsNil) b1, err := EncodeKey(nil, types.NewDatum(m1)) c.Assert(err, IsNil) b2, err := EncodeKey(nil, types.NewDatum(m2)) c.Assert(err, IsNil) ret := bytes.Compare(b1, b2) c.Assert(ret, Equals, t.Ret) } floats := []float64{-123.45, -123.40, -23.45, -1.43, -0.93, -0.4333, -0.068, -0.0099, 0, 0.001, 0.0012, 0.12, 1.2, 1.23, 123.3, 2424.242424} var decs [][]byte for i := range floats { dec := mysql.NewDecimalFromFloat(floats[i]) decs = append(decs, EncodeDecimal(nil, dec)) } for i := 0; i < len(decs)-1; i++ { cmp := bytes.Compare(decs[i], decs[i+1]) c.Assert(cmp, LessEqual, 0) } }
// 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) a = types.RawData(a) if a == nil { return } n, err := types.ToBool(a) if err != nil { return types.UndOp(a, op) } else if n == 0 { return int64(1), nil } return int64(0), nil case opcode.BitNeg: a := Eval(u.V, ctx, args) a = types.RawData(a) 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) a = types.RawData(a) if a == nil { return } switch x := a.(type) { case nil: return nil, nil case bool: if x { return int64(1), nil } return int64(0), 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 case []byte: return x, nil case mysql.Hex: return x, nil case mysql.Bit: return x, nil case mysql.Enum: return x, nil case mysql.Set: return x, nil default: return types.UndOp(a, op) } case opcode.Minus: a := Eval(u.V, ctx, args) a = types.RawData(a) if a == nil { return } switch x := a.(type) { case nil: return nil, nil case bool: if x { return int64(-1), nil } return int64(0), 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 case []byte: f, err := types.StrToFloat(string(x)) return -f, err case mysql.Hex: return -x.ToNumber(), nil case mysql.Bit: return -x.ToNumber(), nil case mysql.Enum: return -x.ToNumber(), nil case mysql.Set: return -x.ToNumber(), nil default: return types.UndOp(a, op) } default: panic("should never happen") } }
// TODO: add more tests. func (s *testEvalSuite) TestEval(c *C) { colID := int64(1) row := make(map[int64]types.Datum) row[colID] = types.NewIntDatum(100) xevaluator := &Evaluator{Row: row} cases := []struct { expr *tipb.Expr result types.Datum }{ // Datums. { datumExpr(types.NewFloat32Datum(1.1)), types.NewFloat32Datum(1.1), }, { datumExpr(types.NewFloat64Datum(1.1)), types.NewFloat64Datum(1.1), }, { datumExpr(types.NewIntDatum(1)), types.NewIntDatum(1), }, { datumExpr(types.NewUintDatum(1)), types.NewUintDatum(1), }, { datumExpr(types.NewBytesDatum([]byte("abc"))), types.NewBytesDatum([]byte("abc")), }, { datumExpr(types.NewStringDatum("abc")), types.NewStringDatum("abc"), }, { datumExpr(types.Datum{}), types.Datum{}, }, { datumExpr(types.NewDurationDatum(mysql.Duration{Duration: time.Hour})), types.NewDurationDatum(mysql.Duration{Duration: time.Hour}), }, { datumExpr(types.NewDecimalDatum(mysql.NewDecimalFromFloat(1.1))), types.NewDecimalDatum(mysql.NewDecimalFromFloat(1.1)), }, { columnExpr(1), types.NewIntDatum(100), }, // Comparison operations. { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(1), tipb.ExprType_LT), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(1), types.NewIntDatum(100), tipb.ExprType_LT), types.NewIntDatum(1), }, { binaryExpr(types.NewIntDatum(100), types.Datum{}, tipb.ExprType_LT), types.Datum{}, }, { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(1), tipb.ExprType_LE), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(1), types.NewIntDatum(1), tipb.ExprType_LE), types.NewIntDatum(1), }, { binaryExpr(types.NewIntDatum(100), types.Datum{}, tipb.ExprType_LE), types.Datum{}, }, { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(1), tipb.ExprType_EQ), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(100), tipb.ExprType_EQ), types.NewIntDatum(1), }, { binaryExpr(types.NewIntDatum(100), types.Datum{}, tipb.ExprType_EQ), types.Datum{}, }, { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(100), tipb.ExprType_NE), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(1), tipb.ExprType_NE), types.NewIntDatum(1), }, { binaryExpr(types.NewIntDatum(100), types.Datum{}, tipb.ExprType_NE), types.Datum{}, }, { binaryExpr(types.NewIntDatum(1), types.NewIntDatum(100), tipb.ExprType_GE), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(100), tipb.ExprType_GE), types.NewIntDatum(1), }, { binaryExpr(types.NewIntDatum(100), types.Datum{}, tipb.ExprType_GE), types.Datum{}, }, { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(100), tipb.ExprType_GT), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(1), tipb.ExprType_GT), types.NewIntDatum(1), }, { binaryExpr(types.NewIntDatum(100), types.Datum{}, tipb.ExprType_GT), types.Datum{}, }, { binaryExpr(types.NewIntDatum(1), types.Datum{}, tipb.ExprType_NullEQ), types.NewIntDatum(0), }, { binaryExpr(types.Datum{}, types.Datum{}, tipb.ExprType_NullEQ), types.NewIntDatum(1), }, // Logic operation. { binaryExpr(types.NewIntDatum(0), types.NewIntDatum(1), tipb.ExprType_And), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(1), types.NewIntDatum(1), tipb.ExprType_And), types.NewIntDatum(1), }, { binaryExpr(types.NewIntDatum(0), types.Datum{}, tipb.ExprType_And), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(1), types.Datum{}, tipb.ExprType_And), types.Datum{}, }, { binaryExpr(types.NewIntDatum(0), types.NewIntDatum(0), tipb.ExprType_Or), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(0), types.NewIntDatum(1), tipb.ExprType_Or), types.NewIntDatum(1), }, { binaryExpr(types.NewIntDatum(0), types.Datum{}, tipb.ExprType_Or), types.Datum{}, }, { binaryExpr(types.NewIntDatum(1), types.Datum{}, tipb.ExprType_Or), types.NewIntDatum(1), }, { binaryExpr( binaryExpr(types.NewIntDatum(1), types.NewIntDatum(1), tipb.ExprType_EQ), binaryExpr(types.NewIntDatum(1), types.NewIntDatum(1), tipb.ExprType_EQ), tipb.ExprType_And), types.NewIntDatum(1), }, { notExpr(datumExpr(types.NewIntDatum(1))), types.NewIntDatum(0), }, { notExpr(datumExpr(types.NewIntDatum(0))), types.NewIntDatum(1), }, { notExpr(datumExpr(types.Datum{})), types.Datum{}, }, } for _, ca := range cases { result, err := xevaluator.Eval(ca.expr) c.Assert(err, IsNil) c.Assert(result.Kind(), Equals, ca.result.Kind()) cmp, err := result.CompareDatum(ca.result) c.Assert(err, IsNil) c.Assert(cmp, Equals, 0) } }