func (s *testTypeEtcSuite) TestCoerce(c *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) }
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)}, // 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)}, // 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)}, } 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.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 *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}, // 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}, // 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}, // 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{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) }
func (s *testBinOpSuite) TestComparisonOp(c *C) { tbl := []struct { lhs interface{} op opcode.Op rhs interface{} result int8 // 0 for false, 1 for true }{ // test EQ {1, opcode.EQ, 2, 0}, {false, opcode.EQ, false, 1}, {false, opcode.EQ, true, 0}, {true, opcode.EQ, true, 1}, {true, opcode.EQ, false, 0}, {"1", opcode.EQ, true, 1}, {"1", opcode.EQ, false, 0}, // test NEQ {1, opcode.NE, 2, 1}, {false, opcode.NE, false, 0}, {false, opcode.NE, true, 1}, {true, opcode.NE, true, 0}, {"1", opcode.NE, true, 0}, {"1", opcode.NE, false, 1}, // test GT, GE {1, opcode.GT, 0, 1}, {1, opcode.GT, 1, 0}, {1, opcode.GE, 1, 1}, {3.14, opcode.GT, 3, 1}, {3.14, opcode.GE, 3.14, 1}, // test LT, LE {1, opcode.LT, 2, 1}, {1, opcode.LT, 1, 0}, {1, opcode.LE, 1, 1}, } for _, t := range tbl { expr := NewBinaryOperation(t.op, Value{t.lhs}, Value{t.rhs}) v, err := expr.Eval(nil, nil) c.Assert(err, IsNil) val, err := types.ToBool(v) c.Assert(err, IsNil) c.Assert(val, Equals, t.result) } // test nil nilTbl := []struct { lhs interface{} op opcode.Op rhs interface{} }{ {nil, opcode.EQ, nil}, {nil, opcode.EQ, 1}, {nil, opcode.NE, nil}, {nil, opcode.NE, 1}, {nil, opcode.LT, nil}, {nil, opcode.LT, 1}, {nil, opcode.LE, nil}, {nil, opcode.LE, 1}, {nil, opcode.GT, nil}, {nil, opcode.GT, 1}, {nil, opcode.GE, nil}, {nil, opcode.GE, 1}, } for _, t := range nilTbl { expr := NewBinaryOperation(t.op, Value{t.lhs}, Value{t.rhs}) v, err := expr.Eval(nil, nil) c.Assert(err, IsNil) c.Assert(v, IsNil) } // test evalCompare function cmpTbl := []struct { lhs interface{} rhs interface{} ret int // 0, 1, -1 }{ {float64(1), float64(1), 0}, {float64(1), "1", 0}, {int64(1), int64(1), 0}, {int64(-1), uint64(1), -1}, {int64(-1), "-1", 0}, {uint64(1), uint64(1), 0}, {uint64(1), int64(-1), 1}, {uint64(1), "1", 0}, {mysql.NewDecimalFromInt(1, 0), mysql.NewDecimalFromInt(1, 0), 0}, {mysql.NewDecimalFromInt(1, 0), "1", 0}, {"1", "1", 0}, {"1", int64(-1), 1}, {"1", float64(2), -1}, {"1", uint64(1), 0}, {"1", mysql.NewDecimalFromInt(1, 0), 0}, {"2011-01-01 11:11:11", mysql.Time{time.Now(), mysql.TypeDatetime, 0}, -1}, {"12:00:00", mysql.ZeroDuration, 1}, {mysql.ZeroDuration, mysql.ZeroDuration, 0}, {mysql.Time{time.Now().Add(time.Second * 10), mysql.TypeDatetime, 0}, mysql.Time{time.Now(), mysql.TypeDatetime, 0}, 1}, } for _, t := range cmpTbl { ret, err := evalCompare(t.lhs, t.rhs) c.Assert(err, IsNil) c.Assert(ret, Equals, t.ret) ret, err = evalCompare(t.rhs, t.lhs) c.Assert(err, IsNil) c.Assert(ret, Equals, -t.ret) } // test error mock := mockExpr{ isStatic: false, err: errors.New("must error"), } errTbl := []struct { arg interface{} op opcode.Op }{ {1, opcode.EQ}, {1.1, opcode.NE}, {mysql.NewDecimalFromInt(1, 0), opcode.LT}, {1, opcode.LE}, {1.1, opcode.GT}, {1, opcode.GE}, } for _, t := range errTbl { expr := NewBinaryOperation(t.op, Value{t.arg}, mock) _, err := expr.Eval(nil, nil) c.Assert(err, NotNil) _, err = expr.Clone() c.Assert(err, NotNil) expr = NewBinaryOperation(t.op, mock, Value{t.arg}) _, err = expr.Eval(nil, nil) c.Assert(err, NotNil) _, err = expr.Clone() c.Assert(err, NotNil) } mock.err = nil mock.val = "abc" for _, t := range errTbl { expr := NewBinaryOperation(t.op, Value{t.arg}, mock) _, err := expr.Eval(nil, nil) c.Assert(err, NotNil) expr = NewBinaryOperation(t.op, mock, Value{t.arg}) _, err = expr.Eval(nil, nil) c.Assert(err, NotNil) } expr := BinaryOperation{Op: opcode.Plus, L: Value{1}, R: Value{1}} _, err := expr.evalComparisonOp(nil, nil) c.Assert(err, NotNil) _, err = evalCompare(1, 1) c.Assert(err, NotNil) }
func (s *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) }
func (s *testTypeConvertSuite) TestConvert(c *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 *testCompareSuite) TestCompare(c *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(1.23), float32(3.45), -1}, {float64(354.23), float32(3.45), 1}, {float64(0.0), float64(3.45), -1}, {float64(354.23), float64(3.45), 1}, {float64(3.452), float64(3.452), 0}, {float32(1.23), nil, 1}, {int(432), nil, 1}, {-4, int(32), -1}, {int(4), -32, 1}, {int(432), int8(12), 1}, {int(23), int8(28), -1}, {int(123), int8(123), 0}, {int(432), int16(12), 1}, {int(23), int16(128), -1}, {int(123), int16(123), 0}, {int(432), int32(12), 1}, {int(23), int32(128), -1}, {int(123), int32(123), 0}, {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}, {int8(3), int(3), 0}, {int16(923), int(180), 1}, {int32(173), int(120), 1}, {int64(133), int(183), -1}, {uint(23), nil, 1}, {uint(23), uint(123), -1}, {uint8(3), uint8(3), 0}, {uint16(923), uint16(180), 1}, {uint32(173), uint32(120), 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}, } for _, t := range cmpTbl { ret, err := Compare(t.lhs, t.rhs) c.Assert(err, IsNil) c.Assert(ret, Equals, t.ret) ret, err = Compare(t.rhs, t.lhs) c.Assert(err, IsNil) c.Assert(ret, Equals, -t.ret) } cmpError := []struct { lhs interface{} rhs interface{} }{ {[]interface{}{1}, 1}, {[]interface{}{1}, []interface{}{1, 2}}, {mysql.NewDecimalFromInt(1, 0), "++abc"}, {float64(1.0), "++abc"}, {[]interface{}{1}, []interface{}{"+-abc"}}, } for _, t := range cmpError { _, err := Compare(t.lhs, t.rhs) c.Assert(err, NotNil) _, err = Compare(t.rhs, t.lhs) c.Assert(err, NotNil) } }
// CastValue casts a value based on column's type. func (c *Col) CastValue(ctx context.Context, val interface{}) (casted interface{}, err error) { if val == nil { return } switch c.Tp { case mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong, mysql.TypeYear, mysql.TypeBit: intVal, errCode := c.normalizeIntegerValue(val) if errCode == errCodeType { casted = intVal err = c.TypeError(val) return } return c.castIntegerValue(intVal, errCode) case mysql.TypeFloat, mysql.TypeDouble: return c.castFloatValue(val) case mysql.TypeDate, mysql.TypeDatetime, mysql.TypeTimestamp: switch v := val.(type) { case int64: casted, err = mysql.ParseTimeFromNum(v, c.Tp, c.Decimal) if err != nil { err = newParseColError(err, c) } case string: casted, err = mysql.ParseTime(v, c.Tp, c.Decimal) if err != nil { err = newParseColError(err, c) } case mysql.Time: var t mysql.Time t, err = v.Convert(c.Tp) if err != nil { err = newParseColError(err, c) return } casted, err = t.RoundFrac(c.Decimal) if err != nil { err = newParseColError(err, c) } default: err = c.TypeError(val) } case mysql.TypeDuration: switch v := val.(type) { case string: casted, err = mysql.ParseDuration(v, c.Decimal) if err != nil { err = newParseColError(err, c) } case mysql.Time: var t mysql.Duration t, err = v.ConvertToDuration() if err != nil { err = newParseColError(err, c) return } casted, err = t.RoundFrac(c.Decimal) if err != nil { err = newParseColError(err, c) } case mysql.Duration: casted, err = v.RoundFrac(c.Decimal) default: err = c.TypeError(val) } case mysql.TypeBlob, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob, mysql.TypeString, mysql.TypeVarchar, mysql.TypeVarString: strV := "" switch v := val.(type) { case mysql.Time: strV = v.String() case mysql.Duration: strV = v.String() case []byte: if c.Charset == charset.CharsetBin { casted = v return } strV = string(v) default: strV = fmt.Sprintf("%v", val) } if (c.Flen != types.UnspecifiedLength) && (len(strV) > c.Flen) { strV = strV[:c.Flen] } casted = strV case mysql.TypeDecimal, mysql.TypeNewDecimal: switch v := val.(type) { case string: casted, err = mysql.ParseDecimal(v) if err != nil { err = newParseColError(err, c) } case int8: casted = mysql.NewDecimalFromInt(int64(v), 0) case int16: casted = mysql.NewDecimalFromInt(int64(v), 0) case int32: casted = mysql.NewDecimalFromInt(int64(v), 0) case int64: casted = mysql.NewDecimalFromInt(int64(v), 0) case int: casted = mysql.NewDecimalFromInt(int64(v), 0) case uint8: casted = mysql.NewDecimalFromUint(uint64(v), 0) case uint16: casted = mysql.NewDecimalFromUint(uint64(v), 0) case uint32: casted = mysql.NewDecimalFromUint(uint64(v), 0) case uint64: casted = mysql.NewDecimalFromUint(uint64(v), 0) case uint: casted = mysql.NewDecimalFromUint(uint64(v), 0) case float32: casted = mysql.NewDecimalFromFloat(float64(v)) case float64: casted = mysql.NewDecimalFromFloat(float64(v)) case mysql.Decimal: casted = v } default: err = c.TypeError(val) } return }
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 *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 { // create a call and use dummy args. e, err := NewCall(t.F, []expression.Expression{Value{nil}}, t.Distinct) c.Assert(err, IsNil) call, ok := e.(*Call) c.Assert(ok, IsTrue) m := map[interface{}]interface{}{} for _, arg := range t.RoundArgs { call.Args = []expression.Expression{Value{arg}} _, err = call.Eval(nil, m) } m[ExprAggDone] = struct{}{} v, err := e.Eval(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) } } }