// 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 getZeroValue(col *model.ColumnInfo) types.Datum { var d types.Datum switch col.Tp { case mysql.TypeTiny, mysql.TypeInt24, mysql.TypeShort, mysql.TypeLong, mysql.TypeLonglong, mysql.TypeYear: if mysql.HasUnsignedFlag(col.Flag) { d.SetUint64(0) } else { d.SetInt64(0) } case mysql.TypeFloat: d.SetFloat32(0) case mysql.TypeDouble: d.SetFloat64(0) case mysql.TypeNewDecimal: d.SetMysqlDecimal(mysql.NewDecimalFromInt(0, 0)) case mysql.TypeString, mysql.TypeVarString, mysql.TypeVarchar: d.SetString("") case mysql.TypeBlob, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob: d.SetBytes([]byte{}) case mysql.TypeDuration: d.SetMysqlDuration(mysql.ZeroDuration) case mysql.TypeDate, mysql.TypeNewDate: d.SetMysqlTime(mysql.ZeroDate) case mysql.TypeTimestamp: d.SetMysqlTime(mysql.ZeroTimestamp) case mysql.TypeDatetime: d.SetMysqlTime(mysql.ZeroDatetime) case mysql.TypeBit: d.SetMysqlBit(mysql.Bit{Value: 0, Width: mysql.MinBitWidth}) case mysql.TypeSet: d.SetMysqlSet(mysql.Set{}) } return d }
// DecodeDecimal decodes bytes to decimal. // DecodeFloat decodes a float from a byte slice // Decimal decoding: // Byte -> value sign // DecodeInt -> exp value // DecodeBytes -> abs value bytes func DecodeDecimal(b []byte) ([]byte, mysql.Decimal, error) { var ( r = b d mysql.Decimal err error ) // Decode value sign. valSign := int64(r[0]) r = r[1:] if valSign == zeroSign { d, err = mysql.ParseDecimal("0") return r, d, errors.Trace(err) } // Decode exp value. expVal := int64(0) r, expVal, err = DecodeInt(r) if err != nil { return r, d, errors.Trace(err) } // Decode abs value bytes. value := []byte{} if valSign == negativeSign { expVal = -expVal r, value, err = DecodeBytesDesc(r) } else { r, value, err = DecodeBytes(r) } if err != nil { return r, d, errors.Trace(err) } // Set decimal sign and point to value. if valSign == negativeSign { value = append([]byte("-0."), value...) } else { value = append([]byte("0."), value...) } numberDecimal, err := mysql.ParseDecimal(string(value)) if err != nil { return r, d, errors.Trace(err) } expDecimal := mysql.NewDecimalFromInt(1, int32(expVal)) d = numberDecimal.Mul(expDecimal) if expDecimal.Exponent() > 0 { // For int64(3), it will be converted to value=0.3 and exp=1 when doing encode. // Its frac will be changed after we run d = numberDecimal.Mul(expDecimal). // So we try to get frac to the original one. d.SetFracDigits(d.FracDigits() - expDecimal.Exponent()) } return r, d, nil }
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 (s *testTypeEtcSuite) TestCoerce(c *check.C) { checkCoerce(c, uint64(3), int16(4)) checkCoerce(c, uint64(0xffffffffffffffff), float64(2.3)) checkCoerce(c, float64(1.3), uint64(0xffffffffffffffff)) checkCoerce(c, int64(11), float64(4.313)) checkCoerce(c, uint(2), uint16(52)) checkCoerce(c, uint8(8), true) checkCoerce(c, uint32(62), int8(8)) checkCoerce(c, mysql.NewDecimalFromInt(1, 0), false) checkCoerce(c, float32(3.4), mysql.NewDecimalFromUint(1, 0)) checkCoerce(c, int32(43), 3.235) }
// DecodeDecimal decodes bytes to decimal. // DecodeFloat decodes a float from a byte slice // Decimal decoding: // Byte -> value sign // DecodeInt -> exp value // DecodeBytes -> abs value bytes func DecodeDecimal(b []byte) ([]byte, mysql.Decimal, error) { var ( r = b d mysql.Decimal err error ) // Decode value sign. valSign := int64(r[0]) r = r[1:] if valSign == zeroSign { d, err = mysql.ParseDecimal("0") return r, d, errors.Trace(err) } // Decode exp value. expVal := int64(0) r, expVal, err = DecodeInt(r) if err != nil { return r, d, errors.Trace(err) } // Decode abs value bytes. value := []byte{} if valSign == negativeSign { expVal = -expVal r, value, err = DecodeBytesDesc(r) } else { r, value, err = DecodeBytes(r) } if err != nil { return r, d, errors.Trace(err) } // Set decimal sign and point to value. if valSign == negativeSign { value = append([]byte("-0."), value...) } else { value = append([]byte("0."), value...) } numberDecimal, err := mysql.ParseDecimal(string(value)) if err != nil { return r, d, errors.Trace(err) } expDecimal := mysql.NewDecimalFromInt(1, int32(expVal)) d = numberDecimal.Mul(expDecimal) return r, d, nil }
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 (s *testUnaryOperationSuite) TestUnaryOp(c *C) { tbl := []struct { arg interface{} op opcode.Op result interface{} }{ // test NOT. {1, opcode.Not, int64(0)}, {0, opcode.Not, int64(1)}, {nil, opcode.Not, nil}, {mysql.Hex{Value: 0}, opcode.Not, int64(1)}, {mysql.Bit{Value: 0, Width: 1}, opcode.Not, int64(1)}, {mysql.Enum{Name: "a", Value: 1}, opcode.Not, int64(0)}, {mysql.Set{Name: "a", Value: 1}, opcode.Not, int64(0)}, // test BitNeg. {nil, opcode.BitNeg, nil}, {-1, opcode.BitNeg, uint64(0)}, // test Plus. {nil, opcode.Plus, nil}, {float32(1.0), opcode.Plus, float32(1.0)}, {float64(1.0), opcode.Plus, float64(1.0)}, {int(1), opcode.Plus, int(1)}, {int64(1), opcode.Plus, int64(1)}, {uint64(1), opcode.Plus, uint64(1)}, {"1.0", opcode.Plus, "1.0"}, {[]byte("1.0"), opcode.Plus, []byte("1.0")}, {mysql.Hex{Value: 1}, opcode.Plus, mysql.Hex{Value: 1}}, {mysql.Bit{Value: 1, Width: 1}, opcode.Plus, mysql.Bit{Value: 1, Width: 1}}, {true, opcode.Plus, int64(1)}, {false, opcode.Plus, int64(0)}, {mysql.Enum{Name: "a", Value: 1}, opcode.Plus, mysql.Enum{Name: "a", Value: 1}}, {mysql.Set{Name: "a", Value: 1}, opcode.Plus, mysql.Set{Name: "a", Value: 1}}, // test Minus. {nil, opcode.Minus, nil}, {float32(1.0), opcode.Minus, float32(-1.0)}, {float64(1.0), opcode.Minus, float64(-1.0)}, {int(1), opcode.Minus, int(-1)}, {int64(1), opcode.Minus, int64(-1)}, {uint(1), opcode.Minus, -int64(1)}, {uint8(1), opcode.Minus, -int64(1)}, {uint16(1), opcode.Minus, -int64(1)}, {uint32(1), opcode.Minus, -int64(1)}, {uint64(1), opcode.Minus, -int64(1)}, {"1.0", opcode.Minus, -1.0}, {[]byte("1.0"), opcode.Minus, -1.0}, {mysql.Hex{Value: 1}, opcode.Minus, -1.0}, {mysql.Bit{Value: 1, Width: 1}, opcode.Minus, -1.0}, {true, opcode.Minus, int64(-1)}, {false, opcode.Minus, int64(0)}, {mysql.Enum{Name: "a", Value: 1}, opcode.Minus, -1.0}, {mysql.Set{Name: "a", Value: 1}, opcode.Minus, -1.0}, } for _, t := range tbl { expr := NewUnaryOperation(t.op, Value{t.arg}) exprc := expr.Clone() result, err := exprc.Eval(nil, nil) c.Assert(err, IsNil) c.Assert(result, DeepEquals, t.result) } tbl = []struct { arg interface{} op opcode.Op result interface{} }{ {mysql.NewDecimalFromInt(1, 0), opcode.Plus, mysql.NewDecimalFromInt(1, 0)}, {mysql.Duration{Duration: time.Duration(838*3600 + 59*60 + 59), Fsp: mysql.DefaultFsp}, opcode.Plus, mysql.Duration{Duration: time.Duration(838*3600 + 59*60 + 59), Fsp: mysql.DefaultFsp}}, {mysql.Time{Time: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), Type: mysql.TypeDatetime, Fsp: 0}, opcode.Plus, mysql.Time{Time: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), Type: mysql.TypeDatetime, Fsp: 0}}, {mysql.NewDecimalFromInt(1, 0), opcode.Minus, mysql.NewDecimalFromInt(-1, 0)}, {mysql.ZeroDuration, opcode.Minus, mysql.NewDecimalFromInt(0, 0)}, {mysql.Time{Time: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), Type: mysql.TypeDatetime, Fsp: 0}, opcode.Minus, mysql.NewDecimalFromInt(-20091110230000, 0)}, } for _, t := range tbl { expr := NewUnaryOperation(t.op, Value{t.arg}) exprc := expr.Clone() result, err := exprc.Eval(nil, nil) c.Assert(err, IsNil) ret, err := types.Compare(result, t.result) c.Assert(err, IsNil) c.Assert(ret, Equals, 0) } // test String(). strTbl := []struct { expr Expression op opcode.Op isStatic bool }{ {NewBinaryOperation(opcode.EQ, Value{1}, Value{1}), opcode.Plus, true}, {NewUnaryOperation(opcode.Not, Value{1}), opcode.Not, true}, {Value{1}, opcode.Not, true}, {Value{1}, opcode.Plus, true}, {&PExpr{Value{1}}, opcode.Not, true}, {NewBinaryOperation(opcode.EQ, Value{1}, Value{1}), opcode.Not, true}, {NewBinaryOperation(opcode.NE, Value{1}, Value{1}), opcode.Not, true}, {NewBinaryOperation(opcode.GT, Value{1}, Value{1}), opcode.Not, true}, {NewBinaryOperation(opcode.GE, Value{1}, Value{1}), opcode.Not, true}, {NewBinaryOperation(opcode.LT, Value{1}, Value{1}), opcode.Not, true}, {NewBinaryOperation(opcode.LE, Value{1}, Value{1}), opcode.Not, true}, } for _, t := range strTbl { expr := NewUnaryOperation(t.op, t.expr) c.Assert(expr.IsStatic(), Equals, t.isStatic) str := expr.String() c.Assert(len(str), Greater, 0) } // test error. errTbl := []struct { arg interface{} op opcode.Op }{ {mockExpr{}, opcode.Not}, {mockExpr{}, opcode.BitNeg}, {mockExpr{}, opcode.Plus}, {mockExpr{}, opcode.Minus}, {mockExpr{}, opcode.EQ}, } // test error clone expr := NewUnaryOperation(opcode.Not, mockExpr{err: errors.New("must error")}) c.Assert(expr.Clone(), NotNil) for _, t := range errTbl { expr := NewUnaryOperation(t.op, Value{t.arg}) _, err := expr.Eval(nil, nil) c.Assert(err, NotNil) } }
func (s *testEvaluatorSuite) TestUnaryOp(c *C) { tbl := []struct { arg interface{} op opcode.Op result interface{} }{ // test NOT. {1, opcode.Not, int64(0)}, {0, opcode.Not, int64(1)}, {nil, opcode.Not, nil}, {mysql.Hex{Value: 0}, opcode.Not, int64(1)}, {mysql.Bit{Value: 0, Width: 1}, opcode.Not, int64(1)}, {mysql.Enum{Name: "a", Value: 1}, opcode.Not, int64(0)}, {mysql.Set{Name: "a", Value: 1}, opcode.Not, int64(0)}, // test BitNeg. {nil, opcode.BitNeg, nil}, {-1, opcode.BitNeg, uint64(0)}, // test Plus. {nil, opcode.Plus, nil}, {float64(1.0), opcode.Plus, float64(1.0)}, {int(1), opcode.Plus, int(1)}, {int64(1), opcode.Plus, int64(1)}, {uint64(1), opcode.Plus, uint64(1)}, {"1.0", opcode.Plus, "1.0"}, {[]byte("1.0"), opcode.Plus, []byte("1.0")}, {mysql.Hex{Value: 1}, opcode.Plus, mysql.Hex{Value: 1}}, {mysql.Bit{Value: 1, Width: 1}, opcode.Plus, mysql.Bit{Value: 1, Width: 1}}, {true, opcode.Plus, int64(1)}, {false, opcode.Plus, int64(0)}, {mysql.Enum{Name: "a", Value: 1}, opcode.Plus, mysql.Enum{Name: "a", Value: 1}}, {mysql.Set{Name: "a", Value: 1}, opcode.Plus, mysql.Set{Name: "a", Value: 1}}, // test Minus. {nil, opcode.Minus, nil}, {float64(1.0), opcode.Minus, float64(-1.0)}, {int(1), opcode.Minus, int(-1)}, {int64(1), opcode.Minus, int64(-1)}, {uint64(1), opcode.Minus, -int64(1)}, {"1.0", opcode.Minus, -1.0}, {[]byte("1.0"), opcode.Minus, -1.0}, {mysql.Hex{Value: 1}, opcode.Minus, -1.0}, {mysql.Bit{Value: 1, Width: 1}, opcode.Minus, -1.0}, {true, opcode.Minus, int64(-1)}, {false, opcode.Minus, int64(0)}, {mysql.Enum{Name: "a", Value: 1}, opcode.Minus, -1.0}, {mysql.Set{Name: "a", Value: 1}, opcode.Minus, -1.0}, } ctx := mock.NewContext() expr := &ast.UnaryOperationExpr{} for _, t := range tbl { expr.Op = t.op expr.V = ast.NewValueExpr(t.arg) result, err := Eval(ctx, expr) c.Assert(err, IsNil) c.Assert(result, DeepEquals, t.result) } tbl = []struct { arg interface{} op opcode.Op result interface{} }{ {mysql.NewDecimalFromInt(1, 0), opcode.Plus, mysql.NewDecimalFromInt(1, 0)}, {mysql.Duration{Duration: time.Duration(838*3600 + 59*60 + 59), Fsp: mysql.DefaultFsp}, opcode.Plus, mysql.Duration{Duration: time.Duration(838*3600 + 59*60 + 59), Fsp: mysql.DefaultFsp}}, {mysql.Time{Time: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), Type: mysql.TypeDatetime, Fsp: 0}, opcode.Plus, mysql.Time{Time: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), Type: mysql.TypeDatetime, Fsp: 0}}, {mysql.NewDecimalFromInt(1, 0), opcode.Minus, mysql.NewDecimalFromInt(-1, 0)}, {mysql.ZeroDuration, opcode.Minus, mysql.NewDecimalFromInt(0, 0)}, {mysql.Time{Time: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), Type: mysql.TypeDatetime, Fsp: 0}, opcode.Minus, mysql.NewDecimalFromInt(-20091110230000, 0)}, } for _, t := range tbl { expr := &ast.UnaryOperationExpr{Op: t.op, V: ast.NewValueExpr(t.arg)} result, err := Eval(ctx, expr) c.Assert(err, IsNil) ret, err := types.Compare(result, t.result) c.Assert(err, IsNil) c.Assert(ret, Equals, 0) } }
func (s *testTableCodecSuite) TestRowCodec(c *C) { defer testleak.AfterTest(c)() c1 := &column{id: 1, tp: types.NewFieldType(mysql.TypeLonglong)} c2 := &column{id: 2, tp: types.NewFieldType(mysql.TypeVarchar)} c3 := &column{id: 3, tp: types.NewFieldType(mysql.TypeNewDecimal)} cols := []*column{c1, c2, c3} row := make([]types.Datum, 3) row[0] = types.NewIntDatum(100) row[1] = types.NewBytesDatum([]byte("abc")) row[2] = types.NewDecimalDatum(mysql.NewDecimalFromInt(1, 1)) // Encode colIDs := make([]int64, 0, 3) for _, col := range cols { colIDs = append(colIDs, col.id) } bs, err := EncodeRow(row, colIDs) c.Assert(err, IsNil) c.Assert(bs, NotNil) // Decode colMap := make(map[int64]*types.FieldType, 3) for _, col := range cols { colMap[col.id] = col.tp } r, err := DecodeRow(bs, colMap) c.Assert(err, IsNil) c.Assert(r, NotNil) c.Assert(r, HasLen, 3) // Compare decoded row and original row for i, col := range cols { v, ok := r[col.id] c.Assert(ok, IsTrue) equal, err1 := v.CompareDatum(row[i]) c.Assert(err1, IsNil) c.Assert(equal, Equals, 0) } // colMap may contains more columns than encoded row. colMap[4] = types.NewFieldType(mysql.TypeFloat) r, err = DecodeRow(bs, colMap) c.Assert(err, IsNil) c.Assert(r, NotNil) c.Assert(r, HasLen, 3) for i, col := range cols { v, ok := r[col.id] c.Assert(ok, IsTrue) equal, err1 := v.CompareDatum(row[i]) c.Assert(err1, IsNil) c.Assert(equal, Equals, 0) } // colMap may contains less columns than encoded row. delete(colMap, 3) delete(colMap, 4) r, err = DecodeRow(bs, colMap) c.Assert(err, IsNil) c.Assert(r, NotNil) c.Assert(r, HasLen, 2) for i, col := range cols { if i > 1 { break } v, ok := r[col.id] c.Assert(ok, IsTrue) equal, err1 := v.CompareDatum(row[i]) c.Assert(err1, IsNil) c.Assert(equal, Equals, 0) } // Make sure empty row return not nil value. bs, err = EncodeRow([]types.Datum{}, []int64{}) c.Assert(err, IsNil) c.Assert(bs, HasLen, 1) r, err = DecodeRow(bs, colMap) c.Assert(err, IsNil) c.Assert(r, IsNil) }
func (s *testBuiltinSuite) TestGroupBy(c *C) { tbl := []struct { F string // args for every Eval round RoundArgs []interface{} Distinct bool Ret interface{} }{ {"avg", []interface{}{1, 1}, false, 1}, {"avg", []interface{}{1, 2}, true, 1.5}, {"avg", []interface{}{1.0, 2.0}, true, 1.5}, {"avg", []interface{}{1, 1}, true, 1}, {"avg", []interface{}{nil, nil}, true, nil}, {"count", []interface{}{1, 1}, false, 2}, {"count", []interface{}{1, 1}, true, 1}, {"count", []interface{}{nil, nil}, true, 0}, {"count", []interface{}{nil, nil}, false, 0}, {"count", []interface{}{nil, 1}, true, 1}, {"max", []interface{}{1, 2, 3}, false, 3}, {"max", []interface{}{nil, 2}, false, 2}, {"max", []interface{}{nil, nil}, false, nil}, {"min", []interface{}{1, 2, 3}, false, 1}, {"min", []interface{}{nil, 1}, false, 1}, {"min", []interface{}{nil, nil}, false, nil}, {"min", []interface{}{3, 2, 1}, false, 1}, {"sum", []interface{}{1, 1, 1, 1, 1}, false, 5}, {"sum", []interface{}{float64(1.0), float64(1.0)}, false, 2.0}, {"sum", []interface{}{1, 1, 1, 1, 1}, true, 1}, {"sum", []interface{}{1, mysql.NewDecimalFromInt(1, 0)}, false, 2}, {"sum", []interface{}{nil, nil}, false, nil}, {"sum", []interface{}{nil, nil}, true, nil}, } for _, t := range tbl { f, ok := Funcs[t.F] c.Assert(ok, IsTrue) m := map[interface{}]interface{}{} m[ExprEvalFn] = new(Func) m[ExprAggDistinct] = CreateAggregateDistinct(t.F, t.Distinct) for _, arg := range t.RoundArgs { args := []interface{}{arg} _, err := f.F(args, m) c.Assert(err, IsNil) } m[ExprAggDone] = struct{}{} v, err := f.F(nil, m) c.Assert(err, IsNil) switch v.(type) { case nil: c.Assert(t.Ret, IsNil) default: // we can not check decimal type directly, but we can convert all to float64 f, err := types.ToFloat64(v) c.Assert(err, IsNil) ret, err := types.ToFloat64(t.Ret) c.Assert(err, IsNil) c.Assert(f, Equals, ret) } } }
func (s *testEvaluatorSuite) TestBinopNumeric(c *C) { ctx := mock.NewContext() tbl := []struct { lhs interface{} op opcode.Op rhs interface{} ret interface{} }{ // plus {1, opcode.Plus, 1, 2}, {1, opcode.Plus, uint64(1), 2}, {1, opcode.Plus, "1", 2}, {1, opcode.Plus, mysql.NewDecimalFromInt(1, 0), 2}, {uint64(1), opcode.Plus, 1, 2}, {uint64(1), opcode.Plus, uint64(1), 2}, {1, opcode.Plus, []byte("1"), 2}, {1, opcode.Plus, mysql.Hex{Value: 1}, 2}, {1, opcode.Plus, mysql.Bit{Value: 1, Width: 1}, 2}, {1, opcode.Plus, mysql.Enum{Name: "a", Value: 1}, 2}, {1, opcode.Plus, mysql.Set{Name: "a", Value: 1}, 2}, // minus {1, opcode.Minus, 1, 0}, {1, opcode.Minus, uint64(1), 0}, {1, opcode.Minus, float64(1), 0}, {1, opcode.Minus, mysql.NewDecimalFromInt(1, 0), 0}, {uint64(1), opcode.Minus, 1, 0}, {uint64(1), opcode.Minus, uint64(1), 0}, {mysql.NewDecimalFromInt(1, 0), opcode.Minus, 1, 0}, {"1", opcode.Minus, []byte("1"), 0}, // mul {1, opcode.Mul, 1, 1}, {1, opcode.Mul, uint64(1), 1}, {1, opcode.Mul, float64(1), 1}, {1, opcode.Mul, mysql.NewDecimalFromInt(1, 0), 1}, {uint64(1), opcode.Mul, 1, 1}, {uint64(1), opcode.Mul, uint64(1), 1}, {mysql.Time{}, opcode.Mul, 0, 0}, {mysql.ZeroDuration, opcode.Mul, 0, 0}, {mysql.Time{Time: time.Now(), Fsp: 0, Type: mysql.TypeDatetime}, opcode.Mul, 0, 0}, {mysql.Time{Time: time.Now(), Fsp: 6, Type: mysql.TypeDatetime}, opcode.Mul, 0, 0}, {mysql.Duration{Duration: 100000000, Fsp: 6}, opcode.Mul, 0, 0}, // div {1, opcode.Div, float64(1), 1}, {1, opcode.Div, float64(0), nil}, {1, opcode.Div, 2, 0.5}, {1, opcode.Div, 0, nil}, // int div {1, opcode.IntDiv, 2, 0}, {1, opcode.IntDiv, uint64(2), 0}, {1, opcode.IntDiv, 0, nil}, {1, opcode.IntDiv, uint64(0), nil}, {uint64(1), opcode.IntDiv, 2, 0}, {uint64(1), opcode.IntDiv, uint64(2), 0}, {uint64(1), opcode.IntDiv, 0, nil}, {uint64(1), opcode.IntDiv, uint64(0), nil}, {1.0, opcode.IntDiv, 2.0, 0}, {1.0, opcode.IntDiv, 0, nil}, // mod {10, opcode.Mod, 2, 0}, {10, opcode.Mod, uint64(2), 0}, {10, opcode.Mod, 0, nil}, {10, opcode.Mod, uint64(0), nil}, {-10, opcode.Mod, uint64(2), 0}, {uint64(10), opcode.Mod, 2, 0}, {uint64(10), opcode.Mod, uint64(2), 0}, {uint64(10), opcode.Mod, 0, nil}, {uint64(10), opcode.Mod, uint64(0), nil}, {uint64(10), opcode.Mod, -2, 0}, {float64(10), opcode.Mod, 2, 0}, {float64(10), opcode.Mod, 0, nil}, {mysql.NewDecimalFromInt(10, 0), opcode.Mod, 2, 0}, {mysql.NewDecimalFromInt(10, 0), opcode.Mod, 0, nil}, } 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) switch v.(type) { case nil: c.Assert(t.ret, IsNil) default: // we use float64 as the result type check for all. f, err := types.ToFloat64(v) c.Assert(err, IsNil) r, err := types.ToFloat64(t.ret) c.Assert(err, IsNil) c.Assert(r, Equals, f) } } }
func (s *testTypeConvertSuite) TestConvert(c *check.C) { // integer ranges signedDeny(c, mysql.TypeTiny, -129, "-128") signedAccept(c, mysql.TypeTiny, -128, "-128") signedAccept(c, mysql.TypeTiny, 127, "127") signedDeny(c, mysql.TypeTiny, 128, "127") unsignedDeny(c, mysql.TypeTiny, -1, "0") unsignedAccept(c, mysql.TypeTiny, 0, "0") unsignedAccept(c, mysql.TypeTiny, 255, "255") unsignedDeny(c, mysql.TypeTiny, 256, "255") signedDeny(c, mysql.TypeShort, int64(math.MinInt16)-1, strvalue(int64(math.MinInt16))) signedAccept(c, mysql.TypeShort, int64(math.MinInt16), strvalue(int64(math.MinInt16))) signedAccept(c, mysql.TypeShort, int64(math.MaxInt16), strvalue(int64(math.MaxInt16))) signedDeny(c, mysql.TypeShort, int64(math.MaxInt16)+1, strvalue(int64(math.MaxInt16))) unsignedDeny(c, mysql.TypeShort, -1, "0") unsignedAccept(c, mysql.TypeShort, 0, "0") unsignedAccept(c, mysql.TypeShort, uint64(math.MaxUint16), strvalue(uint64(math.MaxUint16))) unsignedDeny(c, mysql.TypeShort, uint64(math.MaxUint16)+1, strvalue(uint64(math.MaxUint16))) signedDeny(c, mysql.TypeInt24, -1<<23-1, strvalue(-1<<23)) signedAccept(c, mysql.TypeInt24, -1<<23, strvalue(-1<<23)) signedAccept(c, mysql.TypeInt24, 1<<23-1, strvalue(1<<23-1)) signedDeny(c, mysql.TypeInt24, 1<<23, strvalue(1<<23-1)) unsignedDeny(c, mysql.TypeInt24, -1, "0") unsignedAccept(c, mysql.TypeInt24, 0, "0") unsignedAccept(c, mysql.TypeInt24, 1<<24-1, strvalue(1<<24-1)) unsignedDeny(c, mysql.TypeInt24, 1<<24, strvalue(1<<24-1)) signedDeny(c, mysql.TypeLong, int64(math.MinInt32)-1, strvalue(int64(math.MinInt32))) signedAccept(c, mysql.TypeLong, int64(math.MinInt32), strvalue(int64(math.MinInt32))) signedAccept(c, mysql.TypeLong, int64(math.MaxInt32), strvalue(int64(math.MaxInt32))) signedDeny(c, mysql.TypeLong, uint64(math.MaxUint64), strvalue(uint64(math.MaxInt32))) signedDeny(c, mysql.TypeLong, int64(math.MaxInt32)+1, strvalue(int64(math.MaxInt32))) unsignedDeny(c, mysql.TypeLong, -1, "0") unsignedAccept(c, mysql.TypeLong, 0, "0") unsignedAccept(c, mysql.TypeLong, uint64(math.MaxUint32), strvalue(uint64(math.MaxUint32))) unsignedDeny(c, mysql.TypeLong, uint64(math.MaxUint32)+1, strvalue(uint64(math.MaxUint32))) signedDeny(c, mysql.TypeLonglong, math.MinInt64*1.1, strvalue(int64(math.MinInt64))) signedAccept(c, mysql.TypeLonglong, int64(math.MinInt64), strvalue(int64(math.MinInt64))) signedAccept(c, mysql.TypeLonglong, int64(math.MaxInt64), strvalue(int64(math.MaxInt64))) signedDeny(c, mysql.TypeLonglong, math.MaxInt64*1.1, strvalue(int64(math.MaxInt64))) unsignedDeny(c, mysql.TypeLonglong, -1, "0") unsignedAccept(c, mysql.TypeLonglong, 0, "0") unsignedAccept(c, mysql.TypeLonglong, uint64(math.MaxUint64), strvalue(uint64(math.MaxUint64))) unsignedDeny(c, mysql.TypeLonglong, math.MaxUint64*1.1, strvalue(uint64(math.MaxUint64))) // integer from string signedAccept(c, mysql.TypeLong, " 234 ", "234") signedAccept(c, mysql.TypeLong, " 2.35e3 ", "2350") signedAccept(c, mysql.TypeLong, " +2.51 ", "3") signedAccept(c, mysql.TypeLong, " -3.58", "-4") // integer from float signedAccept(c, mysql.TypeLong, 234.5456, "235") signedAccept(c, mysql.TypeLong, -23.45, "-23") // float from string signedAccept(c, mysql.TypeFloat, "23.523", "23.523") signedAccept(c, mysql.TypeFloat, int64(123), "123") signedAccept(c, mysql.TypeFloat, uint64(123), "123") signedAccept(c, mysql.TypeFloat, int(123), "123") signedAccept(c, mysql.TypeFloat, float32(123), "123") signedAccept(c, mysql.TypeFloat, float64(123), "123") signedAccept(c, mysql.TypeDouble, " -23.54", "-23.54") // year signedDeny(c, mysql.TypeYear, 123, "<nil>") signedDeny(c, mysql.TypeYear, 3000, "<nil>") signedAccept(c, mysql.TypeYear, "2000", "2000") // time from string signedAccept(c, mysql.TypeDate, "2012-08-23", "2012-08-23") signedAccept(c, mysql.TypeDatetime, "2012-08-23 12:34:03.123456", "2012-08-23 12:34:03") signedAccept(c, mysql.TypeDatetime, mysql.ZeroDatetime, "0000-00-00 00:00:00") signedAccept(c, mysql.TypeDatetime, int64(0), "0000-00-00 00:00:00") signedAccept(c, mysql.TypeTimestamp, "2012-08-23 12:34:03.123456", "2012-08-23 12:34:03") signedAccept(c, mysql.TypeDuration, "10:11:12", "10:11:12") signedAccept(c, mysql.TypeDuration, mysql.ZeroDatetime, "00:00:00") signedAccept(c, mysql.TypeDuration, mysql.ZeroDuration, "00:00:00") signedDeny(c, mysql.TypeDate, "2012-08-x", "0000-00-00") signedDeny(c, mysql.TypeDatetime, "2012-08-x", "0000-00-00 00:00:00") signedDeny(c, mysql.TypeTimestamp, "2012-08-x", "0000-00-00 00:00:00") signedDeny(c, mysql.TypeDuration, "2012-08-x", "00:00:00") signedDeny(c, mysql.TypeDuration, 0, "<nil>") // string from string signedAccept(c, mysql.TypeString, "abc", "abc") // string from integer signedAccept(c, mysql.TypeString, 5678, "5678") signedAccept(c, mysql.TypeString, mysql.ZeroDuration, "00:00:00") signedAccept(c, mysql.TypeString, mysql.ZeroDatetime, "0000-00-00 00:00:00") signedAccept(c, mysql.TypeString, []byte("123"), "123") //TODO add more tests signedAccept(c, mysql.TypeNewDecimal, 123, "123") signedAccept(c, mysql.TypeNewDecimal, int64(123), "123") signedAccept(c, mysql.TypeNewDecimal, uint64(123), "123") signedAccept(c, mysql.TypeNewDecimal, float32(123), "123") signedAccept(c, mysql.TypeNewDecimal, 123.456, "123.456") signedAccept(c, mysql.TypeNewDecimal, "-123.456", "-123.456") signedAccept(c, mysql.TypeNewDecimal, mysql.NewDecimalFromInt(123, 5), "12300000") signedAccept(c, mysql.TypeNewDecimal, mysql.NewDecimalFromInt(-123, -5), "-0.00123") }
func (s *testColumnSuite) TestGetZeroValue(c *C) { cases := []struct { ft *types.FieldType value types.Datum }{ { types.NewFieldType(mysql.TypeLong), types.NewIntDatum(0), }, { &types.FieldType{ Tp: mysql.TypeLonglong, Flag: mysql.UnsignedFlag, }, types.NewUintDatum(0), }, { types.NewFieldType(mysql.TypeFloat), types.NewFloat32Datum(0), }, { types.NewFieldType(mysql.TypeDouble), types.NewFloat64Datum(0), }, { types.NewFieldType(mysql.TypeNewDecimal), types.NewDecimalDatum(mysql.NewDecimalFromInt(0, 0)), }, { types.NewFieldType(mysql.TypeVarchar), types.NewStringDatum(""), }, { types.NewFieldType(mysql.TypeBlob), types.NewBytesDatum([]byte{}), }, { types.NewFieldType(mysql.TypeDuration), types.NewDurationDatum(mysql.ZeroDuration), }, { types.NewFieldType(mysql.TypeDatetime), types.NewDatum(mysql.ZeroDatetime), }, { types.NewFieldType(mysql.TypeTimestamp), types.NewDatum(mysql.ZeroTimestamp), }, { types.NewFieldType(mysql.TypeDate), types.NewDatum(mysql.ZeroDate), }, { types.NewFieldType(mysql.TypeBit), types.NewDatum(mysql.Bit{Value: 0, Width: mysql.MinBitWidth}), }, { types.NewFieldType(mysql.TypeSet), types.NewDatum(mysql.Set{}), }, } for _, ca := range cases { colInfo := &model.ColumnInfo{FieldType: *ca.ft} zv := getZeroValue(colInfo) c.Assert(zv.Kind(), Equals, ca.value.Kind()) cmp, err := zv.CompareDatum(ca.value) c.Assert(err, IsNil) c.Assert(cmp, Equals, 0) } }
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 (s *testAggFuncSuite) TestXAPISum(c *C) { defer testleak.AfterTest(c)() // Compose aggregate exec for "select sum(c2) from t groupby c1"; // // Data in region1: // c1 c2 // 1 11 // 2 21 // 1 1 // // Partial aggregate result for region1: // groupkey sum // 1 12 // 2 21 // // Data in region2: // 1 nil // 1 3 // 3 31 // // Partial aggregate result for region2: // groupkey sum // 1 3 // 3 31 // // Expected final aggregate result: // sum(c2) // 15 // 21 // 31 c1 := ast.NewValueExpr([]byte{0}) rf1 := &ast.ResultField{Expr: c1} c2 := ast.NewValueExpr(0) rf2 := &ast.ResultField{Expr: c2} col2 := &ast.ColumnNameExpr{Refer: rf2} fc := &ast.AggregateFuncExpr{ F: ast.AggFuncSum, Args: []ast.ExprNode{col2}, } // Return row: // GroupKey, Sum // Partial result from region1 row1 := types.MakeDatums([]byte{1}, 12) row2 := types.MakeDatums([]byte{2}, 21) // Partial result from region2 row3 := types.MakeDatums([]byte{1}, 3) row4 := types.MakeDatums([]byte{3}, 31) data := []([]types.Datum){row1, row2, row3, row4} rows := make([]*Row, 0, 3) for _, d := range data { rows = append(rows, &Row{Data: d}) } src := &mockExec{ rows: rows, fields: []*ast.ResultField{rf1, rf2}, } agg := &XAggregateExec{ AggFuncs: []*ast.AggregateFuncExpr{fc}, Src: src, } ast.SetFlag(fc) // First row: 15 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(15), 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: 31 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(31), 0))) agg.Close() // After clear up, fc's value should be default. val, err = evaluator.Eval(ctx, fc) c.Assert(err, IsNil) c.Assert(val, testutil.DatumEquals, types.NewDatum(nil)) }
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) c.Assert(expr.Clone(), NotNil) expr = NewBinaryOperation(t.op, mock, Value{t.arg}) _, err = expr.Eval(nil, nil) c.Assert(err, NotNil) c.Assert(expr.Clone(), 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) }
func (s *testBinOpSuite) TestNumericOp(c *C) { tbl := []struct { lhs interface{} op opcode.Op rhs interface{} ret interface{} }{ // plus {1, opcode.Plus, 1, 2}, {1, opcode.Plus, uint64(1), 2}, {1, opcode.Plus, "1", 2}, {1, opcode.Plus, mysql.NewDecimalFromInt(1, 0), 2}, {uint64(1), opcode.Plus, 1, 2}, {uint64(1), opcode.Plus, uint64(1), 2}, {1, opcode.Plus, []byte("1"), 2}, {1, opcode.Plus, mysql.Hex{Value: 1}, 2}, {1, opcode.Plus, mysql.Bit{Value: 1, Width: 1}, 2}, {1, opcode.Plus, mysql.Enum{Name: "a", Value: 1}, 2}, {1, opcode.Plus, mysql.Set{Name: "a", Value: 1}, 2}, // minus {1, opcode.Minus, 1, 0}, {1, opcode.Minus, uint64(1), 0}, {1, opcode.Minus, float64(1), 0}, {1, opcode.Minus, mysql.NewDecimalFromInt(1, 0), 0}, {uint64(1), opcode.Minus, 1, 0}, {uint64(1), opcode.Minus, uint64(1), 0}, {mysql.NewDecimalFromInt(1, 0), opcode.Minus, 1, 0}, {"1", opcode.Minus, []byte("1"), 0}, // mul {1, opcode.Mul, 1, 1}, {1, opcode.Mul, uint64(1), 1}, {1, opcode.Mul, float64(1), 1}, {1, opcode.Mul, mysql.NewDecimalFromInt(1, 0), 1}, {uint64(1), opcode.Mul, 1, 1}, {uint64(1), opcode.Mul, uint64(1), 1}, {mysql.Time{}, opcode.Mul, 0, 0}, {mysql.ZeroDuration, opcode.Mul, 0, 0}, {mysql.Time{Time: time.Now(), Fsp: 0, Type: mysql.TypeDatetime}, opcode.Mul, 0, 0}, {mysql.Time{Time: time.Now(), Fsp: 6, Type: mysql.TypeDatetime}, opcode.Mul, 0, 0}, {mysql.Duration{Duration: 100000000, Fsp: 6}, opcode.Mul, 0, 0}, // div {1, opcode.Div, float64(1), 1}, {1, opcode.Div, float64(0), nil}, {1, opcode.Div, 2, 0.5}, {1, opcode.Div, 0, nil}, // int div {1, opcode.IntDiv, 2, 0}, {1, opcode.IntDiv, uint64(2), 0}, {1, opcode.IntDiv, 0, nil}, {1, opcode.IntDiv, uint64(0), nil}, {uint64(1), opcode.IntDiv, 2, 0}, {uint64(1), opcode.IntDiv, uint64(2), 0}, {uint64(1), opcode.IntDiv, 0, nil}, {uint64(1), opcode.IntDiv, uint64(0), nil}, {1.0, opcode.IntDiv, 2.0, 0}, {1.0, opcode.IntDiv, 0, nil}, // mod {10, opcode.Mod, 2, 0}, {10, opcode.Mod, uint64(2), 0}, {10, opcode.Mod, 0, nil}, {10, opcode.Mod, uint64(0), nil}, {-10, opcode.Mod, uint64(2), 0}, {uint64(10), opcode.Mod, 2, 0}, {uint64(10), opcode.Mod, uint64(2), 0}, {uint64(10), opcode.Mod, 0, nil}, {uint64(10), opcode.Mod, uint64(0), nil}, {uint64(10), opcode.Mod, -2, 0}, {float64(10), opcode.Mod, 2, 0}, {float64(10), opcode.Mod, 0, nil}, {mysql.NewDecimalFromInt(10, 0), opcode.Mod, 2, 0}, {mysql.NewDecimalFromInt(10, 0), opcode.Mod, 0, nil}, } for _, t := range tbl { expr := NewBinaryOperation(t.op, Value{t.lhs}, Value{t.rhs}) v, err := expr.Eval(nil, nil) c.Assert(err, IsNil) switch v.(type) { case nil: c.Assert(t.ret, IsNil) default: // we use float64 as the result type check for all. f, err := types.ToFloat64(v) c.Assert(err, IsNil) r, err := types.ToFloat64(t.ret) c.Assert(err, IsNil) c.Assert(r, Equals, f) } } // test error expr := &BinaryOperation{} _, err := expr.evalPlus(1, 1) c.Assert(err, NotNil) _, err = expr.evalMinus(1, 1) c.Assert(err, NotNil) _, err = expr.evalMul(1, 1) c.Assert(err, NotNil) _, err = expr.evalDiv("abc", 1) c.Assert(err, NotNil) _, err = expr.evalDiv(float64(1), "abc") c.Assert(err, NotNil) _, err = expr.evalDiv(1, "abc") c.Assert(err, NotNil) _, err = expr.evalIntDiv("abc", 1) c.Assert(err, NotNil) _, err = expr.evalIntDiv(1, "abc") c.Assert(err, NotNil) _, err = expr.evalMod("abc", 1) c.Assert(err, NotNil) expr.L = Value{1} expr.R = Value{1} _, err = expr.evalArithmeticOp(nil, nil) c.Assert(err, NotNil) expr.L = mockExpr{err: errors.New("must error")} _, err = expr.evalArithmeticOp(nil, nil) c.Assert(err, NotNil) expr.L = Value{"abc"} expr.R = Value{1} _, err = expr.evalArithmeticOp(nil, nil) c.Assert(err, NotNil) expr.L = Value{[]byte("abc")} expr.R = Value{1} _, err = expr.evalArithmeticOp(nil, nil) c.Assert(err, NotNil) expr.L = Value{1} expr.R = Value{"abc"} _, err = expr.evalArithmeticOp(nil, nil) c.Assert(err, NotNil) expr.Op = 0 _, err = expr.Eval(nil, nil) c.Assert(err, NotNil) expr.L = NewTestRow(1, 2) expr.R = Value{nil} expr.Op = opcode.Plus _, err = expr.Eval(nil, nil) c.Assert(err, NotNil) expr.Op = opcode.LE _, err = expr.Eval(nil, nil) c.Assert(err, NotNil) expr.R = NewTestRow(1, 2) expr.Op = opcode.Plus _, err = expr.Eval(nil, nil) c.Assert(err, NotNil) expr.L = NewTestRow(1, 2) expr.R = NewTestRow(1, 2) expr.Op = opcode.Plus _, err = expr.Eval(nil, nil) c.Assert(err, NotNil) }
func (s *testCompareSuite) TestCompare(c *check.C) { 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}, {mysql.NewDecimalFromInt(1, 0), []byte("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: time.Now(), Type: mysql.TypeDatetime, Fsp: 0}, -1}, {"12:00:00", mysql.ZeroDuration, 1}, {mysql.ZeroDuration, mysql.ZeroDuration, 0}, {mysql.Time{Time: time.Now().Add(time.Second * 10), Type: mysql.TypeDatetime, Fsp: 0}, mysql.Time{Time: time.Now(), Type: mysql.TypeDatetime, Fsp: 0}, 1}, {nil, 2, -1}, {nil, nil, 0}, {false, nil, 1}, {false, true, -1}, {true, true, 0}, {false, false, 0}, {true, 2, -1}, {float64(1.23), nil, 1}, {float64(0.0), float64(3.45), -1}, {float64(354.23), float64(3.45), 1}, {float64(3.452), float64(3.452), 0}, {int(432), nil, 1}, {-4, int(32), -1}, {int(4), -32, 1}, {int(432), int64(12), 1}, {int(23), int64(128), -1}, {int(123), int64(123), 0}, {int(432), int(12), 1}, {int(23), int(123), -1}, {int64(133), int(183), -1}, {uint64(133), uint64(183), -1}, {uint64(2), int64(-2), 1}, {uint64(2), int64(1), 1}, {"", nil, 1}, {"", "24", -1}, {"aasf", "4", 1}, {"", "", 0}, {[]byte(""), nil, 1}, {[]byte(""), []byte("sff"), -1}, {mysql.Time{}, nil, 1}, {mysql.Time{}, mysql.Time{Time: time.Now(), Type: mysql.TypeDatetime, Fsp: 3}, -1}, {mysql.Time{Time: time.Now(), Type: mysql.TypeDatetime, Fsp: 3}, "0000-00-00 00:00:00", 1}, {mysql.Duration{Duration: time.Duration(34), Fsp: 2}, nil, 1}, {mysql.Duration{Duration: time.Duration(34), Fsp: 2}, mysql.Duration{Duration: time.Duration(29034), Fsp: 2}, -1}, {mysql.Duration{Duration: time.Duration(3340), Fsp: 2}, mysql.Duration{Duration: time.Duration(34), Fsp: 2}, 1}, {mysql.Duration{Duration: time.Duration(34), Fsp: 2}, mysql.Duration{Duration: time.Duration(34), Fsp: 2}, 0}, {[]byte{}, []byte{}, 0}, {[]byte("abc"), []byte("ab"), 1}, {[]byte("123"), 1234, -1}, {[]byte{}, nil, 1}, {[]interface{}{1, 2, 3}, []interface{}{1, 2, 3}, 0}, {[]interface{}{1, 3, 3}, []interface{}{1, 2, 3}, 1}, {[]interface{}{1, 2, 3}, []interface{}{2, 2, 3}, -1}, {mysql.Hex{Value: 1}, 1, 0}, {mysql.Hex{Value: 0x4D7953514C}, "MySQL", 0}, {mysql.Hex{Value: 0}, uint64(10), -1}, {mysql.Hex{Value: 1}, float64(0), 1}, {mysql.Hex{Value: 1}, mysql.NewDecimalFromInt(1, 0), 0}, {mysql.Hex{Value: 1}, mysql.Bit{Value: 0, Width: 1}, 1}, {mysql.Hex{Value: 1}, mysql.Hex{Value: 1}, 0}, {mysql.Bit{Value: 1, Width: 1}, 1, 0}, {mysql.Bit{Value: 0x41, Width: 8}, "A", 0}, {mysql.Bit{Value: 1, Width: 1}, uint64(10), -1}, {mysql.Bit{Value: 1, Width: 1}, float64(0), 1}, {mysql.Bit{Value: 1, Width: 1}, mysql.NewDecimalFromInt(1, 0), 0}, {mysql.Bit{Value: 1, Width: 1}, mysql.Hex{Value: 2}, -1}, {mysql.Bit{Value: 1, Width: 1}, mysql.Bit{Value: 1, Width: 1}, 0}, {mysql.Enum{Name: "a", Value: 1}, 1, 0}, {mysql.Enum{Name: "a", Value: 1}, "a", 0}, {mysql.Enum{Name: "a", Value: 1}, uint64(10), -1}, {mysql.Enum{Name: "a", Value: 1}, float64(0), 1}, {mysql.Enum{Name: "a", Value: 1}, mysql.NewDecimalFromInt(1, 0), 0}, {mysql.Enum{Name: "a", Value: 1}, mysql.Hex{Value: 2}, -1}, {mysql.Enum{Name: "a", Value: 1}, mysql.Bit{Value: 1, Width: 1}, 0}, {mysql.Enum{Name: "a", Value: 1}, mysql.Hex{Value: 1}, 0}, {mysql.Enum{Name: "a", Value: 1}, mysql.Enum{Name: "a", Value: 1}, 0}, {mysql.Set{Name: "a", Value: 1}, 1, 0}, {mysql.Set{Name: "a", Value: 1}, "a", 0}, {mysql.Set{Name: "a", Value: 1}, uint64(10), -1}, {mysql.Set{Name: "a", Value: 1}, float64(0), 1}, {mysql.Set{Name: "a", Value: 1}, mysql.NewDecimalFromInt(1, 0), 0}, {mysql.Set{Name: "a", Value: 1}, mysql.Hex{Value: 2}, -1}, {mysql.Set{Name: "a", Value: 1}, mysql.Bit{Value: 1, Width: 1}, 0}, {mysql.Set{Name: "a", Value: 1}, mysql.Hex{Value: 1}, 0}, {mysql.Set{Name: "a", Value: 1}, mysql.Enum{Name: "a", Value: 1}, 0}, {mysql.Set{Name: "a", Value: 1}, mysql.Set{Name: "a", Value: 1}, 0}, } for i, t := range cmpTbl { comment := check.Commentf("%d %v %v", i, t.lhs, t.rhs) ret, err := Compare(t.lhs, t.rhs) c.Assert(err, check.IsNil) c.Assert(ret, check.Equals, t.ret, comment) ret, err = Compare(t.rhs, t.lhs) c.Assert(err, check.IsNil) c.Assert(ret, check.Equals, -t.ret, comment) } }