// 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()) } }
func builtinAvg(args []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { // avg use decimal for integer and decimal type, use float for others // see https://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html type avg struct { sum interface{} n uint64 decimalResult bool } if _, ok := ctx[ExprEvalArgAggEmpty]; ok { return } fn := ctx[ExprEvalFn] distinct := getDistinct(ctx, fn) if _, ok := ctx[ExprAggDone]; ok { distinct.clear() data, ok := ctx[fn].(avg) if !ok { return } switch x := data.sum.(type) { case nil: return nil, nil case float64: return float64(x) / float64(data.n), nil case mysql.Decimal: return x.Div(mysql.NewDecimalFromUint(data.n, 0)), nil } panic("should not happend") } data, _ := ctx[fn].(avg) y := args[0] if types.IsNil(y) { return } ok, err := distinct.isDistinct(args...) if err != nil || !ok { // if err or not distinct, return return nil, err } if types.IsNil(data.sum) { data.n = 0 } data.sum, err = calculateSum(data.sum, y) if err != nil { return nil, errors.Errorf("eval AVG aggregate err: %v", err) } data.n++ ctx[fn] = data return }
func (e *Evaluator) evalAggAvg(v *ast.AggregateFuncExpr) { ctx := v.GetContext() switch x := ctx.Value.(type) { case float64: ctx.Value = x / float64(ctx.Count) case mysql.Decimal: ctx.Value = x.Div(mysql.NewDecimalFromUint(uint64(ctx.Count), 0)) } v.SetValue(ctx.Value) }
func (s *testTypeEtcSuite) TestCoerce(c *check.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) }
// 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() t := x.Div(mysql.NewDecimalFromUint(uint64(ctx.Count), 0)) d.SetMysqlDecimal(t) } return }
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() t := x.Div(mysql.NewDecimalFromUint(uint64(ctx.Count), 0)) v.SetMysqlDecimal(t) } ctx.Value = *v.GetDatum() }
// GetGroupResult implements AggregationFunction interface. func (af *avgFunction) GetGroupResult(groupKey []byte) (d types.Datum) { ctx := af.getContext(groupKey) switch x := ctx.Value.(type) { case float64: t := x / float64(ctx.Count) ctx.Value = t d.SetFloat64(t) case mysql.Decimal: t := x.Div(mysql.NewDecimalFromUint(uint64(ctx.Count), 0)) ctx.Value = t d.SetMysqlDecimal(t) } return }
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 }