Пример #1
0
func (s *testTypeConvertSuite) TestConvertToBool(c *C) {
	testToBool(c, int(0), 0)
	testToBool(c, int64(0), 0)
	testToBool(c, uint64(0), 0)
	testToBool(c, float32(0), 0)
	testToBool(c, float64(0), 0)
	testToBool(c, "", 0)
	testToBool(c, "0", 0)
	testToBool(c, []byte{}, 0)
	testToBool(c, []byte("0"), 0)
	testToBool(c, mysql.Hex{Value: 0}, 0)
	testToBool(c, mysql.Bit{Value: 0, Width: 8}, 0)
	testToBool(c, mysql.Enum{Name: "a", Value: 1}, 1)
	testToBool(c, mysql.Set{Name: "a", Value: 1}, 1)

	t, err := mysql.ParseTime("2011-11-10 11:11:11.999999", mysql.TypeTimestamp, 6)
	c.Assert(err, IsNil)
	testToBool(c, t, 1)

	td, err := mysql.ParseDuration("11:11:11.999999", 6)
	c.Assert(err, IsNil)
	testToBool(c, td, 1)

	ft := NewFieldType(mysql.TypeNewDecimal)
	ft.Decimal = 5
	v, err := Convert(3.1415926, ft)
	c.Assert(err, IsNil)
	testToBool(c, v, 1)

	_, err = ToBool(&invalidMockType{})
	c.Assert(err, NotNil)
}
Пример #2
0
func (s *testTypeConvertSuite) TestConvertToString(c *C) {
	testToString(c, "0", "0")
	testToString(c, true, "1")
	testToString(c, "false", "false")
	testToString(c, int(0), "0")
	testToString(c, int8(0), "0")
	testToString(c, int16(0), "0")
	testToString(c, int32(0), "0")
	testToString(c, int64(0), "0")
	testToString(c, uint(0), "0")
	testToString(c, uint8(0), "0")
	testToString(c, uint16(0), "0")
	testToString(c, uint32(0), "0")
	testToString(c, uint64(0), "0")
	testToString(c, float32(1.6), "1.6")
	testToString(c, float64(-0.6), "-0.6")
	testToString(c, []byte{1}, "\x01")

	t, err := mysql.ParseTime("2011-11-10 11:11:11.999999", mysql.TypeTimestamp, 6)
	c.Assert(err, IsNil)
	testToString(c, t, "2011-11-10 11:11:11.999999")

	td, err := mysql.ParseDuration("11:11:11.999999", 6)
	c.Assert(err, IsNil)
	testToString(c, td, "11:11:11.999999")

	ft := NewFieldType(mysql.TypeNewDecimal)
	ft.Decimal = 5
	v, err := Convert(3.1415926, ft)
	c.Assert(err, IsNil)
	testToString(c, v, "3.14159")

	_, err = ToString(&invalidMockType{})
	c.Assert(err, NotNil)
}
Пример #3
0
func (s *testTypeConvertSuite) TestConvertToString(c *C) {
	testToString(c, "0", "0")
	testToString(c, true, "1")
	testToString(c, "false", "false")
	testToString(c, int(0), "0")
	testToString(c, int64(0), "0")
	testToString(c, uint64(0), "0")
	testToString(c, float32(1.6), "1.6")
	testToString(c, float64(-0.6), "-0.6")
	testToString(c, []byte{1}, "\x01")
	testToString(c, mysql.Hex{Value: 0x4D7953514C}, "MySQL")
	testToString(c, mysql.Bit{Value: 0x41, Width: 8}, "A")
	testToString(c, mysql.Enum{Name: "a", Value: 1}, "a")
	testToString(c, mysql.Set{Name: "a", Value: 1}, "a")

	t, err := mysql.ParseTime("2011-11-10 11:11:11.999999", mysql.TypeTimestamp, 6)
	c.Assert(err, IsNil)
	testToString(c, t, "2011-11-10 11:11:11.999999")

	td, err := mysql.ParseDuration("11:11:11.999999", 6)
	c.Assert(err, IsNil)
	testToString(c, td, "11:11:11.999999")

	ft := NewFieldType(mysql.TypeNewDecimal)
	ft.Decimal = 5
	v, err := Convert(3.1415926, ft)
	c.Assert(err, IsNil)
	testToString(c, v, "3.14159")

	_, err = ToString(&invalidMockType{})
	c.Assert(err, NotNil)
}
Пример #4
0
func (s *testTypeConvertSuite) TestConvertToFloat64(c *C) {
	testToFloat64(c, "0", float64(0))
	testToFloat64(c, int(0), float64(0))
	testToFloat64(c, int64(0), float64(0))
	testToFloat64(c, uint64(0), float64(0))
	// TODO: check this
	//testToFloat64(c, float32(3.1), float64(3.1))
	testToFloat64(c, float64(3.1), float64(3.1))
	testToFloat64(c, mysql.Hex{Value: 100}, float64(100))
	testToFloat64(c, mysql.Bit{Value: 100, Width: 8}, float64(100))
	testToFloat64(c, mysql.Enum{Name: "a", Value: 1}, float64(1))
	testToFloat64(c, mysql.Set{Name: "a", Value: 1}, float64(1))

	t, err := mysql.ParseTime("2011-11-10 11:11:11.999999", mysql.TypeTimestamp, 6)
	c.Assert(err, IsNil)
	testToFloat64(c, t, float64(20111110111111.999999))

	td, err := mysql.ParseDuration("11:11:11.999999", 6)
	c.Assert(err, IsNil)
	testToFloat64(c, td, float64(111111.999999))

	ft := NewFieldType(mysql.TypeNewDecimal)
	ft.Decimal = 5
	v, err := Convert(3.1415926, ft)
	c.Assert(err, IsNil)
	testToFloat64(c, v, float64(3.14159))

	_, err = ToFloat64(&invalidMockType{})
	c.Assert(err, NotNil)
}
Пример #5
0
func (s *testTypeConvertSuite) TestConvertToInt64(c *C) {
	testToInt64(c, "0", int64(0))
	testToInt64(c, int(0), int64(0))
	testToInt64(c, int64(0), int64(0))
	testToInt64(c, uint64(0), int64(0))
	testToInt64(c, float32(3.1), int64(3))
	testToInt64(c, float64(3.1), int64(3))
	testToInt64(c, mysql.Hex{Value: 100}, int64(100))
	testToInt64(c, mysql.Bit{Value: 100, Width: 8}, int64(100))

	t, err := mysql.ParseTime("2011-11-10 11:11:11.999999", mysql.TypeTimestamp, 0)
	c.Assert(err, IsNil)
	testToInt64(c, t, int64(20111110111112))

	td, err := mysql.ParseDuration("11:11:11.999999", 6)
	c.Assert(err, IsNil)
	testToInt64(c, td, int64(111112))

	ft := NewFieldType(mysql.TypeNewDecimal)
	ft.Decimal = 5
	v, err := Convert(3.1415926, ft)
	c.Assert(err, IsNil)
	testToInt64(c, v, int64(3))

	_, err = ToInt64(&invalidMockType{})
	c.Assert(err, NotNil)
}
Пример #6
0
func (s *testTypeConvertSuite) TestConvertToFloat64(c *C) {
	testToFloat64(c, "0", float64(0))
	testToFloat64(c, false, float64(0))
	testToFloat64(c, true, float64(1))
	testToFloat64(c, int(0), float64(0))
	testToFloat64(c, int8(0), float64(0))
	testToFloat64(c, int16(0), float64(0))
	testToFloat64(c, int32(0), float64(0))
	testToFloat64(c, int64(0), float64(0))
	testToFloat64(c, uint(0), float64(0))
	testToFloat64(c, uint8(0), float64(0))
	testToFloat64(c, uint16(0), float64(0))
	testToFloat64(c, uint32(0), float64(0))
	testToFloat64(c, uint64(0), float64(0))
	// TODO: check this
	//testToFloat64(c, float32(3.1), float64(3.1))
	testToFloat64(c, float64(3.1), float64(3.1))

	t, err := mysql.ParseTime("2011-11-10 11:11:11.999999", mysql.TypeTimestamp, 6)
	c.Assert(err, IsNil)
	testToFloat64(c, t, float64(20111110111111.999999))

	td, err := mysql.ParseDuration("11:11:11.999999", 6)
	c.Assert(err, IsNil)
	testToFloat64(c, td, float64(111111.999999))

	ft := NewFieldType(mysql.TypeNewDecimal)
	ft.Decimal = 5
	v, err := Convert(3.1415926, ft)
	c.Assert(err, IsNil)
	testToFloat64(c, v, float64(3.14159))

	_, err = ToFloat64(&invalidMockType{})
	c.Assert(err, NotNil)
}
Пример #7
0
func (s *testTypeConvertSuite) TestConvertToBool(c *C) {
	testToBool(c, false, int8(0))
	testToBool(c, int(0), int8(0))
	testToBool(c, int8(0), int8(0))
	testToBool(c, int16(0), int8(0))
	testToBool(c, int32(0), int8(0))
	testToBool(c, int64(0), int8(0))
	testToBool(c, uint(0), int8(0))
	testToBool(c, uint8(0), int8(0))
	testToBool(c, uint16(0), int8(0))
	testToBool(c, uint32(0), int8(0))
	testToBool(c, uint64(0), int8(0))
	testToBool(c, float32(0), int8(0))
	testToBool(c, float64(0), int8(0))
	testToBool(c, "", int8(0))
	testToBool(c, "0", int8(0))
	testToBool(c, []byte{}, int8(0))
	testToBool(c, []byte("0"), int8(0))

	t, err := mysql.ParseTime("2011-11-10 11:11:11.999999", mysql.TypeTimestamp, 6)
	c.Assert(err, IsNil)
	testToBool(c, t, int8(1))

	td, err := mysql.ParseDuration("11:11:11.999999", 6)
	c.Assert(err, IsNil)
	testToBool(c, td, int8(1))

	ft := NewFieldType(mysql.TypeNewDecimal)
	ft.Decimal = 5
	v, err := Convert(3.1415926, ft)
	c.Assert(err, IsNil)
	testToBool(c, v, int8(1))

	_, err = ToBool(&invalidMockType{})
	c.Assert(err, NotNil)
}
Пример #8
0
// Convert converts the val with type tp.
func Convert(val interface{}, target *FieldType) (v interface{}, err error) { //NTYPE
	tp := target.Tp
	if val == nil {
		return nil, nil
	}
	switch tp { // TODO: implement mysql types convert when "CAST() AS" syntax are supported.
	case mysql.TypeFloat:
		x, err := ToFloat64(val)
		if err != nil {
			return invConv(val, tp)
		}
		if target.Flen != UnspecifiedLength {
			x, err = TruncateFloat(x, target.Flen, target.Decimal)
			if err != nil {
				return nil, errors.Trace(err)
			}
		}
		return float32(x), nil
	case mysql.TypeDouble:
		x, err := ToFloat64(val)
		if err != nil {
			return invConv(val, tp)
		}
		if target.Flen != UnspecifiedLength {
			x, err = TruncateFloat(x, target.Flen, target.Decimal)
			if err != nil {
				return nil, errors.Trace(err)
			}
		}
		return float64(x), nil
	case mysql.TypeBlob, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob,
		mysql.TypeString, mysql.TypeVarchar, mysql.TypeVarString:
		x, err := ToString(val)
		if err != nil {
			return invConv(val, tp)
		}
		// TODO: consider target.Charset/Collate
		x = truncateStr(x, target.Flen)
		if target.Charset == charset.CharsetBin {
			return []byte(x), nil
		}
		return x, nil
	case mysql.TypeDuration:
		fsp := mysql.DefaultFsp
		if target.Decimal != UnspecifiedLength {
			fsp = target.Decimal
		}
		switch x := val.(type) {
		case mysql.Duration:
			return x.RoundFrac(fsp)
		case mysql.Time:
			t, err := x.ConvertToDuration()
			if err != nil {
				return nil, errors.Trace(err)
			}

			return t.RoundFrac(fsp)
		case string:
			return mysql.ParseDuration(x, fsp)
		default:
			return invConv(val, tp)
		}
	case mysql.TypeTimestamp, mysql.TypeDatetime, mysql.TypeDate:
		fsp := mysql.DefaultFsp
		if target.Decimal != UnspecifiedLength {
			fsp = target.Decimal
		}
		switch x := val.(type) {
		case mysql.Time:
			t, err := x.Convert(tp)
			if err != nil {
				return nil, errors.Trace(err)
			}
			return t.RoundFrac(fsp)
		case mysql.Duration:
			t, err := x.ConvertToTime(tp)
			if err != nil {
				return nil, errors.Trace(err)
			}
			return t.RoundFrac(fsp)
		case string:
			return mysql.ParseTime(x, tp, fsp)
		case int64:
			return mysql.ParseTimeFromNum(x, tp, fsp)
		default:
			return invConv(val, tp)
		}
	case mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong:
		unsigned := mysql.HasUnsignedFlag(target.Flag)
		if unsigned {
			return convertToUint(val, target)
		}
		return convertToInt(val, target)
	case mysql.TypeBit:
		x, err := convertToUint(val, target)
		if err != nil {
			return x, errors.Trace(err)
		}

		// check bit boundary, if bit has n width, the boundary is
		// in [0, (1 << n) - 1]
		width := target.Flen
		if width == 0 {
			width = mysql.MinBitWidth
		} else if width == mysql.UnspecifiedBitWidth {
			width = mysql.MaxBitWidth
		}

		maxValue := uint64(1)<<uint64(width) - 1

		if x > maxValue {
			return maxValue, overflow(val, tp)
		}
		return x, nil
	case mysql.TypeDecimal, mysql.TypeNewDecimal:
		x, err := ToDecimal(val)
		if err != nil {
			return invConv(val, tp)
		}
		if target.Decimal != UnspecifiedLength {
			x = x.Round(int32(target.Decimal))
		}
		// TODO: check Flen
		return x, nil
	case mysql.TypeYear:
		var (
			intVal int64
			err    error
		)
		switch x := val.(type) {
		case string:
			intVal, err = StrToInt(x)
		case mysql.Time:
			return int64(x.Year()), nil
		case mysql.Duration:
			return int64(time.Now().Year()), nil
		default:
			intVal, err = ToInt64(x)
		}
		if err != nil {
			return invConv(val, tp)
		}
		y, err := mysql.AdjustYear(int(intVal))
		if err != nil {
			return invConv(val, tp)
		}
		return int64(y), nil
	default:
		panic("should never happen")
	}
}
Пример #9
0
// Cast casts val to certain types and does not return error.
func Cast(val interface{}, target *FieldType) (v interface{}) { //NTYPE
	tp := target.Tp
	switch tp {
	case mysql.TypeString:
		x, _ := ToString(val)
		// TODO: consider target.Charset/Collate
		x = truncateStr(x, target.Flen)
		if target.Charset == charset.CharsetBin {
			return []byte(x)
		}
		return x
	case mysql.TypeDuration:
		var dur mysql.Duration
		fsp := mysql.DefaultFsp
		if target.Decimal != UnspecifiedLength {
			fsp = target.Decimal
		}
		switch x := val.(type) {
		case mysql.Duration:
			dur, _ = x.RoundFrac(fsp)
		case mysql.Time:
			dur, _ = x.ConvertToDuration()
			dur, _ = dur.RoundFrac(fsp)
		case string:
			dur, _ = mysql.ParseDuration(x, fsp)
		}
		return dur
	case mysql.TypeDatetime, mysql.TypeDate:
		fsp := mysql.DefaultFsp
		if target.Decimal != UnspecifiedLength {
			fsp = target.Decimal
		}
		var t mysql.Time
		t.Type = tp
		switch x := val.(type) {
		case mysql.Time:
			t, _ = x.Convert(tp)
			t, _ = t.RoundFrac(fsp)
		case mysql.Duration:
			t, _ = x.ConvertToTime(tp)
			t, _ = t.RoundFrac(fsp)
		case string:
			t, _ = mysql.ParseTime(x, tp, fsp)
		case int64:
			t, _ = mysql.ParseTimeFromNum(x, tp, fsp)
		}
		return t
	case mysql.TypeLonglong:
		if mysql.HasUnsignedFlag(target.Flag) {
			v, _ = ToUint64(val)
		} else {
			v, _ = ToInt64(val)
		}
		return
	case mysql.TypeNewDecimal:
		x, _ := ToDecimal(val)
		if target.Decimal != UnspecifiedLength {
			x = x.Round(int32(target.Decimal))
		}
		// TODO: check Flen
		return x
	default:
		panic("should never happen")
	}
}
Пример #10
0
func parseTime(c *C, s string) mysql.Time {
	m, err := mysql.ParseTime(s, mysql.TypeDatetime, mysql.DefaultFsp)
	c.Assert(err, IsNil)
	return m
}
Пример #11
0
func (s *testTypeConvertSuite) TestConvertType(c *C) {
	ft := NewFieldType(mysql.TypeBlob)
	ft.Flen = 4
	ft.Charset = "utf8"
	v, err := Convert("123456", ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, "1234")
	ft = NewFieldType(mysql.TypeString)
	ft.Flen = 4
	ft.Charset = charset.CharsetBin
	v, err = Convert("12345", ft)
	c.Assert(err, IsNil)
	c.Assert(v, DeepEquals, []byte("1234"))

	ft = NewFieldType(mysql.TypeFloat)
	ft.Flen = 5
	ft.Decimal = 2
	v, err = Convert(111.114, ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, float32(111.11))

	ft = NewFieldType(mysql.TypeFloat)
	ft.Flen = 5
	ft.Decimal = 2
	v, err = Convert(999.999, ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, float32(999.99))

	ft = NewFieldType(mysql.TypeFloat)
	ft.Flen = 5
	ft.Decimal = 2
	v, err = Convert(-999.999, ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, float32(-999.99))

	ft = NewFieldType(mysql.TypeFloat)
	ft.Flen = 5
	ft.Decimal = 2
	v, err = Convert(1111.11, ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, float32(999.99))

	ft = NewFieldType(mysql.TypeFloat)
	ft.Flen = 5
	ft.Decimal = 2
	v, err = Convert(999.916, ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, float32(999.92))

	ft = NewFieldType(mysql.TypeFloat)
	ft.Flen = 5
	ft.Decimal = 2
	v, err = Convert(999.915, ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, float32(999.91))

	ft = NewFieldType(mysql.TypeFloat)
	ft.Flen = 5
	ft.Decimal = 2
	v, err = Convert(999.9155, ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, float32(999.92))

	// For TypeBlob
	ft = NewFieldType(mysql.TypeBlob)
	v, err = Convert(&invalidMockType{}, ft)
	c.Assert(err, NotNil)

	// Nil
	ft = NewFieldType(mysql.TypeBlob)
	v, err = Convert(nil, ft)
	c.Assert(err, IsNil)
	c.Assert(v, IsNil)

	// TypeDouble
	ft = NewFieldType(mysql.TypeDouble)
	ft.Flen = 5
	ft.Decimal = 2
	v, err = Convert(999.9155, ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, float64(999.92))

	// For TypeString
	ft = NewFieldType(mysql.TypeString)
	ft.Flen = 3
	v, err = Convert("12345", ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, "123")
	ft = NewFieldType(mysql.TypeString)
	ft.Flen = 3
	ft.Charset = charset.CharsetBin
	v, err = Convert("12345", ft)
	c.Assert(err, IsNil)
	c.Assert(v, DeepEquals, []byte("123"))

	// For TypeDuration
	ft = NewFieldType(mysql.TypeDuration)
	ft.Decimal = 3
	v, err = Convert("10:11:12.123456", ft)
	c.Assert(err, IsNil)
	c.Assert(v.(mysql.Duration).String(), Equals, "10:11:12.123")
	ft.Decimal = 1
	vv, err := Convert(v, ft)
	c.Assert(err, IsNil)
	c.Assert(vv.(mysql.Duration).String(), Equals, "10:11:12.1")

	vt, err := mysql.ParseTime("2010-10-10 10:11:11.12345", mysql.TypeTimestamp, 2)
	c.Assert(vt.String(), Equals, "2010-10-10 10:11:11.12")
	c.Assert(err, IsNil)
	v, err = Convert(vt, ft)
	c.Assert(err, IsNil)
	c.Assert(v.(mysql.Duration).String(), Equals, "10:11:11.1")

	// For mysql.TypeTimestamp, mysql.TypeDatetime, mysql.TypeDate
	ft = NewFieldType(mysql.TypeTimestamp)
	ft.Decimal = 3
	v, err = Convert("2010-10-10 10:11:11.12345", ft)
	c.Assert(err, IsNil)
	c.Assert(v.(mysql.Time).String(), Equals, "2010-10-10 10:11:11.123")
	ft.Decimal = 1
	vv, err = Convert(v, ft)
	c.Assert(err, IsNil)
	c.Assert(vv.(mysql.Time).String(), Equals, "2010-10-10 10:11:11.1")

	// For TypeLonglong
	ft = NewFieldType(mysql.TypeLonglong)
	v, err = Convert("100", ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, int64(100))
	ft = NewFieldType(mysql.TypeLonglong)
	ft.Flag |= mysql.UnsignedFlag
	v, err = Convert("100", ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, uint64(100))

	// For TypeNewDecimal
	ft = NewFieldType(mysql.TypeNewDecimal)
	ft.Decimal = 5
	v, err = Convert(3.1415926, ft)
	c.Assert(err, IsNil)
	c.Assert(v.(mysql.Decimal).String(), Equals, "3.14159")

	// For TypeYear
	ft = NewFieldType(mysql.TypeYear)
	v, err = Convert("2015-11-11", ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, int16(2015))
	v, err = Convert(2015, ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, int16(2015))
	v, err = Convert(1800, ft)
	c.Assert(err, NotNil)
	dt, err := mysql.ParseDate("2015-11-11")
	c.Assert(err, IsNil)
	v, err = Convert(dt, ft)
	c.Assert(v, Equals, int16(2015))
	v, err = Convert(mysql.ZeroDuration, ft)
	c.Assert(v, Equals, int16(time.Now().Year()))
}
Пример #12
0
Файл: etc.go Проект: npk/tidb
// Compare returns an integer comparing the interface a to b.
// TODO: compare should return errors instead of panicing.
func Compare(a, b interface{}) int {
	switch x := a.(type) {
	case nil:
		if b != nil {
			return -1
		}

		return 0
	case bool:
		switch y := b.(type) {
		case nil:
			return 1
		case bool:
			if !x && y {
				return -1
			}

			if x == y {
				return 0
			}

			return 1
		default:
			// Make bool collate before anything except nil and
			// other bool for index seeking first non NULL value.
			return -1
		}
	case float32:
		return compareFloat64With(float64(x), b)
	case float64:
		return compareFloat64With(float64(x), b)
	case int8:
		return compareInt64With(int64(x), b)
	case int16:
		return compareInt64With(int64(x), b)
	case int32:
		return compareInt64With(int64(x), b)
	case int:
		return compareInt64With(int64(x), b)
	case int64:
		return compareInt64With(int64(x), b)
	case uint8:
		return compareUint64With(uint64(x), b)
	case uint16:
		return compareUint64With(uint64(x), b)
	case uint:
		return compareUint64With(uint64(x), b)
	case uint32:
		return compareUint64With(uint64(x), b)
	case uint64:
		return compareUint64With(uint64(x), b)
	case string:
		switch y := b.(type) {
		case nil:
			return 1
		case string:
			if x < y {
				return -1
			}

			if x == y {
				return 0
			}

			return 1
		default:
			panic("should never happen")
		}
	case []byte:
		switch y := b.(type) {
		case nil:
			return 1
		case []byte:
			return bytes.Compare(x, y)
		default:
			panic("should never happen")
		}
	case mysql.Time:
		switch y := b.(type) {
		case nil:
			return 1
		case mysql.Time:
			return x.Compare(y)
		case string:
			t, err := mysql.ParseTime(y, x.Type, x.Fsp)
			if err != nil {
				log.Warnf("Failed to convert %s to mysql.Time with err %v", y, err)
				return 1
			}
			return x.Compare(t)
		default:
			panic("should never happen")
		}
	case mysql.Duration:
		switch y := b.(type) {
		case nil:
			return 1
		case mysql.Duration:
			if x.Duration < y.Duration {
				return -1
			}

			if x.Duration == y.Duration {
				return 0
			}

			return 1
		default:
			panic("should never happen")
		}
	case mysql.Decimal:
		y, err := ToDecimal(b)
		if err != nil {
			panic(fmt.Sprintf("should never happen, err: %v", err))
		}
		return x.Cmp(y)
	default:
		panic("should never happen")
	}
}
Пример #13
0
// Convert converts the val with type tp.
func Convert(val interface{}, target *FieldType) (v interface{}, err error) { //NTYPE
	tp := target.Tp
	if val == nil {
		return nil, nil
	}
	switch tp { // TODO: implement mysql types convert when "CAST() AS" syntax are supported.
	case mysql.TypeFloat:
		x, err := ToFloat64(val)
		if err != nil {
			return InvConv(val, tp)
		}
		if target.Flen != UnspecifiedLength {
			x, err = TruncateFloat(x, target.Flen, target.Decimal)
			if err != nil {
				return nil, errors.Trace(err)
			}
		}
		return float32(x), nil
	case mysql.TypeDouble:
		x, err := ToFloat64(val)
		if err != nil {
			return InvConv(val, tp)
		}
		if target.Flen != UnspecifiedLength {
			x, err = TruncateFloat(x, target.Flen, target.Decimal)
			if err != nil {
				return nil, errors.Trace(err)
			}
		}
		return float64(x), nil
	case mysql.TypeString:
		x, err := ToString(val)
		if err != nil {
			return InvConv(val, tp)
		}
		// TODO: consider target.Charset/Collate
		x = truncateStr(x, target.Flen)
		if target.Charset == charset.CharsetBin {
			return []byte(x), nil
		}
		return x, nil
	case mysql.TypeBlob:
		x, err := ToString(val)
		if err != nil {
			return InvConv(val, tp)
		}
		x = truncateStr(x, target.Flen)
		if target.Charset == charset.CharsetBin {
			return []byte(x), nil
		}
		return x, nil
	case mysql.TypeDuration:
		fsp := mysql.DefaultFsp
		if target.Decimal != UnspecifiedLength {
			fsp = target.Decimal
		}
		switch x := val.(type) {
		case mysql.Duration:
			return x.RoundFrac(fsp)
		case mysql.Time:
			t, err := x.ConvertToDuration()
			if err != nil {
				return nil, errors.Trace(err)
			}

			return t.RoundFrac(fsp)
		case string:
			return mysql.ParseDuration(x, fsp)
		default:
			return InvConv(val, tp)
		}
	case mysql.TypeTimestamp, mysql.TypeDatetime, mysql.TypeDate:
		fsp := mysql.DefaultFsp
		if target.Decimal != UnspecifiedLength {
			fsp = target.Decimal
		}
		switch x := val.(type) {
		case mysql.Time:
			t, err := x.Convert(tp)
			if err != nil {
				return nil, errors.Trace(err)
			}
			return t.RoundFrac(fsp)
		case mysql.Duration:
			t, err := x.ConvertToTime(tp)
			if err != nil {
				return nil, errors.Trace(err)
			}
			return t.RoundFrac(fsp)
		case string:
			return mysql.ParseTime(x, tp, fsp)
		default:
			return InvConv(val, tp)
		}
	case mysql.TypeLonglong:
		x, err := ToInt64(val)
		if err != nil {
			return InvConv(val, tp)
		}
		// TODO: We should first convert to uint64 then check unsigned flag.
		if mysql.HasUnsignedFlag(target.Flag) {
			return uint64(x), nil
		}
		return x, nil
	case mysql.TypeNewDecimal:
		x, err := ToDecimal(val)
		if err != nil {
			return InvConv(val, tp)
		}
		if target.Decimal != UnspecifiedLength {
			x = x.Round(int32(target.Decimal))
		}
		// TODO: check Flen
		return x, nil
	case mysql.TypeYear:
		var (
			intVal int64
			err    error
		)
		switch x := val.(type) {
		case string:
			intVal, err = StrToInt(x)
		case mysql.Time:
			return int16(x.Year()), nil
		case mysql.Duration:
			return int16(time.Now().Year()), nil
		default:
			intVal, err = ToInt64(x)
		}
		if err != nil {
			return InvConv(val, tp)
		}
		y, err := mysql.AdjustYear(int(intVal))
		if err != nil {
			return InvConv(val, tp)
		}
		return int16(y), nil
	default:
		panic("should never happen")
	}
}
Пример #14
0
func (s *testTypeConvertSuite) TestConvertType(c *C) {
	ft := NewFieldType(mysql.TypeBlob)
	ft.Flen = 4
	ft.Charset = "utf8"
	v, err := Convert("123456", ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, "1234")
	ft = NewFieldType(mysql.TypeString)
	ft.Flen = 4
	ft.Charset = charset.CharsetBin
	v, err = Convert("12345", ft)
	c.Assert(err, IsNil)
	c.Assert(v, DeepEquals, []byte("1234"))

	ft = NewFieldType(mysql.TypeFloat)
	ft.Flen = 5
	ft.Decimal = 2
	v, err = Convert(111.114, ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, float32(111.11))

	ft = NewFieldType(mysql.TypeFloat)
	ft.Flen = 5
	ft.Decimal = 2
	v, err = Convert(999.999, ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, float32(999.99))

	ft = NewFieldType(mysql.TypeFloat)
	ft.Flen = 5
	ft.Decimal = 2
	v, err = Convert(-999.999, ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, float32(-999.99))

	ft = NewFieldType(mysql.TypeFloat)
	ft.Flen = 5
	ft.Decimal = 2
	v, err = Convert(1111.11, ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, float32(999.99))

	ft = NewFieldType(mysql.TypeFloat)
	ft.Flen = 5
	ft.Decimal = 2
	v, err = Convert(999.916, ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, float32(999.92))

	ft = NewFieldType(mysql.TypeFloat)
	ft.Flen = 5
	ft.Decimal = 2
	v, err = Convert(999.915, ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, float32(999.91))

	ft = NewFieldType(mysql.TypeFloat)
	ft.Flen = 5
	ft.Decimal = 2
	v, err = Convert(999.9155, ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, float32(999.92))

	// For TypeBlob
	ft = NewFieldType(mysql.TypeBlob)
	v, err = Convert(&invalidMockType{}, ft)
	c.Assert(err, NotNil)

	// Nil
	ft = NewFieldType(mysql.TypeBlob)
	v, err = Convert(nil, ft)
	c.Assert(err, IsNil)
	c.Assert(v, IsNil)

	// TypeDouble
	ft = NewFieldType(mysql.TypeDouble)
	ft.Flen = 5
	ft.Decimal = 2
	v, err = Convert(999.9155, ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, float64(999.92))

	// For TypeString
	ft = NewFieldType(mysql.TypeString)
	ft.Flen = 3
	v, err = Convert("12345", ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, "123")
	ft = NewFieldType(mysql.TypeString)
	ft.Flen = 3
	ft.Charset = charset.CharsetBin
	v, err = Convert("12345", ft)
	c.Assert(err, IsNil)
	c.Assert(v, DeepEquals, []byte("123"))

	// For TypeDuration
	ft = NewFieldType(mysql.TypeDuration)
	ft.Decimal = 3
	v, err = Convert("10:11:12.123456", ft)
	c.Assert(err, IsNil)
	c.Assert(v.(mysql.Duration).String(), Equals, "10:11:12.123")
	ft.Decimal = 1
	vv, err := Convert(v, ft)
	c.Assert(err, IsNil)
	c.Assert(vv.(mysql.Duration).String(), Equals, "10:11:12.1")

	vt, err := mysql.ParseTime("2010-10-10 10:11:11.12345", mysql.TypeTimestamp, 2)
	c.Assert(vt.String(), Equals, "2010-10-10 10:11:11.12")
	c.Assert(err, IsNil)
	v, err = Convert(vt, ft)
	c.Assert(err, IsNil)
	c.Assert(v.(mysql.Duration).String(), Equals, "10:11:11.1")

	// For mysql.TypeTimestamp, mysql.TypeDatetime, mysql.TypeDate
	ft = NewFieldType(mysql.TypeTimestamp)
	ft.Decimal = 3
	v, err = Convert("2010-10-10 10:11:11.12345", ft)
	c.Assert(err, IsNil)
	c.Assert(v.(mysql.Time).String(), Equals, "2010-10-10 10:11:11.123")
	ft.Decimal = 1
	vv, err = Convert(v, ft)
	c.Assert(err, IsNil)
	c.Assert(vv.(mysql.Time).String(), Equals, "2010-10-10 10:11:11.1")

	// For TypeLonglong
	ft = NewFieldType(mysql.TypeLonglong)
	v, err = Convert("100", ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, int64(100))
	ft = NewFieldType(mysql.TypeLonglong)
	ft.Flag |= mysql.UnsignedFlag
	v, err = Convert("100", ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, uint64(100))

	// For TypeBit
	ft = NewFieldType(mysql.TypeBit)
	ft.Flen = 8
	v, err = Convert("100", ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, mysql.Bit{Value: 100, Width: 8})

	v, err = Convert(mysql.Hex{Value: 100}, ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, mysql.Bit{Value: 100, Width: 8})

	v, err = Convert(mysql.Bit{Value: 100, Width: 8}, ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, mysql.Bit{Value: 100, Width: 8})

	ft.Flen = 1
	v, err = Convert(1, ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, mysql.Bit{Value: 1, Width: 1})

	_, err = Convert(2, ft)
	c.Assert(err, NotNil)

	ft.Flen = 0
	_, err = Convert(2, ft)
	c.Assert(err, NotNil)

	// For TypeNewDecimal
	ft = NewFieldType(mysql.TypeNewDecimal)
	ft.Decimal = 5
	v, err = Convert(3.1415926, ft)
	c.Assert(err, IsNil)
	c.Assert(v.(mysql.Decimal).String(), Equals, "3.14159")

	// For TypeYear
	ft = NewFieldType(mysql.TypeYear)
	v, err = Convert("2015-11-11", ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, int64(2015))
	v, err = Convert(2015, ft)
	c.Assert(err, IsNil)
	c.Assert(v, Equals, int64(2015))
	v, err = Convert(1800, ft)
	c.Assert(err, NotNil)
	dt, err := mysql.ParseDate("2015-11-11")
	c.Assert(err, IsNil)
	v, err = Convert(dt, ft)
	c.Assert(v, Equals, int64(2015))
	v, err = Convert(mysql.ZeroDuration, ft)
	c.Assert(v, Equals, int64(time.Now().Year()))

	// For enum
	ft = NewFieldType(mysql.TypeEnum)
	ft.Elems = []string{"a", "b", "c"}
	v, err = Convert("a", ft)
	c.Assert(err, IsNil)
	c.Assert(v, DeepEquals, mysql.Enum{Name: "a", Value: 1})
	v, err = Convert(2, ft)
	c.Assert(err, IsNil)
	c.Assert(v, DeepEquals, mysql.Enum{Name: "b", Value: 2})
	_, err = Convert("d", ft)
	c.Assert(err, NotNil)
	_, err = Convert(4, ft)
	c.Assert(err, NotNil)

	ft = NewFieldType(mysql.TypeSet)
	ft.Elems = []string{"a", "b", "c"}
	v, err = Convert("a", ft)
	c.Assert(err, IsNil)
	c.Assert(v, DeepEquals, mysql.Set{Name: "a", Value: 1})
	v, err = Convert(2, ft)
	c.Assert(err, IsNil)
	c.Assert(v, DeepEquals, mysql.Set{Name: "b", Value: 2})
	v, err = Convert(3, ft)
	c.Assert(err, IsNil)
	c.Assert(v, DeepEquals, mysql.Set{Name: "a,b", Value: 3})
	_, err = Convert("d", ft)
	c.Assert(err, NotNil)
	_, err = Convert(9, ft)
	c.Assert(err, NotNil)
}
Пример #15
0
// 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
}
Пример #16
0
// Convert converts the val with type tp.
func Convert(val interface{}, target *FieldType) (v interface{}, err error) { //NTYPE
	tp := target.Tp
	if val == nil {
		return nil, nil
	}
	switch tp { // TODO: implement mysql types convert when "CAST() AS" syntax are supported.
	case mysql.TypeFloat:
		x, err := ToFloat64(val)
		if err != nil {
			return InvConv(val, tp)
		}
		if target.Flen != UnspecifiedLength {
			x, err = TruncateFloat(x, target.Flen, target.Decimal)
			if err != nil {
				return nil, errors.Trace(err)
			}
		}
		return float32(x), nil
	case mysql.TypeDouble:
		x, err := ToFloat64(val)
		if err != nil {
			return InvConv(val, tp)
		}
		if target.Flen != UnspecifiedLength {
			x, err = TruncateFloat(x, target.Flen, target.Decimal)
			if err != nil {
				return nil, errors.Trace(err)
			}
		}
		return float64(x), nil
	case mysql.TypeString:
		x, err := ToString(val)
		if err != nil {
			return InvConv(val, tp)
		}
		// TODO: consider target.Charset/Collate
		x = truncateStr(x, target.Flen)
		return x, nil
	case mysql.TypeBlob:
		x, err := ToString(val)
		if err != nil {
			return InvConv(val, tp)
		}
		x = truncateStr(x, target.Flen)
		return x, nil
	case mysql.TypeDuration:
		fsp := mysql.DefaultFsp
		if target.Decimal != UnspecifiedLength {
			fsp = target.Decimal
		}
		switch x := val.(type) {
		case mysql.Duration:
			return x.RoundFrac(fsp)
		case mysql.Time:
			t, err := x.ConvertToDuration()
			if err != nil {
				return nil, errors.Trace(err)
			}

			return t.RoundFrac(fsp)
		case string:
			return mysql.ParseDuration(x, fsp)
		default:
			return InvConv(val, tp)
		}
	case mysql.TypeTimestamp, mysql.TypeDatetime, mysql.TypeDate:
		fsp := mysql.DefaultFsp
		if target.Decimal != UnspecifiedLength {
			fsp = target.Decimal
		}
		switch x := val.(type) {
		case mysql.Time:
			t, err := x.Convert(tp)
			if err != nil {
				return nil, errors.Trace(err)
			}
			return t.RoundFrac(fsp)
		case mysql.Duration:
			t, err := x.ConvertToTime(tp)
			if err != nil {
				return nil, errors.Trace(err)
			}
			return t.RoundFrac(fsp)
		case string:
			return mysql.ParseTime(x, tp, fsp)
		default:
			return InvConv(val, tp)
		}
	case mysql.TypeLonglong:
		x, err := ToInt64(val)
		if err != nil {
			return InvConv(val, tp)
		}
		return x, nil
	case mysql.TypeNewDecimal:
		x, err := ToDecimal(val)
		if err != nil {
			return InvConv(val, tp)
		}
		if target.Decimal != UnspecifiedLength {
			x = x.Round(int32(target.Decimal))
		}
		// TODO: check Flen
		return x, nil
	default:
		panic("should never happen")
	}
}
Пример #17
0
func getTimeValue(ctx context.Context, v interface{}, tp byte, fsp int) (interface{}, error) {
	value := mysql.Time{
		Type: tp,
		Fsp:  fsp,
	}

	defaultTime, err := getSystemTimestamp(ctx)
	if err != nil {
		return nil, errors.Trace(err)
	}

	switch x := v.(type) {
	case string:
		if x == CurrentTimestamp {
			value.Time = defaultTime
		} else if x == ZeroTimestamp {
			value, _ = mysql.ParseTimeFromNum(0, tp, fsp)
		} else {
			value, err = mysql.ParseTime(x, tp, fsp)
			if err != nil {
				return nil, errors.Trace(err)
			}
		}
	case Value:
		switch xval := x.Val.(type) {
		case string:
			value, err = mysql.ParseTime(xval, tp, fsp)
			if err != nil {
				return nil, errors.Trace(err)
			}
		case int64:
			value, err = mysql.ParseTimeFromNum(int64(xval), tp, fsp)
			if err != nil {
				return nil, errors.Trace(err)
			}
		case nil:
			return nil, nil
		default:
			return nil, errors.Trace(errDefaultValue)
		}
	case *Ident:
		if x.Equal(CurrentTimeExpr) {
			return CurrentTimestamp, nil
		}

		return nil, errors.Trace(errDefaultValue)
	case *UnaryOperation:
		// support some expression, like `-1`
		m := map[interface{}]interface{}{}
		v := Eval(x, nil, m)
		ft := types.NewFieldType(mysql.TypeLonglong)
		xval, err := types.Convert(v, ft)
		if err != nil {
			return nil, errors.Trace(err)
		}

		value, err = mysql.ParseTimeFromNum(xval.(int64), tp, fsp)
		if err != nil {
			return nil, errors.Trace(err)
		}
	default:
		return nil, nil
	}

	return value, nil
}
Пример #18
0
// Convert converts the val with type tp.
func Convert(val interface{}, target *FieldType) (v interface{}, err error) {
	tp := target.Tp
	if val == nil {
		return nil, nil
	}
	switch tp { // TODO: implement mysql types convert when "CAST() AS" syntax are supported.
	case mysql.TypeFloat:
		x, err := ToFloat64(val)
		if err != nil {
			return invConv(val, tp)
		}
		// For float and following double type, we will only truncate it for float(M, D) format.
		// If no D is set, we will handle it like origin float whether M is set or not.
		if target.Flen != UnspecifiedLength && target.Decimal != UnspecifiedLength {
			x, err = TruncateFloat(x, target.Flen, target.Decimal)
			if err != nil {
				return nil, errors.Trace(err)
			}
		}
		return float32(x), nil
	case mysql.TypeDouble:
		x, err := ToFloat64(val)
		if err != nil {
			return invConv(val, tp)
		}
		if target.Flen != UnspecifiedLength && target.Decimal != UnspecifiedLength {
			x, err = TruncateFloat(x, target.Flen, target.Decimal)
			if err != nil {
				return nil, errors.Trace(err)
			}
		}
		return float64(x), nil
	case mysql.TypeBlob, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob,
		mysql.TypeString, mysql.TypeVarchar, mysql.TypeVarString:
		x, err := ToString(val)
		if err != nil {
			return invConv(val, tp)
		}
		// TODO: consider target.Charset/Collate
		x = truncateStr(x, target.Flen)
		if target.Charset == charset.CharsetBin {
			return []byte(x), nil
		}
		return x, nil
	case mysql.TypeDuration:
		fsp := mysql.DefaultFsp
		if target.Decimal != UnspecifiedLength {
			fsp = target.Decimal
		}
		switch x := val.(type) {
		case mysql.Duration:
			return x.RoundFrac(fsp)
		case mysql.Time:
			t, err := x.ConvertToDuration()
			if err != nil {
				return nil, errors.Trace(err)
			}

			return t.RoundFrac(fsp)
		case string:
			return mysql.ParseDuration(x, fsp)
		default:
			return invConv(val, tp)
		}
	case mysql.TypeTimestamp, mysql.TypeDatetime, mysql.TypeDate:
		fsp := mysql.DefaultFsp
		if target.Decimal != UnspecifiedLength {
			fsp = target.Decimal
		}
		switch x := val.(type) {
		case mysql.Time:
			t, err := x.Convert(tp)
			if err != nil {
				return nil, errors.Trace(err)
			}
			return t.RoundFrac(fsp)
		case mysql.Duration:
			t, err := x.ConvertToTime(tp)
			if err != nil {
				return nil, errors.Trace(err)
			}
			return t.RoundFrac(fsp)
		case string:
			return mysql.ParseTime(x, tp, fsp)
		case int64:
			return mysql.ParseTimeFromNum(x, tp, fsp)
		default:
			return invConv(val, tp)
		}
	case mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong:
		unsigned := mysql.HasUnsignedFlag(target.Flag)
		if unsigned {
			return convertToUint(val, target)
		}
		return convertToInt(val, target)
	case mysql.TypeBit:
		x, err := convertToUint(val, target)
		if err != nil {
			return x, errors.Trace(err)
		}

		// check bit boundary, if bit has n width, the boundary is
		// in [0, (1 << n) - 1]
		width := target.Flen
		if width == 0 || width == mysql.UnspecifiedBitWidth {
			width = mysql.MinBitWidth
		}

		maxValue := uint64(1)<<uint64(width) - 1

		if x > maxValue {
			return maxValue, overflow(val, tp)
		}
		return mysql.Bit{Value: x, Width: width}, nil
	case mysql.TypeDecimal, mysql.TypeNewDecimal:
		x, err := ToDecimal(val)
		if err != nil {
			return invConv(val, tp)
		}
		if target.Decimal != UnspecifiedLength {
			x = x.Round(int32(target.Decimal))
		}
		// TODO: check Flen
		return x, nil
	case mysql.TypeYear:
		var (
			intVal int64
			err    error
		)
		switch x := val.(type) {
		case string:
			intVal, err = StrToInt(x)
		case mysql.Time:
			return int64(x.Year()), nil
		case mysql.Duration:
			return int64(time.Now().Year()), nil
		default:
			intVal, err = ToInt64(x)
		}
		if err != nil {
			return invConv(val, tp)
		}
		y, err := mysql.AdjustYear(int(intVal))
		if err != nil {
			return invConv(val, tp)
		}
		return int64(y), nil
	case mysql.TypeEnum:
		var (
			e   mysql.Enum
			err error
		)
		switch x := val.(type) {
		case string:
			e, err = mysql.ParseEnumName(target.Elems, x)
		case []byte:
			e, err = mysql.ParseEnumName(target.Elems, string(x))
		default:
			var number uint64
			number, err = ToUint64(x)
			if err != nil {
				return nil, errors.Trace(err)
			}
			e, err = mysql.ParseEnumValue(target.Elems, number)
		}

		if err != nil {
			return invConv(val, tp)
		}
		return e, nil
	case mysql.TypeSet:
		var (
			s   mysql.Set
			err error
		)
		switch x := val.(type) {
		case string:
			s, err = mysql.ParseSetName(target.Elems, x)
		case []byte:
			s, err = mysql.ParseSetName(target.Elems, string(x))
		default:
			var number uint64
			number, err = ToUint64(x)
			if err != nil {
				return nil, errors.Trace(err)
			}
			s, err = mysql.ParseSetValue(target.Elems, number)
		}

		if err != nil {
			return invConv(val, tp)
		}
		return s, nil
	default:
		panic("should never happen")
	}
}