func toDecimal(l yyLexer, lval *yySymType, str string) int { dec := new(types.MyDecimal) err := dec.FromString(hack.Slice(str)) if err != nil { l.Errorf("decimal literal: %v", err) } lval.item = dec return decLit }
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 := types.NewDecFromInt(ctx.Count) to := new(types.MyDecimal) types.DecimalDiv(x, y, to, types.DivFracIncr) to.Round(to, ctx.Value.Frac()+types.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(types.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 (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 types.MyDecimal y.FromUint(uint64(ctx.Count)) types.DecimalDiv(x, &y, &to, types.DivFracIncr) to.Round(&to, ctx.Value.Frac()+types.DivFracIncr) v.SetMysqlDecimal(&to) } ctx.Value = *v.GetDatum() }
// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_from-unixtime func builtinFromUnixTime(args []types.Datum, ctx context.Context) (d types.Datum, err error) { sc := ctx.GetSessionVars().StmtCtx unixTimeStamp, err := args[0].ToDecimal(sc) if err != nil { return d, errors.Trace(err) } // 0 <= unixTimeStamp <= INT32_MAX if unixTimeStamp.IsNegative() { return } integralPart, err := unixTimeStamp.ToInt() if err == types.ErrTruncated { err = nil } if err != nil { return d, errors.Trace(err) } if integralPart > int64(math.MaxInt32) { return } // Split the integral part and fractional part of a decimal timestamp. // e.g. for timestamp 12345.678, // first get the integral part 12345, // then (12345.678 - 12345) * (10^9) to get the decimal part and convert it to nanosecond precision. integerDecimalTp := new(types.MyDecimal).FromInt(integralPart) fracDecimalTp := new(types.MyDecimal) err = types.DecimalSub(unixTimeStamp, integerDecimalTp, fracDecimalTp) if err != nil { return d, errors.Trace(err) } nano := new(types.MyDecimal).FromInt(int64(time.Second)) x := new(types.MyDecimal) err = types.DecimalMul(fracDecimalTp, nano, x) if err != nil { return d, errors.Trace(err) } fractionalPart, err := x.ToInt() // here fractionalPart is result multiplying the original fractional part by 10^9. if err == types.ErrTruncated { err = nil } if err != nil { return d, errors.Trace(err) } _, fracDigitsNumber := unixTimeStamp.PrecisionAndFrac() fsp := fracDigitsNumber if fracDigitsNumber > types.MaxFsp { fsp = types.MaxFsp } tr, err := types.RoundFrac(time.Unix(integralPart, fractionalPart), fsp) if err != nil { return d, errors.Trace(err) } t := types.Time{ Time: types.FromGoTime(tr), Type: mysql.TypeDatetime, Fsp: fsp, } if args[0].Kind() == types.KindString { // Keep consistent with MySQL. t.Fsp = types.MaxFsp } d.SetMysqlTime(t) if len(args) == 1 { return } return builtinDateFormat([]types.Datum{d, args[1]}, ctx) }
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(types.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, 1) 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}, } sc := new(variable.StatementContext) for _, t := range tblCmp { d1 := types.NewDatum(t.Arg1) dec1, err := d1.ToDecimal(sc) c.Assert(err, IsNil) d1.SetMysqlDecimal(dec1) d2 := types.NewDatum(t.Arg2) dec2, err := d2.ToDecimal(sc) 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 := types.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) } }