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 := new(mysql.MyDecimal) err := dec.FromString([]byte(s)) return d.GetMysqlDecimal().Compare(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) } }
func (af *avgFunction) calculateResult(ctx *ast.AggEvaluateContext) (d types.Datum) { switch ctx.Value.Kind() { case types.KindFloat64: t := ctx.Value.GetFloat64() / float64(ctx.Count) d.SetValue(t) case types.KindMysqlDecimal: x := ctx.Value.GetMysqlDecimal() y := mysql.NewDecFromInt(ctx.Count) to := new(mysql.MyDecimal) mysql.DecimalDiv(x, y, to, mysql.DivFracIncr) to.Round(to, ctx.Value.Frac()+mysql.DivFracIncr) d.SetMysqlDecimal(to) } return }
// GetGroupResult implements AggregationFunction interface. func (af *avgFunction) GetGroupResult(groupKey []byte) (d types.Datum) { ctx := af.getContext(groupKey) switch ctx.Value.Kind() { case types.KindFloat64: t := ctx.Value.GetFloat64() / float64(ctx.Count) d.SetValue(t) case types.KindMysqlDecimal: x := ctx.Value.GetMysqlDecimal() y := mysql.NewDecFromInt(ctx.Count) to := new(mysql.MyDecimal) mysql.DecimalDiv(x, y, to, mysql.DivFracIncr) to.Round(to, ctx.Value.Frac()+mysql.DivFracIncr) d.SetMysqlDecimal(to) } return }
// DecodeDecimal decodes bytes to decimal. func DecodeDecimal(b []byte) ([]byte, types.Datum, error) { var d types.Datum if len(b) < 3 { return b, d, errors.New("insufficient bytes to decode value") } precision := int(b[0]) frac := int(b[1]) b = b[2:] dec := new(mysql.MyDecimal) binSize, err := dec.FromBin(b, precision, frac) b = b[binSize:] if err != nil { return b, d, errors.Trace(err) } d.SetLength(precision) d.SetFrac(frac) d.SetMysqlDecimal(dec) return b, d, nil }
func (d *Datum) compareMysqlDecimal(dec *mysql.MyDecimal) (int, error) { switch d.k { case KindMysqlDecimal: return d.GetMysqlDecimal().Compare(dec), nil case KindString, KindBytes: dDec := new(mysql.MyDecimal) err := dDec.FromString(d.GetBytes()) return dDec.Compare(dec), err default: fVal, _ := dec.ToFloat64() return d.compareFloat64(fVal) } }
// decimal2RoundUint converts a MyDecimal to an uint64 after rounding. func decimal2RoundUint(x *mysql.MyDecimal) (uint64, error) { roundX := new(mysql.MyDecimal) x.Round(roundX, 0) var ( uintX uint64 err error ) if roundX.IsNegative() { intX, err := roundX.ToInt() if err != nil && err != mysql.ErrTruncated { return 0, errors.Trace(err) } uintX = uint64(intX) } else { uintX, err = roundX.ToUint() if err != nil && err != mysql.ErrTruncated { return 0, errors.Trace(err) } } return uintX, nil }
func (e *Evaluator) evalAggAvg(v *ast.AggregateFuncExpr) { ctx := v.GetContext() switch ctx.Value.Kind() { case types.KindFloat64: t := ctx.Value.GetFloat64() / float64(ctx.Count) v.SetValue(t) case types.KindMysqlDecimal: x := ctx.Value.GetMysqlDecimal() var y, to mysql.MyDecimal y.FromUint(uint64(ctx.Count)) mysql.DecimalDiv(x, &y, &to, mysql.DivFracIncr) to.Round(&to, ctx.Value.Frac()+mysql.DivFracIncr) v.SetMysqlDecimal(&to) } ctx.Value = *v.GetDatum() }
// ToInt64 converts to a int64. func (d *Datum) ToInt64() (int64, error) { tp := mysql.TypeLonglong lowerBound := signedLowerBound[tp] upperBound := signedUpperBound[tp] switch d.Kind() { case KindInt64: return convertIntToInt(d.GetInt64(), lowerBound, upperBound, tp) case KindUint64: return convertUintToInt(d.GetUint64(), upperBound, tp) case KindFloat32: return convertFloatToInt(float64(d.GetFloat32()), lowerBound, upperBound, tp) case KindFloat64: return convertFloatToInt(d.GetFloat64(), lowerBound, upperBound, tp) case KindString: s := d.GetString() fval, err := StrToFloat(s) if err != nil { return 0, errors.Trace(err) } return convertFloatToInt(fval, lowerBound, upperBound, tp) case KindBytes: s := string(d.GetBytes()) fval, err := StrToFloat(s) if err != nil { return 0, errors.Trace(err) } return convertFloatToInt(fval, lowerBound, upperBound, tp) case KindMysqlTime: // 2011-11-10 11:11:11.999999 -> 20111110111112 dec := d.GetMysqlTime().ToNumber() dec.Round(dec, 0) ival, err := dec.ToInt() ival, err2 := convertIntToInt(ival, lowerBound, upperBound, tp) if err == nil { err = err2 } return ival, err case KindMysqlDuration: // 11:11:11.999999 -> 111112 dec := d.GetMysqlDuration().ToNumber() dec.Round(dec, 0) ival, err := dec.ToInt() ival, err2 := convertIntToInt(ival, lowerBound, upperBound, tp) if err == nil { err = err2 } return ival, err case KindMysqlDecimal: var to mysql.MyDecimal d.GetMysqlDecimal().Round(&to, 0) ival, err := to.ToInt() ival, err2 := convertIntToInt(ival, lowerBound, upperBound, tp) if err == nil { err = err2 } return ival, err case KindMysqlHex: fval := d.GetMysqlHex().ToNumber() return convertFloatToInt(fval, lowerBound, upperBound, tp) case KindMysqlBit: fval := d.GetMysqlBit().ToNumber() return convertFloatToInt(fval, lowerBound, upperBound, tp) case KindMysqlEnum: fval := d.GetMysqlEnum().ToNumber() return convertFloatToInt(fval, lowerBound, upperBound, tp) case KindMysqlSet: fval := d.GetMysqlSet().ToNumber() return convertFloatToInt(fval, lowerBound, upperBound, tp) default: return 0, errors.Errorf("cannot convert %v(type %T) to int64", d.GetValue(), d.GetValue()) } }
// ConvertDatumToDecimal converts datum to decimal. func ConvertDatumToDecimal(d Datum) (*mysql.MyDecimal, error) { dec := new(mysql.MyDecimal) var err error switch d.Kind() { case KindInt64: dec.FromInt(d.GetInt64()) case KindUint64: dec.FromUint(d.GetUint64()) case KindFloat32: err = dec.FromFloat64(float64(d.GetFloat32())) case KindFloat64: err = dec.FromFloat64(d.GetFloat64()) case KindString: err = dec.FromString(d.GetBytes()) case KindMysqlDecimal: *dec = *d.GetMysqlDecimal() case KindMysqlHex: dec.FromInt(d.GetMysqlHex().Value) case KindMysqlBit: dec.FromUint(d.GetMysqlBit().Value) case KindMysqlEnum: dec.FromUint(d.GetMysqlEnum().Value) case KindMysqlSet: dec.FromUint(d.GetMysqlSet().Value) default: err = fmt.Errorf("can't convert %v to decimal", d.GetValue()) } return dec, err }
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 { dec := new(mysql.MyDecimal) err := dec.FromString([]byte(t)) c.Assert(err, IsNil) b, err := EncodeKey(nil, types.NewDatum(dec)) c.Assert(err, IsNil) v, err := Decode(b) c.Assert(err, IsNil) c.Assert(v, HasLen, 1) vv := v[0].GetMysqlDecimal() c.Assert(vv.Compare(dec), Equals, 0) } 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 { d1 := types.NewDatum(t.Arg1) dec1, err := d1.ToDecimal() c.Assert(err, IsNil) d1.SetMysqlDecimal(dec1) d2 := types.NewDatum(t.Arg2) dec2, err := d2.ToDecimal() c.Assert(err, IsNil) d2.SetMysqlDecimal(dec2) d1.SetLength(30) d1.SetFrac(6) d2.SetLength(30) d2.SetFrac(6) b1, err := EncodeKey(nil, d1) c.Assert(err, IsNil) b2, err := EncodeKey(nil, d2) c.Assert(err, IsNil) ret := bytes.Compare(b1, b2) c.Assert(ret, Equals, t.Ret, Commentf("%v %x %x", t, b1, b2)) } 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.NewDecFromFloatForTest(floats[i]) var d types.Datum d.SetLength(20) d.SetFrac(6) d.SetMysqlDecimal(dec) decs = append(decs, EncodeDecimal(nil, d)) } for i := 0; i < len(decs)-1; i++ { cmp := bytes.Compare(decs[i], decs[i+1]) c.Assert(cmp, LessEqual, 0) } }
// ComputeIntDiv computes the result of a / b, both a and b are integer. func ComputeIntDiv(a, b Datum) (d Datum, err error) { switch a.Kind() { case KindInt64: x := a.GetInt64() switch b.Kind() { case KindInt64: y := b.GetInt64() if y == 0 { return d, nil } r, err1 := DivInt64(x, y) d.SetInt64(r) return d, errors.Trace(err1) case KindUint64: y := b.GetUint64() if y == 0 { return d, nil } r, err1 := DivIntWithUint(x, y) d.SetUint64(r) return d, errors.Trace(err1) } case KindUint64: x := a.GetUint64() switch b.Kind() { case KindInt64: y := b.GetInt64() if y == 0 { return d, nil } r, err1 := DivUintWithInt(x, y) d.SetUint64(r) return d, errors.Trace(err1) case KindUint64: y := b.GetUint64() if y == 0 { return d, nil } d.SetUint64(x / y) return d, nil } } // If either is not integer, use decimal to calculate x, err := a.ToDecimal() if err != nil { return d, errors.Trace(err) } y, err := b.ToDecimal() if err != nil { return d, errors.Trace(err) } to := new(mysql.MyDecimal) err = mysql.DecimalDiv(x, y, to, mysql.DivFracIncr) if err == mysql.ErrDivByZero { return d, nil } iVal, err1 := to.ToInt() if err == nil { err = err1 } d.SetInt64(iVal) return d, nil }