예제 #1
0
파일: decimal.go 프로젝트: lovedboy/tidb
// DecodeDecimal decodes bytes to decimal.
// DecodeFloat decodes a float from a byte slice
// Decimal decoding:
// Byte -> value sign
// Byte -> exp 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 sign.
	expSign := int64(r[0])
	r = r[1:]

	// Decode exp value.
	expVal := int64(0)
	r, expVal, err = DecodeInt(r)
	if err != nil {
		return r, d, errors.Trace(err)
	}
	expVal = decodeExp(expVal, expSign, valSign)

	// Decode abs value bytes.
	value := []byte{}
	r, value, err = DecodeBytes(r)
	if err != nil {
		return r, d, errors.Trace(err)
	}
	codecValue(value, valSign)

	// Generate decimal string value.
	var decimalStr []byte
	if valSign == negativeSign {
		decimalStr = append(decimalStr, '-')
	}

	if expVal <= 0 {
		// Like decimal "0.1234" or "0.01234".
		decimalStr = append(decimalStr, '0')
		decimalStr = append(decimalStr, '.')
		decimalStr = append(decimalStr, bytes.Repeat([]byte{'0'}, -int(expVal))...)
		decimalStr = append(decimalStr, value...)
	} else {
		// Like decimal "12.34".
		decimalStr = append(decimalStr, value[:expVal]...)
		decimalStr = append(decimalStr, '.')
		decimalStr = append(decimalStr, value[expVal:]...)
	}

	d, err = mysql.ParseDecimal(string(decimalStr))
	return r, d, errors.Trace(err)
}
예제 #2
0
파일: decimal.go 프로젝트: XuHuaiyu/tidb
// 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
}
예제 #3
0
파일: decimal.go 프로젝트: duzhanyuan/tidb
// 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
}
예제 #4
0
파일: datum.go 프로젝트: XuHuaiyu/tidb
func (d *Datum) compareString(s string) (int, error) {
	switch d.k {
	case KindNull, KindMinNotNull:
		return -1, nil
	case KindMaxValue:
		return 1, nil
	case KindString, KindBytes:
		return CompareString(d.GetString(), s), nil
	case KindMysqlDecimal:
		dec, err := mysql.ParseDecimal(s)
		return d.GetMysqlDecimal().Cmp(dec), err
	case KindMysqlTime:
		dt, err := mysql.ParseDatetime(s)
		return d.GetMysqlTime().Compare(dt), err
	case KindMysqlDuration:
		dur, err := mysql.ParseDuration(s, mysql.MaxFsp)
		return d.GetMysqlDuration().Compare(dur), err
	case KindMysqlBit:
		return CompareString(d.GetMysqlBit().ToString(), s), nil
	case KindMysqlHex:
		return CompareString(d.GetMysqlHex().ToString(), s), nil
	case KindMysqlSet:
		return CompareString(d.GetMysqlSet().String(), s), nil
	case KindMysqlEnum:
		return CompareString(d.GetMysqlEnum().String(), s), nil
	default:
		fVal, err := StrToFloat(s)
		if err != nil {
			return 0, err
		}
		return d.compareFloat64(fVal)
	}
}
예제 #5
0
파일: datum.go 프로젝트: XuHuaiyu/tidb
// 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())
	}
}
예제 #6
0
파일: tables.go 프로젝트: lovedboy/tidb
func (t *Table) unflatten(rec interface{}, col *column.Col) (interface{}, error) {
	if rec == nil {
		return nil, nil
	}
	switch col.Tp {
	case mysql.TypeFloat:
		return float32(rec.(float64)), nil
	case mysql.TypeTiny, mysql.TypeShort, mysql.TypeYear, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong,
		mysql.TypeDouble, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeBlob, mysql.TypeLongBlob,
		mysql.TypeVarchar, mysql.TypeString:
		return rec, nil
	case mysql.TypeDate, mysql.TypeDatetime, mysql.TypeTimestamp:
		var t mysql.Time
		t.Type = col.Tp
		t.Fsp = col.Decimal
		err := t.Unmarshal(rec.([]byte))
		if err != nil {
			return nil, errors.Trace(err)
		}
		return t, nil
	case mysql.TypeDuration:
		return mysql.Duration{Duration: time.Duration(rec.(int64)), Fsp: col.Decimal}, nil
	case mysql.TypeNewDecimal, mysql.TypeDecimal:
		return mysql.ParseDecimal(string(rec.([]byte)))
	case mysql.TypeEnum:
		return mysql.ParseEnumValue(col.Elems, rec.(uint64))
	case mysql.TypeSet:
		return mysql.ParseSetValue(col.Elems, rec.(uint64))
	case mysql.TypeBit:
		return mysql.Bit{Value: rec.(uint64), Width: col.Flen}, nil
	}
	log.Error(col.Tp, rec, reflect.TypeOf(rec))
	return nil, nil
}
예제 #7
0
파일: tables.go 프로젝트: anywhy/tidb
func unflatten(datum types.Datum, tp *types.FieldType) (types.Datum, error) {
	if datum.IsNull() {
		return datum, nil
	}
	switch tp.Tp {
	case mysql.TypeFloat:
		datum.SetFloat32(float32(datum.GetFloat64()))
		return datum, nil
	case mysql.TypeTiny, mysql.TypeShort, mysql.TypeYear, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong,
		mysql.TypeDouble, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeBlob, mysql.TypeLongBlob,
		mysql.TypeVarchar, mysql.TypeString:
		return datum, nil
	case mysql.TypeDate, mysql.TypeDatetime, mysql.TypeTimestamp:
		var t mysql.Time
		t.Type = tp.Tp
		t.Fsp = tp.Decimal
		err := t.Unmarshal(datum.GetBytes())
		if err != nil {
			return datum, errors.Trace(err)
		}
		datum.SetValue(t)
		return datum, nil
	case mysql.TypeDuration:
		dur := mysql.Duration{Duration: time.Duration(datum.GetInt64())}
		datum.SetValue(dur)
		return datum, nil
	case mysql.TypeNewDecimal, mysql.TypeDecimal:
		dec, err := mysql.ParseDecimal(datum.GetString())
		if err != nil {
			return datum, errors.Trace(err)
		}
		if tp.Decimal >= 0 {
			dec = dec.Truncate(int32(tp.Decimal))
		}
		datum.SetValue(dec)
		return datum, nil
	case mysql.TypeEnum:
		enum, err := mysql.ParseEnumValue(tp.Elems, datum.GetUint64())
		if err != nil {
			return datum, errors.Trace(err)
		}
		datum.SetValue(enum)
		return datum, nil
	case mysql.TypeSet:
		set, err := mysql.ParseSetValue(tp.Elems, datum.GetUint64())
		if err != nil {
			return datum, errors.Trace(err)
		}
		datum.SetValue(set)
		return datum, nil
	case mysql.TypeBit:
		bit := mysql.Bit{Value: datum.GetUint64(), Width: tp.Flen}
		datum.SetValue(bit)
		return datum, nil
	}
	log.Error(tp.Tp, datum)
	return datum, nil
}
예제 #8
0
파일: datum.go 프로젝트: XuHuaiyu/tidb
func (d *Datum) compareMysqlDecimal(dec mysql.Decimal) (int, error) {
	switch d.k {
	case KindMysqlDecimal:
		return d.GetMysqlDecimal().Cmp(dec), nil
	case KindString, KindBytes:
		dDec, err := mysql.ParseDecimal(d.GetString())
		return dDec.Cmp(dec), err
	default:
		fVal, _ := dec.Float64()
		return d.compareFloat64(fVal)
	}
}
예제 #9
0
파일: datum.go 프로젝트: XuHuaiyu/tidb
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
}
예제 #10
0
파일: codec_test.go 프로젝트: yzl11/vessel
func (s *testCodecSuite) TestDecimal(c *C) {
	tbl := []string{
		"1234.00",
		"1234",
		"12.34",
		"12.340",
		"0.1234",
		"0.0",
		"0",
		"-0.0",
		"-0.0000",
		"-1234.00",
		"-1234",
		"-12.34",
		"-12.340",
		"-0.1234"}

	for _, t := range tbl {
		m, err := mysql.ParseDecimal(t)
		c.Assert(err, IsNil)
		b, err := EncodeKey(m)
		c.Assert(err, IsNil)
		v, err := DecodeKey(b)
		c.Assert(err, IsNil)
		c.Assert(v, HasLen, 1)
		vv, ok := v[0].(mysql.Decimal)
		c.Assert(ok, IsTrue)
		c.Assert(vv.Equals(m), IsTrue)
	}

	tblCmp := []struct {
		Arg1 interface{}
		Arg2 interface{}
		Ret  int
	}{
		// Test for float type decimal.
		{"1234", "123400", -1},
		{"12340", "123400", -1},
		{"1234", "1234.5", -1},
		{"1234", "1234.0000", 0},
		{"1234", "12.34", 1},
		{"12.34", "12.35", -1},
		{"0.1234", "12.3400", -1},
		{"0.1234", "0.1235", -1},
		{"0.123400", "12.34", -1},
		{"12.34000", "12.34", 0},
		{"0.01234", "0.01235", -1},
		{"0.1234", "0", 1},
		{"0.0000", "0", 0},
		{"0.0001", "0", 1},
		{"0.0001", "0.0000", 1},
		{"0", "-0.0000", 0},
		{"-0.0001", "0", -1},
		{"-0.1234", "0", -1},
		{"-0.1234", "0.1234", -1},
		{"-1.234", "-12.34", 1},
		{"-0.1234", "-12.34", 1},
		{"-12.34", "1234", -1},
		{"-12.34", "-12.35", 1},
		{"-0.01234", "-0.01235", 1},
		{"-1234", "-123400", 1},
		{"-12340", "-123400", 1},

		// Test for int type decimal.
		{int64(-1), int64(1), -1},
		{int64(math.MaxInt64), int64(math.MinInt64), 1},
		{int64(math.MaxInt64), int64(math.MaxInt32), 1},
		{int64(math.MinInt32), int64(math.MaxInt16), -1},
		{int64(math.MinInt64), int64(math.MaxInt8), -1},
		{int64(0), int64(math.MaxInt8), -1},
		{int64(math.MinInt8), int64(0), -1},
		{int64(math.MinInt16), int64(math.MaxInt16), -1},
		{int64(1), int64(-1), 1},
		{int64(1), int64(0), 1},
		{int64(-1), int64(0), -1},
		{int64(0), int64(0), 0},
		{int64(math.MaxInt16), int64(math.MaxInt16), 0},

		// Test for uint type decimal.
		{uint64(0), uint64(0), 0},
		{uint64(1), uint64(0), 1},
		{uint64(0), uint64(1), -1},
		{uint64(math.MaxInt8), uint64(math.MaxInt16), -1},
		{uint64(math.MaxUint32), uint64(math.MaxInt32), 1},
		{uint64(math.MaxUint8), uint64(math.MaxInt8), 1},
		{uint64(math.MaxUint16), uint64(math.MaxInt32), -1},
		{uint64(math.MaxUint64), uint64(math.MaxInt64), 1},
		{uint64(math.MaxInt64), uint64(math.MaxUint32), 1},
		{uint64(math.MaxUint64), uint64(0), 1},
		{uint64(0), uint64(math.MaxUint64), -1},
	}

	for _, t := range tblCmp {
		m1, err := mysql.ConvertToDecimal(t.Arg1)
		c.Assert(err, IsNil)
		m2, err := mysql.ConvertToDecimal(t.Arg2)
		c.Assert(err, IsNil)

		b1, err := EncodeKey(m1)
		c.Assert(err, IsNil)
		b2, err := EncodeKey(m2)
		c.Assert(err, IsNil)

		ret := bytes.Compare(b1, b2)
		c.Assert(ret, Equals, t.Ret)
	}
}
예제 #11
0
파일: codec_test.go 프로젝트: anywhy/tidb
func (s *testCodecSuite) TestDecimal(c *C) {
	defer testleak.AfterTest(c)()
	tbl := []string{
		"1234.00",
		"1234",
		"12.34",
		"12.340",
		"0.1234",
		"0.0",
		"0",
		"-0.0",
		"-0.0000",
		"-1234.00",
		"-1234",
		"-12.34",
		"-12.340",
		"-0.1234"}

	for _, t := range tbl {
		m, err := mysql.ParseDecimal(t)
		c.Assert(err, IsNil)
		b, err := EncodeKey(nil, types.NewDatum(m))
		c.Assert(err, IsNil)
		v, err := Decode(b)
		c.Assert(err, IsNil)
		c.Assert(v, HasLen, 1)
		vv := v[0].GetMysqlDecimal()
		c.Assert(vv.Equals(m), IsTrue)
	}

	tblCmp := []struct {
		Arg1 interface{}
		Arg2 interface{}
		Ret  int
	}{
		// Test for float type decimal.
		{"1234", "123400", -1},
		{"12340", "123400", -1},
		{"1234", "1234.5", -1},
		{"1234", "1234.0000", 0},
		{"1234", "12.34", 1},
		{"12.34", "12.35", -1},
		{"0.12", "0.1234", -1},
		{"0.1234", "12.3400", -1},
		{"0.1234", "0.1235", -1},
		{"0.123400", "12.34", -1},
		{"12.34000", "12.34", 0},
		{"0.01234", "0.01235", -1},
		{"0.1234", "0", 1},
		{"0.0000", "0", 0},
		{"0.0001", "0", 1},
		{"0.0001", "0.0000", 1},
		{"0", "-0.0000", 0},
		{"-0.0001", "0", -1},
		{"-0.1234", "0", -1},
		{"-0.1234", "-0.12", -1},
		{"-0.12", "-0.1234", 1},
		{"-0.12", "-0.1200", 0},
		{"-0.1234", "0.1234", -1},
		{"-1.234", "-12.34", 1},
		{"-0.1234", "-12.34", 1},
		{"-12.34", "1234", -1},
		{"-12.34", "-12.35", 1},
		{"-0.01234", "-0.01235", 1},
		{"-1234", "-123400", 1},
		{"-12340", "-123400", 1},

		// Test for int type decimal.
		{int64(-1), int64(1), -1},
		{int64(math.MaxInt64), int64(math.MinInt64), 1},
		{int64(math.MaxInt64), int64(math.MaxInt32), 1},
		{int64(math.MinInt32), int64(math.MaxInt16), -1},
		{int64(math.MinInt64), int64(math.MaxInt8), -1},
		{int64(0), int64(math.MaxInt8), -1},
		{int64(math.MinInt8), int64(0), -1},
		{int64(math.MinInt16), int64(math.MaxInt16), -1},
		{int64(1), int64(-1), 1},
		{int64(1), int64(0), 1},
		{int64(-1), int64(0), -1},
		{int64(0), int64(0), 0},
		{int64(math.MaxInt16), int64(math.MaxInt16), 0},

		// Test for uint type decimal.
		{uint64(0), uint64(0), 0},
		{uint64(1), uint64(0), 1},
		{uint64(0), uint64(1), -1},
		{uint64(math.MaxInt8), uint64(math.MaxInt16), -1},
		{uint64(math.MaxUint32), uint64(math.MaxInt32), 1},
		{uint64(math.MaxUint8), uint64(math.MaxInt8), 1},
		{uint64(math.MaxUint16), uint64(math.MaxInt32), -1},
		{uint64(math.MaxUint64), uint64(math.MaxInt64), 1},
		{uint64(math.MaxInt64), uint64(math.MaxUint32), 1},
		{uint64(math.MaxUint64), uint64(0), 1},
		{uint64(0), uint64(math.MaxUint64), -1},
	}

	for _, t := range tblCmp {
		m1, err := mysql.ConvertToDecimal(t.Arg1)
		c.Assert(err, IsNil)
		m2, err := mysql.ConvertToDecimal(t.Arg2)
		c.Assert(err, IsNil)

		b1, err := EncodeKey(nil, types.NewDatum(m1))
		c.Assert(err, IsNil)
		b2, err := EncodeKey(nil, types.NewDatum(m2))
		c.Assert(err, IsNil)

		ret := bytes.Compare(b1, b2)
		c.Assert(ret, Equals, t.Ret)
	}

	floats := []float64{-123.45, -123.40, -23.45, -1.43, -0.93, -0.4333, -0.068,
		-0.0099, 0, 0.001, 0.0012, 0.12, 1.2, 1.23, 123.3, 2424.242424}
	var decs [][]byte
	for i := range floats {
		dec := mysql.NewDecimalFromFloat(floats[i])
		decs = append(decs, EncodeDecimal(nil, dec))
	}
	for i := 0; i < len(decs)-1; i++ {
		cmp := bytes.Compare(decs[i], decs[i+1])
		c.Assert(cmp, LessEqual, 0)
	}
}
예제 #12
0
파일: tablecodec.go 프로젝트: XuHuaiyu/tidb
// Unflatten converts a raw datum to a column datum.
func Unflatten(datum types.Datum, ft *types.FieldType, inIndex bool) (types.Datum, error) {
	if datum.IsNull() {
		return datum, nil
	}
	switch ft.Tp {
	case mysql.TypeFloat:
		datum.SetFloat32(float32(datum.GetFloat64()))
		return datum, nil
	case mysql.TypeTiny, mysql.TypeShort, mysql.TypeYear, mysql.TypeInt24,
		mysql.TypeLong, mysql.TypeLonglong, mysql.TypeDouble, mysql.TypeTinyBlob,
		mysql.TypeMediumBlob, mysql.TypeBlob, mysql.TypeLongBlob, mysql.TypeVarchar,
		mysql.TypeString:
		return datum, nil
	case mysql.TypeDate, mysql.TypeDatetime, mysql.TypeTimestamp:
		var t mysql.Time
		t.Type = ft.Tp
		t.Fsp = ft.Decimal
		var err error
		err = t.FromPackedUint(datum.GetUint64())
		if err != nil {
			return datum, errors.Trace(err)
		}
		datum.SetMysqlTime(t)
		return datum, nil
	case mysql.TypeDuration:
		dur := mysql.Duration{Duration: time.Duration(datum.GetInt64())}
		datum.SetValue(dur)
		return datum, nil
	case mysql.TypeNewDecimal:
		if datum.Kind() == types.KindMysqlDecimal {
			if ft.Decimal >= 0 {
				dec := datum.GetMysqlDecimal().Truncate(int32(ft.Decimal))
				datum.SetMysqlDecimal(dec)
			}
			return datum, nil
		}
		dec, err := mysql.ParseDecimal(datum.GetString())
		if err != nil {
			return datum, errors.Trace(err)
		}
		if ft.Decimal >= 0 {
			dec = dec.Truncate(int32(ft.Decimal))
		}
		datum.SetValue(dec)
		return datum, nil
	case mysql.TypeEnum:
		enum, err := mysql.ParseEnumValue(ft.Elems, datum.GetUint64())
		if err != nil {
			return datum, errors.Trace(err)
		}
		datum.SetValue(enum)
		return datum, nil
	case mysql.TypeSet:
		set, err := mysql.ParseSetValue(ft.Elems, datum.GetUint64())
		if err != nil {
			return datum, errors.Trace(err)
		}
		datum.SetValue(set)
		return datum, nil
	case mysql.TypeBit:
		bit := mysql.Bit{Value: datum.GetUint64(), Width: ft.Flen}
		datum.SetValue(bit)
		return datum, nil
	}
	return datum, nil
}