Пример #1
0
// 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())
	}
}
Пример #2
0
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
}
Пример #3
0
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)
}
Пример #4
0
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)
}
Пример #5
0
// 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
}
Пример #6
0
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()
}
Пример #7
0
// 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
}
Пример #8
0
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
}