Esempio n. 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())
	}
}
Esempio n. 2
0
func (s *testDecimalSuite) TestDecimalCodec(c *C) {
	inputs := []struct {
		Input float64
	}{
		{float64(123400)},
		{float64(1234)},
		{float64(12.34)},
		{float64(0.1234)},
		{float64(0.01234)},
		{float64(-0.1234)},
		{float64(-0.01234)},
		{float64(12.3400)},
		{float64(-12.34)},
		{float64(0.00000)},
		{float64(0)},
		{float64(-0.0)},
		{float64(-0.000)},
	}

	for _, input := range inputs {
		v := mysql.NewDecimalFromFloat(input.Input)
		b := EncodeDecimal([]byte{}, v)
		_, d, err := DecodeDecimal(b)
		c.Assert(err, IsNil)
		c.Assert(v.Equals(d), IsTrue)
	}
}
Esempio n. 3
0
func (s *testDecimalSuite) TestFrac(c *C) {
	defer testleak.AfterTest(c)()
	inputs := []struct {
		Input mysql.Decimal
	}{
		{mysql.NewDecimalFromInt(int64(3), 0)},
		{mysql.NewDecimalFromFloat(float64(0.03))},
	}
	for _, v := range inputs {
		testFrac(c, v.Input)
	}
}
Esempio n. 4
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
}
Esempio n. 5
0
func (e *Evaluator) unaryOperation(u *ast.UnaryOperationExpr) bool {
	defer func() {
		if er := recover(); er != nil {
			e.err = errors.Errorf("%v", er)
		}
	}()
	a := u.V.GetValue()
	a = types.RawData(a)
	if a == nil {
		u.SetValue(nil)
		return true
	}
	switch op := u.Op; op {
	case opcode.Not:
		n, err := types.ToBool(a)
		if err != nil {
			e.err = errors.Trace(err)
		} else if n == 0 {
			u.SetValue(int64(1))
		} else {
			u.SetValue(int64(0))
		}
	case opcode.BitNeg:
		// for bit operation, we will use int64 first, then return uint64
		n, err := types.ToInt64(a)
		if err != nil {
			e.err = errors.Trace(err)
			return false
		}
		u.SetValue(uint64(^n))
	case opcode.Plus:
		switch x := a.(type) {
		case bool:
			u.SetValue(boolToInt64(x))
		case float32:
			u.SetValue(+x)
		case float64:
			u.SetValue(+x)
		case int:
			u.SetValue(+x)
		case int8:
			u.SetValue(+x)
		case int16:
			u.SetValue(+x)
		case int32:
			u.SetValue(+x)
		case int64:
			u.SetValue(+x)
		case uint:
			u.SetValue(+x)
		case uint8:
			u.SetValue(+x)
		case uint16:
			u.SetValue(+x)
		case uint32:
			u.SetValue(+x)
		case uint64:
			u.SetValue(+x)
		case mysql.Duration:
			u.SetValue(x)
		case mysql.Time:
			u.SetValue(x)
		case string:
			u.SetValue(x)
		case mysql.Decimal:
			u.SetValue(x)
		case []byte:
			u.SetValue(x)
		case mysql.Hex:
			u.SetValue(x)
		case mysql.Bit:
			u.SetValue(x)
		case mysql.Enum:
			u.SetValue(x)
		case mysql.Set:
			u.SetValue(x)
		default:
			e.err = ErrInvalidOperation
			return false
		}
	case opcode.Minus:
		switch x := a.(type) {
		case bool:
			if x {
				u.SetValue(int64(-1))
			} else {
				u.SetValue(int64(0))
			}
		case float32:
			u.SetValue(-x)
		case float64:
			u.SetValue(-x)
		case int:
			u.SetValue(-x)
		case int8:
			u.SetValue(-x)
		case int16:
			u.SetValue(-x)
		case int32:
			u.SetValue(-x)
		case int64:
			u.SetValue(-x)
		case uint:
			u.SetValue(-int64(x))
		case uint8:
			u.SetValue(-int64(x))
		case uint16:
			u.SetValue(-int64(x))
		case uint32:
			u.SetValue(-int64(x))
		case uint64:
			// TODO: check overflow and do more test for unsigned type
			u.SetValue(-int64(x))
		case mysql.Duration:
			u.SetValue(mysql.ZeroDecimal.Sub(x.ToNumber()))
		case mysql.Time:
			u.SetValue(mysql.ZeroDecimal.Sub(x.ToNumber()))
		case string:
			f, err := types.StrToFloat(x)
			e.err = errors.Trace(err)
			u.SetValue(-f)
		case mysql.Decimal:
			f, _ := x.Float64()
			u.SetValue(mysql.NewDecimalFromFloat(-f))
		case []byte:
			f, err := types.StrToFloat(string(x))
			e.err = errors.Trace(err)
			u.SetValue(-f)
		case mysql.Hex:
			u.SetValue(-x.ToNumber())
		case mysql.Bit:
			u.SetValue(-x.ToNumber())
		case mysql.Enum:
			u.SetValue(-x.ToNumber())
		case mysql.Set:
			u.SetValue(-x.ToNumber())
		default:
			e.err = ErrInvalidOperation
			return false
		}
	default:
		e.err = ErrInvalidOperation
		return false
	}

	return true
}
Esempio n. 6
0
func unaryOpFactory(op opcode.Op) BuiltinFunc {
	return func(args []types.Datum, _ context.Context) (d types.Datum, err error) {
		defer func() {
			if er := recover(); er != nil {
				err = errors.Errorf("%v", er)
			}
		}()
		aDatum := args[0]
		if aDatum.IsNull() {
			return
		}
		switch op {
		case opcode.Not:
			var n int64
			n, err = aDatum.ToBool()
			if err != nil {
				err = errors.Trace(err)
			} else if n == 0 {
				d.SetInt64(1)
			} else {
				d.SetInt64(0)
			}
		case opcode.BitNeg:
			var n int64
			// for bit operation, we will use int64 first, then return uint64
			n, err = aDatum.ToInt64()
			if err != nil {
				return d, errors.Trace(err)
			}
			d.SetUint64(uint64(^n))
		case opcode.Plus:
			switch aDatum.Kind() {
			case types.KindInt64,
				types.KindUint64,
				types.KindFloat64,
				types.KindFloat32,
				types.KindMysqlDuration,
				types.KindMysqlTime,
				types.KindString,
				types.KindMysqlDecimal,
				types.KindBytes,
				types.KindMysqlHex,
				types.KindMysqlBit,
				types.KindMysqlEnum,
				types.KindMysqlSet:
				d = aDatum
			default:
				return d, ErrInvalidOperation.Gen("Unsupported type %v for op.Plus", aDatum.Kind())
			}
		case opcode.Minus:
			switch aDatum.Kind() {
			case types.KindInt64:
				d.SetInt64(-aDatum.GetInt64())
			case types.KindUint64:
				d.SetInt64(-int64(aDatum.GetUint64()))
			case types.KindFloat64:
				d.SetFloat64(-aDatum.GetFloat64())
			case types.KindFloat32:
				d.SetFloat32(-aDatum.GetFloat32())
			case types.KindMysqlDuration:
				d.SetMysqlDecimal(mysql.ZeroDecimal.Sub(aDatum.GetMysqlDuration().ToNumber()))
			case types.KindMysqlTime:
				d.SetMysqlDecimal(mysql.ZeroDecimal.Sub(aDatum.GetMysqlTime().ToNumber()))
			case types.KindString, types.KindBytes:
				f, err1 := types.StrToFloat(aDatum.GetString())
				err = errors.Trace(err1)
				d.SetFloat64(-f)
			case types.KindMysqlDecimal:
				f, _ := aDatum.GetMysqlDecimal().Float64()
				d.SetMysqlDecimal(mysql.NewDecimalFromFloat(-f))
			case types.KindMysqlHex:
				d.SetFloat64(-aDatum.GetMysqlHex().ToNumber())
			case types.KindMysqlBit:
				d.SetFloat64(-aDatum.GetMysqlBit().ToNumber())
			case types.KindMysqlEnum:
				d.SetFloat64(-aDatum.GetMysqlEnum().ToNumber())
			case types.KindMysqlSet:
				d.SetFloat64(-aDatum.GetMysqlSet().ToNumber())
			default:
				return d, ErrInvalidOperation.Gen("Unsupported type %v for op.Minus", aDatum.Kind())
			}
		default:
			return d, ErrInvalidOperation.Gen("Unsupported op %v for unary op", op)
		}
		return
	}
}
Esempio n. 7
0
func (s *testAggFuncSuite) TestXAPIAvg(c *C) {
	defer testleak.AfterTest(c)()
	// Compose aggregate exec for "select avg(c2) from t groupby c1";
	//
	// Data in region1:
	// c1  c2
	// 1	11
	// 2	21
	// 1    1
	// 3    2
	//
	// Partial aggregate result for region1:
	// groupkey	cnt	sum
	// 1		2	12
	// 2		1	21
	// 3		1	2
	//
	// Data in region2:
	// 1    nil
	// 1    3
	// 3    31
	//
	// Partial aggregate result for region2:
	// groupkey	cnt	sum
	// 1		1	3
	// 3		1	31
	//
	// Expected final aggregate result:
	// avg(c2)
	// 5
	// 21
	// 16.500000
	c1 := ast.NewValueExpr([]byte{0})
	rf1 := &ast.ResultField{Expr: c1}
	c2 := ast.NewValueExpr(0)
	rf2 := &ast.ResultField{Expr: c2}
	c3 := ast.NewValueExpr(0)
	rf3 := &ast.ResultField{Expr: c3}
	col2 := &ast.ColumnNameExpr{Refer: rf2}
	fc := &ast.AggregateFuncExpr{
		F:    ast.AggFuncAvg,
		Args: []ast.ExprNode{col2},
	}
	// Return row:
	// GroupKey, Sum
	// Partial result from region1
	row1 := types.MakeDatums([]byte{1}, 2, 12)
	row2 := types.MakeDatums([]byte{2}, 1, 21)
	row3 := types.MakeDatums([]byte{3}, 1, 2)
	// Partial result from region2
	row4 := types.MakeDatums([]byte{1}, 1, 3)
	row5 := types.MakeDatums([]byte{3}, 1, 31)
	data := []([]types.Datum){row1, row2, row3, row4, row5}

	rows := make([]*Row, 0, 5)
	for _, d := range data {
		rows = append(rows, &Row{Data: d})
	}
	src := &mockExec{
		rows:   rows,
		fields: []*ast.ResultField{rf1, rf2, rf3}, // groupby, cnt, sum
	}
	agg := &XAggregateExec{
		AggFuncs: []*ast.AggregateFuncExpr{fc},
		Src:      src,
	}
	ast.SetFlag(fc)
	// First row: 5
	row, err := agg.Next()
	c.Assert(err, IsNil)
	c.Assert(row, NotNil)
	ctx := mock.NewContext()
	val, err := evaluator.Eval(ctx, fc)
	c.Assert(err, IsNil)
	c.Assert(val, testutil.DatumEquals, types.NewDecimalDatum(mysql.NewDecimalFromInt(int64(5), 0)))
	// Second row: 21
	row, err = agg.Next()
	c.Assert(err, IsNil)
	c.Assert(row, NotNil)
	val, err = evaluator.Eval(ctx, fc)
	c.Assert(err, IsNil)
	c.Assert(val, testutil.DatumEquals, types.NewDecimalDatum(mysql.NewDecimalFromInt(int64(21), 0)))
	// Third row: 16.5000
	row, err = agg.Next()
	c.Assert(err, IsNil)
	c.Assert(row, NotNil)
	val, err = evaluator.Eval(ctx, fc)
	c.Assert(err, IsNil)
	d := mysql.NewDecimalFromFloat(float64(16.5))
	d.SetFracDigits(4) // For div operator, default frac is 4.
	c.Assert(val, testutil.DatumEquals, types.NewDecimalDatum(d))
	// Forth row: nil
	row, err = agg.Next()
	c.Assert(err, IsNil)
	c.Assert(row, IsNil)
	// Close executor
	err = agg.Close()
	c.Assert(err, IsNil)
}
Esempio n. 8
0
func (e *Evaluator) unaryOperation(u *ast.UnaryOperationExpr) bool {
	defer func() {
		if er := recover(); er != nil {
			e.err = errors.Errorf("%v", er)
		}
	}()
	aDatum := u.V.GetDatum()
	if aDatum.Kind() == types.KindNull {
		u.SetNull()
		return true
	}
	switch op := u.Op; op {
	case opcode.Not:
		n, err := aDatum.ToBool()
		if err != nil {
			e.err = errors.Trace(err)
		} else if n == 0 {
			u.SetInt64(1)
		} else {
			u.SetInt64(0)
		}
	case opcode.BitNeg:
		// for bit operation, we will use int64 first, then return uint64
		n, err := aDatum.ToInt64()
		if err != nil {
			e.err = errors.Trace(err)
			return false
		}
		u.SetUint64(uint64(^n))
	case opcode.Plus:
		switch aDatum.Kind() {
		case types.KindInt64,
			types.KindUint64,
			types.KindFloat64,
			types.KindFloat32,
			types.KindMysqlDuration,
			types.KindMysqlTime,
			types.KindString,
			types.KindMysqlDecimal,
			types.KindBytes,
			types.KindMysqlHex,
			types.KindMysqlBit,
			types.KindMysqlEnum,
			types.KindMysqlSet:
			u.SetDatum(*aDatum)
		default:
			e.err = ErrInvalidOperation
			return false
		}
	case opcode.Minus:
		switch aDatum.Kind() {
		case types.KindInt64:
			u.SetInt64(-aDatum.GetInt64())
		case types.KindUint64:
			u.SetInt64(-int64(aDatum.GetUint64()))
		case types.KindFloat64:
			u.SetFloat64(-aDatum.GetFloat64())
		case types.KindFloat32:
			u.SetFloat32(-aDatum.GetFloat32())
		case types.KindMysqlDuration:
			u.SetMysqlDecimal(mysql.ZeroDecimal.Sub(aDatum.GetMysqlDuration().ToNumber()))
		case types.KindMysqlTime:
			u.SetMysqlDecimal(mysql.ZeroDecimal.Sub(aDatum.GetMysqlTime().ToNumber()))
		case types.KindString, types.KindBytes:
			f, err := types.StrToFloat(aDatum.GetString())
			e.err = errors.Trace(err)
			u.SetFloat64(-f)
		case types.KindMysqlDecimal:
			f, _ := aDatum.GetMysqlDecimal().Float64()
			u.SetMysqlDecimal(mysql.NewDecimalFromFloat(-f))
		case types.KindMysqlHex:
			u.SetFloat64(-aDatum.GetMysqlHex().ToNumber())
		case types.KindMysqlBit:
			u.SetFloat64(-aDatum.GetMysqlBit().ToNumber())
		case types.KindMysqlEnum:
			u.SetFloat64(-aDatum.GetMysqlEnum().ToNumber())
		case types.KindMysqlSet:
			u.SetFloat64(-aDatum.GetMysqlSet().ToNumber())
		default:
			e.err = ErrInvalidOperation
			return false
		}
	default:
		e.err = ErrInvalidOperation
		return false
	}

	return true
}
Esempio n. 9
0
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)
	}
}
Esempio n. 10
0
// Eval implements the Expression Eval interface.
func (u *UnaryOperation) Eval(ctx context.Context, args map[interface{}]interface{}) (r interface{}, err error) {
	defer func() {
		if e := recover(); e != nil {
			r, err = nil, errors.Errorf("%v", e)
		}
	}()

	switch op := u.Op; op {
	case opcode.Not:
		a := Eval(u.V, ctx, args)
		a = types.RawData(a)
		if a == nil {
			return
		}
		n, err := types.ToBool(a)
		if err != nil {
			return types.UndOp(a, op)
		} else if n == 0 {
			return int64(1), nil
		}
		return int64(0), nil
	case opcode.BitNeg:
		a := Eval(u.V, ctx, args)
		a = types.RawData(a)
		if a == nil {
			return
		}
		// for bit operation, we will use int64 first, then return uint64
		n, err := types.ToInt64(a)
		if err != nil {
			return types.UndOp(a, op)
		}

		return uint64(^n), nil
	case opcode.Plus:
		a := Eval(u.V, ctx, args)
		a = types.RawData(a)
		if a == nil {
			return
		}
		switch x := a.(type) {
		case nil:
			return nil, nil
		case bool:
			if x {
				return int64(1), nil
			}
			return int64(0), nil
		case float32:
			return +x, nil
		case float64:
			return +x, nil
		case int:
			return +x, nil
		case int8:
			return +x, nil
		case int16:
			return +x, nil
		case int32:
			return +x, nil
		case int64:
			return +x, nil
		case uint:
			return +x, nil
		case uint8:
			return +x, nil
		case uint16:
			return +x, nil
		case uint32:
			return +x, nil
		case uint64:
			return +x, nil
		case mysql.Duration:
			return x, nil
		case mysql.Time:
			return x, nil
		case string:
			return x, nil
		case mysql.Decimal:
			return x, nil
		case []byte:
			return x, nil
		case mysql.Hex:
			return x, nil
		case mysql.Bit:
			return x, nil
		case mysql.Enum:
			return x, nil
		case mysql.Set:
			return x, nil
		default:
			return types.UndOp(a, op)
		}
	case opcode.Minus:
		a := Eval(u.V, ctx, args)
		a = types.RawData(a)
		if a == nil {
			return
		}

		switch x := a.(type) {
		case nil:
			return nil, nil
		case bool:
			if x {
				return int64(-1), nil
			}
			return int64(0), nil
		case float32:
			return -x, nil
		case float64:
			return -x, nil
		case int:
			return -x, nil
		case int8:
			return -x, nil
		case int16:
			return -x, nil
		case int32:
			return -x, nil
		case int64:
			return -x, nil
		case uint:
			return -int64(x), nil
		case uint8:
			return -int64(x), nil
		case uint16:
			return -int64(x), nil
		case uint32:
			return -int64(x), nil
		case uint64:
			// TODO: check overflow and do more test for unsigned type
			return -int64(x), nil
		case mysql.Duration:
			return mysql.ZeroDecimal.Sub(x.ToNumber()), nil
		case mysql.Time:
			return mysql.ZeroDecimal.Sub(x.ToNumber()), nil
		case string:
			f, err := types.StrToFloat(x)
			return -f, err
		case mysql.Decimal:
			f, _ := x.Float64()
			return mysql.NewDecimalFromFloat(-f), nil
		case []byte:
			f, err := types.StrToFloat(string(x))
			return -f, err
		case mysql.Hex:
			return -x.ToNumber(), nil
		case mysql.Bit:
			return -x.ToNumber(), nil
		case mysql.Enum:
			return -x.ToNumber(), nil
		case mysql.Set:
			return -x.ToNumber(), nil
		default:
			return types.UndOp(a, op)
		}
	default:
		panic("should never happen")
	}
}
Esempio n. 11
0
// TODO: add more tests.
func (s *testEvalSuite) TestEval(c *C) {
	colID := int64(1)
	row := make(map[int64]types.Datum)
	row[colID] = types.NewIntDatum(100)
	xevaluator := &Evaluator{Row: row}
	cases := []struct {
		expr   *tipb.Expr
		result types.Datum
	}{
		// Datums.
		{
			datumExpr(types.NewFloat32Datum(1.1)),
			types.NewFloat32Datum(1.1),
		},
		{
			datumExpr(types.NewFloat64Datum(1.1)),
			types.NewFloat64Datum(1.1),
		},
		{
			datumExpr(types.NewIntDatum(1)),
			types.NewIntDatum(1),
		},
		{
			datumExpr(types.NewUintDatum(1)),
			types.NewUintDatum(1),
		},
		{
			datumExpr(types.NewBytesDatum([]byte("abc"))),
			types.NewBytesDatum([]byte("abc")),
		},
		{
			datumExpr(types.NewStringDatum("abc")),
			types.NewStringDatum("abc"),
		},
		{
			datumExpr(types.Datum{}),
			types.Datum{},
		},
		{
			datumExpr(types.NewDurationDatum(mysql.Duration{Duration: time.Hour})),
			types.NewDurationDatum(mysql.Duration{Duration: time.Hour}),
		},
		{
			datumExpr(types.NewDecimalDatum(mysql.NewDecimalFromFloat(1.1))),
			types.NewDecimalDatum(mysql.NewDecimalFromFloat(1.1)),
		},
		{
			columnExpr(1),
			types.NewIntDatum(100),
		},
		// Comparison operations.
		{
			binaryExpr(types.NewIntDatum(100), types.NewIntDatum(1), tipb.ExprType_LT),
			types.NewIntDatum(0),
		},
		{
			binaryExpr(types.NewIntDatum(1), types.NewIntDatum(100), tipb.ExprType_LT),
			types.NewIntDatum(1),
		},
		{
			binaryExpr(types.NewIntDatum(100), types.Datum{}, tipb.ExprType_LT),
			types.Datum{},
		},
		{
			binaryExpr(types.NewIntDatum(100), types.NewIntDatum(1), tipb.ExprType_LE),
			types.NewIntDatum(0),
		},
		{
			binaryExpr(types.NewIntDatum(1), types.NewIntDatum(1), tipb.ExprType_LE),
			types.NewIntDatum(1),
		},
		{
			binaryExpr(types.NewIntDatum(100), types.Datum{}, tipb.ExprType_LE),
			types.Datum{},
		},
		{
			binaryExpr(types.NewIntDatum(100), types.NewIntDatum(1), tipb.ExprType_EQ),
			types.NewIntDatum(0),
		},
		{
			binaryExpr(types.NewIntDatum(100), types.NewIntDatum(100), tipb.ExprType_EQ),
			types.NewIntDatum(1),
		},
		{
			binaryExpr(types.NewIntDatum(100), types.Datum{}, tipb.ExprType_EQ),
			types.Datum{},
		},
		{
			binaryExpr(types.NewIntDatum(100), types.NewIntDatum(100), tipb.ExprType_NE),
			types.NewIntDatum(0),
		},
		{
			binaryExpr(types.NewIntDatum(100), types.NewIntDatum(1), tipb.ExprType_NE),
			types.NewIntDatum(1),
		},
		{
			binaryExpr(types.NewIntDatum(100), types.Datum{}, tipb.ExprType_NE),
			types.Datum{},
		},
		{
			binaryExpr(types.NewIntDatum(1), types.NewIntDatum(100), tipb.ExprType_GE),
			types.NewIntDatum(0),
		},
		{
			binaryExpr(types.NewIntDatum(100), types.NewIntDatum(100), tipb.ExprType_GE),
			types.NewIntDatum(1),
		},
		{
			binaryExpr(types.NewIntDatum(100), types.Datum{}, tipb.ExprType_GE),
			types.Datum{},
		},
		{
			binaryExpr(types.NewIntDatum(100), types.NewIntDatum(100), tipb.ExprType_GT),
			types.NewIntDatum(0),
		},
		{
			binaryExpr(types.NewIntDatum(100), types.NewIntDatum(1), tipb.ExprType_GT),
			types.NewIntDatum(1),
		},
		{
			binaryExpr(types.NewIntDatum(100), types.Datum{}, tipb.ExprType_GT),
			types.Datum{},
		},
		{
			binaryExpr(types.NewIntDatum(1), types.Datum{}, tipb.ExprType_NullEQ),
			types.NewIntDatum(0),
		},
		{
			binaryExpr(types.Datum{}, types.Datum{}, tipb.ExprType_NullEQ),
			types.NewIntDatum(1),
		},
		// Logic operation.
		{
			binaryExpr(types.NewIntDatum(0), types.NewIntDatum(1), tipb.ExprType_And),
			types.NewIntDatum(0),
		},
		{
			binaryExpr(types.NewIntDatum(1), types.NewIntDatum(1), tipb.ExprType_And),
			types.NewIntDatum(1),
		},
		{
			binaryExpr(types.NewIntDatum(0), types.Datum{}, tipb.ExprType_And),
			types.NewIntDatum(0),
		},
		{
			binaryExpr(types.NewIntDatum(1), types.Datum{}, tipb.ExprType_And),
			types.Datum{},
		},
		{
			binaryExpr(types.NewIntDatum(0), types.NewIntDatum(0), tipb.ExprType_Or),
			types.NewIntDatum(0),
		},
		{
			binaryExpr(types.NewIntDatum(0), types.NewIntDatum(1), tipb.ExprType_Or),
			types.NewIntDatum(1),
		},
		{
			binaryExpr(types.NewIntDatum(0), types.Datum{}, tipb.ExprType_Or),
			types.Datum{},
		},
		{
			binaryExpr(types.NewIntDatum(1), types.Datum{}, tipb.ExprType_Or),
			types.NewIntDatum(1),
		},
		{
			binaryExpr(
				binaryExpr(types.NewIntDatum(1), types.NewIntDatum(1), tipb.ExprType_EQ),
				binaryExpr(types.NewIntDatum(1), types.NewIntDatum(1), tipb.ExprType_EQ),
				tipb.ExprType_And),
			types.NewIntDatum(1),
		},
		{
			notExpr(datumExpr(types.NewIntDatum(1))),
			types.NewIntDatum(0),
		},
		{
			notExpr(datumExpr(types.NewIntDatum(0))),
			types.NewIntDatum(1),
		},
		{
			notExpr(datumExpr(types.Datum{})),
			types.Datum{},
		},
	}
	for _, ca := range cases {
		result, err := xevaluator.Eval(ca.expr)
		c.Assert(err, IsNil)
		c.Assert(result.Kind(), Equals, ca.result.Kind())
		cmp, err := result.CompareDatum(ca.result)
		c.Assert(err, IsNil)
		c.Assert(cmp, Equals, 0)
	}
}