Пример #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 getZeroValue(col *model.ColumnInfo) types.Datum {
	var d types.Datum
	switch col.Tp {
	case mysql.TypeTiny, mysql.TypeInt24, mysql.TypeShort, mysql.TypeLong, mysql.TypeLonglong, mysql.TypeYear:
		if mysql.HasUnsignedFlag(col.Flag) {
			d.SetUint64(0)
		} else {
			d.SetInt64(0)
		}
	case mysql.TypeFloat:
		d.SetFloat32(0)
	case mysql.TypeDouble:
		d.SetFloat64(0)
	case mysql.TypeNewDecimal:
		d.SetMysqlDecimal(mysql.NewDecimalFromInt(0, 0))
	case mysql.TypeString, mysql.TypeVarString, mysql.TypeVarchar:
		d.SetString("")
	case mysql.TypeBlob, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob:
		d.SetBytes([]byte{})
	case mysql.TypeDuration:
		d.SetMysqlDuration(mysql.ZeroDuration)
	case mysql.TypeDate, mysql.TypeNewDate:
		d.SetMysqlTime(mysql.ZeroDate)
	case mysql.TypeTimestamp:
		d.SetMysqlTime(mysql.ZeroTimestamp)
	case mysql.TypeDatetime:
		d.SetMysqlTime(mysql.ZeroDatetime)
	case mysql.TypeBit:
		d.SetMysqlBit(mysql.Bit{Value: 0, Width: mysql.MinBitWidth})
	case mysql.TypeSet:
		d.SetMysqlSet(mysql.Set{})
	}
	return d
}
Пример #3
0
// DecodeDecimal decodes bytes to decimal.
// DecodeFloat decodes a float from a byte slice
// Decimal decoding:
// Byte -> value sign
// DecodeInt -> exp value
// DecodeBytes -> abs value bytes
func DecodeDecimal(b []byte) ([]byte, mysql.Decimal, error) {
	var (
		r   = b
		d   mysql.Decimal
		err error
	)

	// Decode value sign.
	valSign := int64(r[0])
	r = r[1:]
	if valSign == zeroSign {
		d, err = mysql.ParseDecimal("0")
		return r, d, errors.Trace(err)
	}

	// Decode exp value.
	expVal := int64(0)
	r, expVal, err = DecodeInt(r)
	if err != nil {
		return r, d, errors.Trace(err)
	}

	// Decode abs value bytes.
	value := []byte{}
	if valSign == negativeSign {
		expVal = -expVal
		r, value, err = DecodeBytesDesc(r)
	} else {
		r, value, err = DecodeBytes(r)
	}
	if err != nil {
		return r, d, errors.Trace(err)
	}

	// Set decimal sign and point to value.
	if valSign == negativeSign {
		value = append([]byte("-0."), value...)
	} else {
		value = append([]byte("0."), value...)
	}

	numberDecimal, err := mysql.ParseDecimal(string(value))
	if err != nil {
		return r, d, errors.Trace(err)
	}

	expDecimal := mysql.NewDecimalFromInt(1, int32(expVal))
	d = numberDecimal.Mul(expDecimal)
	if expDecimal.Exponent() > 0 {
		// For int64(3), it will be converted to value=0.3 and exp=1 when doing encode.
		// Its frac will be changed after we run d = numberDecimal.Mul(expDecimal).
		// So we try to get frac to the original one.
		d.SetFracDigits(d.FracDigits() - expDecimal.Exponent())
	}
	return r, d, nil
}
Пример #4
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)
	}
}
Пример #5
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)
}
Пример #6
0
// DecodeDecimal decodes bytes to decimal.
// DecodeFloat decodes a float from a byte slice
// Decimal decoding:
// Byte -> value sign
// DecodeInt -> exp value
// DecodeBytes -> abs value bytes
func DecodeDecimal(b []byte) ([]byte, mysql.Decimal, error) {
	var (
		r   = b
		d   mysql.Decimal
		err error
	)

	// Decode value sign.
	valSign := int64(r[0])
	r = r[1:]
	if valSign == zeroSign {
		d, err = mysql.ParseDecimal("0")
		return r, d, errors.Trace(err)
	}

	// Decode exp value.
	expVal := int64(0)
	r, expVal, err = DecodeInt(r)
	if err != nil {
		return r, d, errors.Trace(err)
	}

	// Decode abs value bytes.
	value := []byte{}
	if valSign == negativeSign {
		expVal = -expVal
		r, value, err = DecodeBytesDesc(r)
	} else {
		r, value, err = DecodeBytes(r)
	}
	if err != nil {
		return r, d, errors.Trace(err)
	}

	// Set decimal sign and point to value.
	if valSign == negativeSign {
		value = append([]byte("-0."), value...)
	} else {
		value = append([]byte("0."), value...)
	}

	numberDecimal, err := mysql.ParseDecimal(string(value))
	if err != nil {
		return r, d, errors.Trace(err)
	}

	expDecimal := mysql.NewDecimalFromInt(1, int32(expVal))
	d = numberDecimal.Mul(expDecimal)
	return r, d, nil
}
Пример #7
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
}
Пример #8
0
func (s *testUnaryOperationSuite) TestUnaryOp(c *C) {
	tbl := []struct {
		arg    interface{}
		op     opcode.Op
		result interface{}
	}{
		// test NOT.
		{1, opcode.Not, int64(0)},
		{0, opcode.Not, int64(1)},
		{nil, opcode.Not, nil},
		{mysql.Hex{Value: 0}, opcode.Not, int64(1)},
		{mysql.Bit{Value: 0, Width: 1}, opcode.Not, int64(1)},
		{mysql.Enum{Name: "a", Value: 1}, opcode.Not, int64(0)},
		{mysql.Set{Name: "a", Value: 1}, opcode.Not, int64(0)},

		// test BitNeg.
		{nil, opcode.BitNeg, nil},
		{-1, opcode.BitNeg, uint64(0)},

		// test Plus.
		{nil, opcode.Plus, nil},
		{float32(1.0), opcode.Plus, float32(1.0)},
		{float64(1.0), opcode.Plus, float64(1.0)},
		{int(1), opcode.Plus, int(1)},
		{int64(1), opcode.Plus, int64(1)},
		{uint64(1), opcode.Plus, uint64(1)},
		{"1.0", opcode.Plus, "1.0"},
		{[]byte("1.0"), opcode.Plus, []byte("1.0")},
		{mysql.Hex{Value: 1}, opcode.Plus, mysql.Hex{Value: 1}},
		{mysql.Bit{Value: 1, Width: 1}, opcode.Plus, mysql.Bit{Value: 1, Width: 1}},
		{true, opcode.Plus, int64(1)},
		{false, opcode.Plus, int64(0)},
		{mysql.Enum{Name: "a", Value: 1}, opcode.Plus, mysql.Enum{Name: "a", Value: 1}},
		{mysql.Set{Name: "a", Value: 1}, opcode.Plus, mysql.Set{Name: "a", Value: 1}},

		// test Minus.
		{nil, opcode.Minus, nil},
		{float32(1.0), opcode.Minus, float32(-1.0)},
		{float64(1.0), opcode.Minus, float64(-1.0)},
		{int(1), opcode.Minus, int(-1)},
		{int64(1), opcode.Minus, int64(-1)},
		{uint(1), opcode.Minus, -int64(1)},
		{uint8(1), opcode.Minus, -int64(1)},
		{uint16(1), opcode.Minus, -int64(1)},
		{uint32(1), opcode.Minus, -int64(1)},
		{uint64(1), opcode.Minus, -int64(1)},
		{"1.0", opcode.Minus, -1.0},
		{[]byte("1.0"), opcode.Minus, -1.0},
		{mysql.Hex{Value: 1}, opcode.Minus, -1.0},
		{mysql.Bit{Value: 1, Width: 1}, opcode.Minus, -1.0},
		{true, opcode.Minus, int64(-1)},
		{false, opcode.Minus, int64(0)},
		{mysql.Enum{Name: "a", Value: 1}, opcode.Minus, -1.0},
		{mysql.Set{Name: "a", Value: 1}, opcode.Minus, -1.0},
	}

	for _, t := range tbl {
		expr := NewUnaryOperation(t.op, Value{t.arg})

		exprc := expr.Clone()

		result, err := exprc.Eval(nil, nil)
		c.Assert(err, IsNil)
		c.Assert(result, DeepEquals, t.result)
	}

	tbl = []struct {
		arg    interface{}
		op     opcode.Op
		result interface{}
	}{
		{mysql.NewDecimalFromInt(1, 0), opcode.Plus, mysql.NewDecimalFromInt(1, 0)},
		{mysql.Duration{Duration: time.Duration(838*3600 + 59*60 + 59), Fsp: mysql.DefaultFsp}, opcode.Plus,
			mysql.Duration{Duration: time.Duration(838*3600 + 59*60 + 59), Fsp: mysql.DefaultFsp}},
		{mysql.Time{Time: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), Type: mysql.TypeDatetime, Fsp: 0}, opcode.Plus, mysql.Time{Time: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), Type: mysql.TypeDatetime, Fsp: 0}},

		{mysql.NewDecimalFromInt(1, 0), opcode.Minus, mysql.NewDecimalFromInt(-1, 0)},
		{mysql.ZeroDuration, opcode.Minus, mysql.NewDecimalFromInt(0, 0)},
		{mysql.Time{Time: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), Type: mysql.TypeDatetime, Fsp: 0}, opcode.Minus, mysql.NewDecimalFromInt(-20091110230000, 0)},
	}

	for _, t := range tbl {
		expr := NewUnaryOperation(t.op, Value{t.arg})

		exprc := expr.Clone()

		result, err := exprc.Eval(nil, nil)
		c.Assert(err, IsNil)

		ret, err := types.Compare(result, t.result)
		c.Assert(err, IsNil)
		c.Assert(ret, Equals, 0)
	}

	// test String().
	strTbl := []struct {
		expr     Expression
		op       opcode.Op
		isStatic bool
	}{
		{NewBinaryOperation(opcode.EQ, Value{1}, Value{1}), opcode.Plus, true},
		{NewUnaryOperation(opcode.Not, Value{1}), opcode.Not, true},
		{Value{1}, opcode.Not, true},
		{Value{1}, opcode.Plus, true},
		{&PExpr{Value{1}}, opcode.Not, true},

		{NewBinaryOperation(opcode.EQ, Value{1}, Value{1}), opcode.Not, true},
		{NewBinaryOperation(opcode.NE, Value{1}, Value{1}), opcode.Not, true},
		{NewBinaryOperation(opcode.GT, Value{1}, Value{1}), opcode.Not, true},
		{NewBinaryOperation(opcode.GE, Value{1}, Value{1}), opcode.Not, true},
		{NewBinaryOperation(opcode.LT, Value{1}, Value{1}), opcode.Not, true},
		{NewBinaryOperation(opcode.LE, Value{1}, Value{1}), opcode.Not, true},
	}

	for _, t := range strTbl {
		expr := NewUnaryOperation(t.op, t.expr)

		c.Assert(expr.IsStatic(), Equals, t.isStatic)

		str := expr.String()
		c.Assert(len(str), Greater, 0)

	}

	// test error.
	errTbl := []struct {
		arg interface{}
		op  opcode.Op
	}{
		{mockExpr{}, opcode.Not},
		{mockExpr{}, opcode.BitNeg},
		{mockExpr{}, opcode.Plus},
		{mockExpr{}, opcode.Minus},
		{mockExpr{}, opcode.EQ},
	}

	// test error clone
	expr := NewUnaryOperation(opcode.Not, mockExpr{err: errors.New("must error")})
	c.Assert(expr.Clone(), NotNil)

	for _, t := range errTbl {
		expr := NewUnaryOperation(t.op, Value{t.arg})
		_, err := expr.Eval(nil, nil)
		c.Assert(err, NotNil)
	}
}
Пример #9
0
func (s *testEvaluatorSuite) TestUnaryOp(c *C) {
	tbl := []struct {
		arg    interface{}
		op     opcode.Op
		result interface{}
	}{
		// test NOT.
		{1, opcode.Not, int64(0)},
		{0, opcode.Not, int64(1)},
		{nil, opcode.Not, nil},
		{mysql.Hex{Value: 0}, opcode.Not, int64(1)},
		{mysql.Bit{Value: 0, Width: 1}, opcode.Not, int64(1)},
		{mysql.Enum{Name: "a", Value: 1}, opcode.Not, int64(0)},
		{mysql.Set{Name: "a", Value: 1}, opcode.Not, int64(0)},

		// test BitNeg.
		{nil, opcode.BitNeg, nil},
		{-1, opcode.BitNeg, uint64(0)},

		// test Plus.
		{nil, opcode.Plus, nil},
		{float64(1.0), opcode.Plus, float64(1.0)},
		{int(1), opcode.Plus, int(1)},
		{int64(1), opcode.Plus, int64(1)},
		{uint64(1), opcode.Plus, uint64(1)},
		{"1.0", opcode.Plus, "1.0"},
		{[]byte("1.0"), opcode.Plus, []byte("1.0")},
		{mysql.Hex{Value: 1}, opcode.Plus, mysql.Hex{Value: 1}},
		{mysql.Bit{Value: 1, Width: 1}, opcode.Plus, mysql.Bit{Value: 1, Width: 1}},
		{true, opcode.Plus, int64(1)},
		{false, opcode.Plus, int64(0)},
		{mysql.Enum{Name: "a", Value: 1}, opcode.Plus, mysql.Enum{Name: "a", Value: 1}},
		{mysql.Set{Name: "a", Value: 1}, opcode.Plus, mysql.Set{Name: "a", Value: 1}},

		// test Minus.
		{nil, opcode.Minus, nil},
		{float64(1.0), opcode.Minus, float64(-1.0)},
		{int(1), opcode.Minus, int(-1)},
		{int64(1), opcode.Minus, int64(-1)},
		{uint64(1), opcode.Minus, -int64(1)},
		{"1.0", opcode.Minus, -1.0},
		{[]byte("1.0"), opcode.Minus, -1.0},
		{mysql.Hex{Value: 1}, opcode.Minus, -1.0},
		{mysql.Bit{Value: 1, Width: 1}, opcode.Minus, -1.0},
		{true, opcode.Minus, int64(-1)},
		{false, opcode.Minus, int64(0)},
		{mysql.Enum{Name: "a", Value: 1}, opcode.Minus, -1.0},
		{mysql.Set{Name: "a", Value: 1}, opcode.Minus, -1.0},
	}
	ctx := mock.NewContext()
	expr := &ast.UnaryOperationExpr{}
	for _, t := range tbl {
		expr.Op = t.op
		expr.V = ast.NewValueExpr(t.arg)
		result, err := Eval(ctx, expr)
		c.Assert(err, IsNil)
		c.Assert(result, DeepEquals, t.result)
	}

	tbl = []struct {
		arg    interface{}
		op     opcode.Op
		result interface{}
	}{
		{mysql.NewDecimalFromInt(1, 0), opcode.Plus, mysql.NewDecimalFromInt(1, 0)},
		{mysql.Duration{Duration: time.Duration(838*3600 + 59*60 + 59), Fsp: mysql.DefaultFsp}, opcode.Plus,
			mysql.Duration{Duration: time.Duration(838*3600 + 59*60 + 59), Fsp: mysql.DefaultFsp}},
		{mysql.Time{Time: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), Type: mysql.TypeDatetime, Fsp: 0}, opcode.Plus, mysql.Time{Time: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), Type: mysql.TypeDatetime, Fsp: 0}},

		{mysql.NewDecimalFromInt(1, 0), opcode.Minus, mysql.NewDecimalFromInt(-1, 0)},
		{mysql.ZeroDuration, opcode.Minus, mysql.NewDecimalFromInt(0, 0)},
		{mysql.Time{Time: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), Type: mysql.TypeDatetime, Fsp: 0}, opcode.Minus, mysql.NewDecimalFromInt(-20091110230000, 0)},
	}

	for _, t := range tbl {
		expr := &ast.UnaryOperationExpr{Op: t.op, V: ast.NewValueExpr(t.arg)}

		result, err := Eval(ctx, expr)
		c.Assert(err, IsNil)

		ret, err := types.Compare(result, t.result)
		c.Assert(err, IsNil)
		c.Assert(ret, Equals, 0)
	}
}
Пример #10
0
func (s *testTableCodecSuite) TestRowCodec(c *C) {
	defer testleak.AfterTest(c)()

	c1 := &column{id: 1, tp: types.NewFieldType(mysql.TypeLonglong)}
	c2 := &column{id: 2, tp: types.NewFieldType(mysql.TypeVarchar)}
	c3 := &column{id: 3, tp: types.NewFieldType(mysql.TypeNewDecimal)}
	cols := []*column{c1, c2, c3}

	row := make([]types.Datum, 3)
	row[0] = types.NewIntDatum(100)
	row[1] = types.NewBytesDatum([]byte("abc"))
	row[2] = types.NewDecimalDatum(mysql.NewDecimalFromInt(1, 1))
	// Encode
	colIDs := make([]int64, 0, 3)
	for _, col := range cols {
		colIDs = append(colIDs, col.id)
	}
	bs, err := EncodeRow(row, colIDs)
	c.Assert(err, IsNil)
	c.Assert(bs, NotNil)

	// Decode
	colMap := make(map[int64]*types.FieldType, 3)
	for _, col := range cols {
		colMap[col.id] = col.tp
	}
	r, err := DecodeRow(bs, colMap)
	c.Assert(err, IsNil)
	c.Assert(r, NotNil)
	c.Assert(r, HasLen, 3)
	// Compare decoded row and original row
	for i, col := range cols {
		v, ok := r[col.id]
		c.Assert(ok, IsTrue)
		equal, err1 := v.CompareDatum(row[i])
		c.Assert(err1, IsNil)
		c.Assert(equal, Equals, 0)
	}

	// colMap may contains more columns than encoded row.
	colMap[4] = types.NewFieldType(mysql.TypeFloat)
	r, err = DecodeRow(bs, colMap)
	c.Assert(err, IsNil)
	c.Assert(r, NotNil)
	c.Assert(r, HasLen, 3)
	for i, col := range cols {
		v, ok := r[col.id]
		c.Assert(ok, IsTrue)
		equal, err1 := v.CompareDatum(row[i])
		c.Assert(err1, IsNil)
		c.Assert(equal, Equals, 0)
	}

	// colMap may contains less columns than encoded row.
	delete(colMap, 3)
	delete(colMap, 4)
	r, err = DecodeRow(bs, colMap)
	c.Assert(err, IsNil)
	c.Assert(r, NotNil)
	c.Assert(r, HasLen, 2)
	for i, col := range cols {
		if i > 1 {
			break
		}
		v, ok := r[col.id]
		c.Assert(ok, IsTrue)
		equal, err1 := v.CompareDatum(row[i])
		c.Assert(err1, IsNil)
		c.Assert(equal, Equals, 0)
	}

	// Make sure empty row return not nil value.
	bs, err = EncodeRow([]types.Datum{}, []int64{})
	c.Assert(err, IsNil)
	c.Assert(bs, HasLen, 1)

	r, err = DecodeRow(bs, colMap)
	c.Assert(err, IsNil)
	c.Assert(r, IsNil)
}
Пример #11
0
func (s *testBuiltinSuite) TestGroupBy(c *C) {
	tbl := []struct {
		F string
		// args for every Eval round
		RoundArgs []interface{}
		Distinct  bool
		Ret       interface{}
	}{
		{"avg", []interface{}{1, 1}, false, 1},
		{"avg", []interface{}{1, 2}, true, 1.5},
		{"avg", []interface{}{1.0, 2.0}, true, 1.5},
		{"avg", []interface{}{1, 1}, true, 1},
		{"avg", []interface{}{nil, nil}, true, nil},
		{"count", []interface{}{1, 1}, false, 2},
		{"count", []interface{}{1, 1}, true, 1},
		{"count", []interface{}{nil, nil}, true, 0},
		{"count", []interface{}{nil, nil}, false, 0},
		{"count", []interface{}{nil, 1}, true, 1},
		{"max", []interface{}{1, 2, 3}, false, 3},
		{"max", []interface{}{nil, 2}, false, 2},
		{"max", []interface{}{nil, nil}, false, nil},
		{"min", []interface{}{1, 2, 3}, false, 1},
		{"min", []interface{}{nil, 1}, false, 1},
		{"min", []interface{}{nil, nil}, false, nil},
		{"min", []interface{}{3, 2, 1}, false, 1},
		{"sum", []interface{}{1, 1, 1, 1, 1}, false, 5},
		{"sum", []interface{}{float64(1.0), float64(1.0)}, false, 2.0},
		{"sum", []interface{}{1, 1, 1, 1, 1}, true, 1},
		{"sum", []interface{}{1, mysql.NewDecimalFromInt(1, 0)}, false, 2},
		{"sum", []interface{}{nil, nil}, false, nil},
		{"sum", []interface{}{nil, nil}, true, nil},
	}

	for _, t := range tbl {
		f, ok := Funcs[t.F]
		c.Assert(ok, IsTrue)

		m := map[interface{}]interface{}{}

		m[ExprEvalFn] = new(Func)
		m[ExprAggDistinct] = CreateAggregateDistinct(t.F, t.Distinct)

		for _, arg := range t.RoundArgs {
			args := []interface{}{arg}

			_, err := f.F(args, m)
			c.Assert(err, IsNil)
		}

		m[ExprAggDone] = struct{}{}
		v, err := f.F(nil, m)
		c.Assert(err, IsNil)
		switch v.(type) {
		case nil:
			c.Assert(t.Ret, IsNil)
		default:
			// we can not check decimal type directly, but we can convert all to float64
			f, err := types.ToFloat64(v)
			c.Assert(err, IsNil)

			ret, err := types.ToFloat64(t.Ret)
			c.Assert(err, IsNil)

			c.Assert(f, Equals, ret)
		}
	}
}
Пример #12
0
func (s *testEvaluatorSuite) TestBinopNumeric(c *C) {
	ctx := mock.NewContext()
	tbl := []struct {
		lhs interface{}
		op  opcode.Op
		rhs interface{}
		ret interface{}
	}{
		// plus
		{1, opcode.Plus, 1, 2},
		{1, opcode.Plus, uint64(1), 2},
		{1, opcode.Plus, "1", 2},
		{1, opcode.Plus, mysql.NewDecimalFromInt(1, 0), 2},
		{uint64(1), opcode.Plus, 1, 2},
		{uint64(1), opcode.Plus, uint64(1), 2},
		{1, opcode.Plus, []byte("1"), 2},
		{1, opcode.Plus, mysql.Hex{Value: 1}, 2},
		{1, opcode.Plus, mysql.Bit{Value: 1, Width: 1}, 2},
		{1, opcode.Plus, mysql.Enum{Name: "a", Value: 1}, 2},
		{1, opcode.Plus, mysql.Set{Name: "a", Value: 1}, 2},

		// minus
		{1, opcode.Minus, 1, 0},
		{1, opcode.Minus, uint64(1), 0},
		{1, opcode.Minus, float64(1), 0},
		{1, opcode.Minus, mysql.NewDecimalFromInt(1, 0), 0},
		{uint64(1), opcode.Minus, 1, 0},
		{uint64(1), opcode.Minus, uint64(1), 0},
		{mysql.NewDecimalFromInt(1, 0), opcode.Minus, 1, 0},
		{"1", opcode.Minus, []byte("1"), 0},

		// mul
		{1, opcode.Mul, 1, 1},
		{1, opcode.Mul, uint64(1), 1},
		{1, opcode.Mul, float64(1), 1},
		{1, opcode.Mul, mysql.NewDecimalFromInt(1, 0), 1},
		{uint64(1), opcode.Mul, 1, 1},
		{uint64(1), opcode.Mul, uint64(1), 1},
		{mysql.Time{}, opcode.Mul, 0, 0},
		{mysql.ZeroDuration, opcode.Mul, 0, 0},
		{mysql.Time{Time: time.Now(), Fsp: 0, Type: mysql.TypeDatetime}, opcode.Mul, 0, 0},
		{mysql.Time{Time: time.Now(), Fsp: 6, Type: mysql.TypeDatetime}, opcode.Mul, 0, 0},
		{mysql.Duration{Duration: 100000000, Fsp: 6}, opcode.Mul, 0, 0},

		// div
		{1, opcode.Div, float64(1), 1},
		{1, opcode.Div, float64(0), nil},
		{1, opcode.Div, 2, 0.5},
		{1, opcode.Div, 0, nil},

		// int div
		{1, opcode.IntDiv, 2, 0},
		{1, opcode.IntDiv, uint64(2), 0},
		{1, opcode.IntDiv, 0, nil},
		{1, opcode.IntDiv, uint64(0), nil},
		{uint64(1), opcode.IntDiv, 2, 0},
		{uint64(1), opcode.IntDiv, uint64(2), 0},
		{uint64(1), opcode.IntDiv, 0, nil},
		{uint64(1), opcode.IntDiv, uint64(0), nil},
		{1.0, opcode.IntDiv, 2.0, 0},
		{1.0, opcode.IntDiv, 0, nil},

		// mod
		{10, opcode.Mod, 2, 0},
		{10, opcode.Mod, uint64(2), 0},
		{10, opcode.Mod, 0, nil},
		{10, opcode.Mod, uint64(0), nil},
		{-10, opcode.Mod, uint64(2), 0},
		{uint64(10), opcode.Mod, 2, 0},
		{uint64(10), opcode.Mod, uint64(2), 0},
		{uint64(10), opcode.Mod, 0, nil},
		{uint64(10), opcode.Mod, uint64(0), nil},
		{uint64(10), opcode.Mod, -2, 0},
		{float64(10), opcode.Mod, 2, 0},
		{float64(10), opcode.Mod, 0, nil},
		{mysql.NewDecimalFromInt(10, 0), opcode.Mod, 2, 0},
		{mysql.NewDecimalFromInt(10, 0), opcode.Mod, 0, nil},
	}

	for _, t := range tbl {
		expr := &ast.BinaryOperationExpr{Op: t.op, L: ast.NewValueExpr(t.lhs), R: ast.NewValueExpr(t.rhs)}
		v, err := Eval(ctx, expr)
		c.Assert(err, IsNil)
		switch v.(type) {
		case nil:
			c.Assert(t.ret, IsNil)
		default:
			// we use float64 as the result type check for all.
			f, err := types.ToFloat64(v)
			c.Assert(err, IsNil)

			r, err := types.ToFloat64(t.ret)
			c.Assert(err, IsNil)
			c.Assert(r, Equals, f)
		}
	}
}
Пример #13
0
func (s *testTypeConvertSuite) TestConvert(c *check.C) {
	// integer ranges
	signedDeny(c, mysql.TypeTiny, -129, "-128")
	signedAccept(c, mysql.TypeTiny, -128, "-128")
	signedAccept(c, mysql.TypeTiny, 127, "127")
	signedDeny(c, mysql.TypeTiny, 128, "127")
	unsignedDeny(c, mysql.TypeTiny, -1, "0")
	unsignedAccept(c, mysql.TypeTiny, 0, "0")
	unsignedAccept(c, mysql.TypeTiny, 255, "255")
	unsignedDeny(c, mysql.TypeTiny, 256, "255")

	signedDeny(c, mysql.TypeShort, int64(math.MinInt16)-1, strvalue(int64(math.MinInt16)))
	signedAccept(c, mysql.TypeShort, int64(math.MinInt16), strvalue(int64(math.MinInt16)))
	signedAccept(c, mysql.TypeShort, int64(math.MaxInt16), strvalue(int64(math.MaxInt16)))
	signedDeny(c, mysql.TypeShort, int64(math.MaxInt16)+1, strvalue(int64(math.MaxInt16)))
	unsignedDeny(c, mysql.TypeShort, -1, "0")
	unsignedAccept(c, mysql.TypeShort, 0, "0")
	unsignedAccept(c, mysql.TypeShort, uint64(math.MaxUint16), strvalue(uint64(math.MaxUint16)))
	unsignedDeny(c, mysql.TypeShort, uint64(math.MaxUint16)+1, strvalue(uint64(math.MaxUint16)))

	signedDeny(c, mysql.TypeInt24, -1<<23-1, strvalue(-1<<23))
	signedAccept(c, mysql.TypeInt24, -1<<23, strvalue(-1<<23))
	signedAccept(c, mysql.TypeInt24, 1<<23-1, strvalue(1<<23-1))
	signedDeny(c, mysql.TypeInt24, 1<<23, strvalue(1<<23-1))
	unsignedDeny(c, mysql.TypeInt24, -1, "0")
	unsignedAccept(c, mysql.TypeInt24, 0, "0")
	unsignedAccept(c, mysql.TypeInt24, 1<<24-1, strvalue(1<<24-1))
	unsignedDeny(c, mysql.TypeInt24, 1<<24, strvalue(1<<24-1))

	signedDeny(c, mysql.TypeLong, int64(math.MinInt32)-1, strvalue(int64(math.MinInt32)))
	signedAccept(c, mysql.TypeLong, int64(math.MinInt32), strvalue(int64(math.MinInt32)))
	signedAccept(c, mysql.TypeLong, int64(math.MaxInt32), strvalue(int64(math.MaxInt32)))
	signedDeny(c, mysql.TypeLong, uint64(math.MaxUint64), strvalue(uint64(math.MaxInt32)))
	signedDeny(c, mysql.TypeLong, int64(math.MaxInt32)+1, strvalue(int64(math.MaxInt32)))
	unsignedDeny(c, mysql.TypeLong, -1, "0")
	unsignedAccept(c, mysql.TypeLong, 0, "0")
	unsignedAccept(c, mysql.TypeLong, uint64(math.MaxUint32), strvalue(uint64(math.MaxUint32)))
	unsignedDeny(c, mysql.TypeLong, uint64(math.MaxUint32)+1, strvalue(uint64(math.MaxUint32)))

	signedDeny(c, mysql.TypeLonglong, math.MinInt64*1.1, strvalue(int64(math.MinInt64)))
	signedAccept(c, mysql.TypeLonglong, int64(math.MinInt64), strvalue(int64(math.MinInt64)))
	signedAccept(c, mysql.TypeLonglong, int64(math.MaxInt64), strvalue(int64(math.MaxInt64)))
	signedDeny(c, mysql.TypeLonglong, math.MaxInt64*1.1, strvalue(int64(math.MaxInt64)))
	unsignedDeny(c, mysql.TypeLonglong, -1, "0")
	unsignedAccept(c, mysql.TypeLonglong, 0, "0")
	unsignedAccept(c, mysql.TypeLonglong, uint64(math.MaxUint64), strvalue(uint64(math.MaxUint64)))
	unsignedDeny(c, mysql.TypeLonglong, math.MaxUint64*1.1, strvalue(uint64(math.MaxUint64)))

	// integer from string
	signedAccept(c, mysql.TypeLong, "	  234  ", "234")
	signedAccept(c, mysql.TypeLong, " 2.35e3  ", "2350")
	signedAccept(c, mysql.TypeLong, " +2.51 ", "3")
	signedAccept(c, mysql.TypeLong, " -3.58", "-4")

	// integer from float
	signedAccept(c, mysql.TypeLong, 234.5456, "235")
	signedAccept(c, mysql.TypeLong, -23.45, "-23")

	// float from string
	signedAccept(c, mysql.TypeFloat, "23.523", "23.523")
	signedAccept(c, mysql.TypeFloat, int64(123), "123")
	signedAccept(c, mysql.TypeFloat, uint64(123), "123")
	signedAccept(c, mysql.TypeFloat, int(123), "123")
	signedAccept(c, mysql.TypeFloat, float32(123), "123")
	signedAccept(c, mysql.TypeFloat, float64(123), "123")
	signedAccept(c, mysql.TypeDouble, " -23.54", "-23.54")

	// year
	signedDeny(c, mysql.TypeYear, 123, "<nil>")
	signedDeny(c, mysql.TypeYear, 3000, "<nil>")
	signedAccept(c, mysql.TypeYear, "2000", "2000")

	// time from string
	signedAccept(c, mysql.TypeDate, "2012-08-23", "2012-08-23")
	signedAccept(c, mysql.TypeDatetime, "2012-08-23 12:34:03.123456", "2012-08-23 12:34:03")
	signedAccept(c, mysql.TypeDatetime, mysql.ZeroDatetime, "0000-00-00 00:00:00")
	signedAccept(c, mysql.TypeDatetime, int64(0), "0000-00-00 00:00:00")
	signedAccept(c, mysql.TypeTimestamp, "2012-08-23 12:34:03.123456", "2012-08-23 12:34:03")
	signedAccept(c, mysql.TypeDuration, "10:11:12", "10:11:12")
	signedAccept(c, mysql.TypeDuration, mysql.ZeroDatetime, "00:00:00")
	signedAccept(c, mysql.TypeDuration, mysql.ZeroDuration, "00:00:00")

	signedDeny(c, mysql.TypeDate, "2012-08-x", "0000-00-00")
	signedDeny(c, mysql.TypeDatetime, "2012-08-x", "0000-00-00 00:00:00")
	signedDeny(c, mysql.TypeTimestamp, "2012-08-x", "0000-00-00 00:00:00")
	signedDeny(c, mysql.TypeDuration, "2012-08-x", "00:00:00")
	signedDeny(c, mysql.TypeDuration, 0, "<nil>")

	// string from string
	signedAccept(c, mysql.TypeString, "abc", "abc")

	// string from integer
	signedAccept(c, mysql.TypeString, 5678, "5678")
	signedAccept(c, mysql.TypeString, mysql.ZeroDuration, "00:00:00")
	signedAccept(c, mysql.TypeString, mysql.ZeroDatetime, "0000-00-00 00:00:00")
	signedAccept(c, mysql.TypeString, []byte("123"), "123")

	//TODO add more tests
	signedAccept(c, mysql.TypeNewDecimal, 123, "123")
	signedAccept(c, mysql.TypeNewDecimal, int64(123), "123")
	signedAccept(c, mysql.TypeNewDecimal, uint64(123), "123")
	signedAccept(c, mysql.TypeNewDecimal, float32(123), "123")
	signedAccept(c, mysql.TypeNewDecimal, 123.456, "123.456")
	signedAccept(c, mysql.TypeNewDecimal, "-123.456", "-123.456")
	signedAccept(c, mysql.TypeNewDecimal, mysql.NewDecimalFromInt(123, 5), "12300000")
	signedAccept(c, mysql.TypeNewDecimal, mysql.NewDecimalFromInt(-123, -5), "-0.00123")
}
Пример #14
0
func (s *testColumnSuite) TestGetZeroValue(c *C) {
	cases := []struct {
		ft    *types.FieldType
		value types.Datum
	}{
		{
			types.NewFieldType(mysql.TypeLong),
			types.NewIntDatum(0),
		},
		{
			&types.FieldType{
				Tp:   mysql.TypeLonglong,
				Flag: mysql.UnsignedFlag,
			},
			types.NewUintDatum(0),
		},
		{
			types.NewFieldType(mysql.TypeFloat),
			types.NewFloat32Datum(0),
		},
		{
			types.NewFieldType(mysql.TypeDouble),
			types.NewFloat64Datum(0),
		},
		{
			types.NewFieldType(mysql.TypeNewDecimal),
			types.NewDecimalDatum(mysql.NewDecimalFromInt(0, 0)),
		},
		{
			types.NewFieldType(mysql.TypeVarchar),
			types.NewStringDatum(""),
		},
		{
			types.NewFieldType(mysql.TypeBlob),
			types.NewBytesDatum([]byte{}),
		},
		{
			types.NewFieldType(mysql.TypeDuration),
			types.NewDurationDatum(mysql.ZeroDuration),
		},
		{
			types.NewFieldType(mysql.TypeDatetime),
			types.NewDatum(mysql.ZeroDatetime),
		},
		{
			types.NewFieldType(mysql.TypeTimestamp),
			types.NewDatum(mysql.ZeroTimestamp),
		},
		{
			types.NewFieldType(mysql.TypeDate),
			types.NewDatum(mysql.ZeroDate),
		},
		{
			types.NewFieldType(mysql.TypeBit),
			types.NewDatum(mysql.Bit{Value: 0, Width: mysql.MinBitWidth}),
		},
		{
			types.NewFieldType(mysql.TypeSet),
			types.NewDatum(mysql.Set{}),
		},
	}
	for _, ca := range cases {
		colInfo := &model.ColumnInfo{FieldType: *ca.ft}
		zv := getZeroValue(colInfo)
		c.Assert(zv.Kind(), Equals, ca.value.Kind())
		cmp, err := zv.CompareDatum(ca.value)
		c.Assert(err, IsNil)
		c.Assert(cmp, Equals, 0)
	}
}
Пример #15
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)
}
Пример #16
0
func (s *testAggFuncSuite) TestXAPISum(c *C) {
	defer testleak.AfterTest(c)()
	// Compose aggregate exec for "select sum(c2) from t groupby c1";
	//
	// Data in region1:
	// c1  c2
	// 1	11
	// 2	21
	// 1    1
	//
	// Partial aggregate result for region1:
	// groupkey	sum
	// 1		12
	// 2		21
	//
	// Data in region2:
	// 1    nil
	// 1    3
	// 3    31
	//
	// Partial aggregate result for region2:
	// groupkey	sum
	// 1		3
	// 3		31
	//
	// Expected final aggregate result:
	// sum(c2)
	// 15
	// 21
	// 31
	c1 := ast.NewValueExpr([]byte{0})
	rf1 := &ast.ResultField{Expr: c1}
	c2 := ast.NewValueExpr(0)
	rf2 := &ast.ResultField{Expr: c2}
	col2 := &ast.ColumnNameExpr{Refer: rf2}
	fc := &ast.AggregateFuncExpr{
		F:    ast.AggFuncSum,
		Args: []ast.ExprNode{col2},
	}
	// Return row:
	// GroupKey, Sum
	// Partial result from region1
	row1 := types.MakeDatums([]byte{1}, 12)
	row2 := types.MakeDatums([]byte{2}, 21)
	// Partial result from region2
	row3 := types.MakeDatums([]byte{1}, 3)
	row4 := types.MakeDatums([]byte{3}, 31)
	data := []([]types.Datum){row1, row2, row3, row4}

	rows := make([]*Row, 0, 3)
	for _, d := range data {
		rows = append(rows, &Row{Data: d})
	}
	src := &mockExec{
		rows:   rows,
		fields: []*ast.ResultField{rf1, rf2},
	}
	agg := &XAggregateExec{
		AggFuncs: []*ast.AggregateFuncExpr{fc},
		Src:      src,
	}
	ast.SetFlag(fc)
	// First row: 15
	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(15), 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: 31
	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(31), 0)))
	agg.Close()
	// After clear up, fc's value should be default.
	val, err = evaluator.Eval(ctx, fc)
	c.Assert(err, IsNil)
	c.Assert(val, testutil.DatumEquals, types.NewDatum(nil))
}
Пример #17
0
func (s *testBinOpSuite) TestComparisonOp(c *C) {
	tbl := []struct {
		lhs    interface{}
		op     opcode.Op
		rhs    interface{}
		result int64 // 0 for false, 1 for true
	}{
		// test EQ
		{1, opcode.EQ, 2, 0},
		{false, opcode.EQ, false, 1},
		{false, opcode.EQ, true, 0},
		{true, opcode.EQ, true, 1},
		{true, opcode.EQ, false, 0},
		{"1", opcode.EQ, true, 1},
		{"1", opcode.EQ, false, 0},

		// test NEQ
		{1, opcode.NE, 2, 1},
		{false, opcode.NE, false, 0},
		{false, opcode.NE, true, 1},
		{true, opcode.NE, true, 0},
		{"1", opcode.NE, true, 0},
		{"1", opcode.NE, false, 1},

		// test GT, GE
		{1, opcode.GT, 0, 1},
		{1, opcode.GT, 1, 0},
		{1, opcode.GE, 1, 1},
		{3.14, opcode.GT, 3, 1},
		{3.14, opcode.GE, 3.14, 1},

		// test LT, LE
		{1, opcode.LT, 2, 1},
		{1, opcode.LT, 1, 0},
		{1, opcode.LE, 1, 1},
	}

	for _, t := range tbl {
		expr := NewBinaryOperation(t.op, Value{t.lhs}, Value{t.rhs})
		v, err := expr.Eval(nil, nil)
		c.Assert(err, IsNil)
		val, err := types.ToBool(v)
		c.Assert(err, IsNil)
		c.Assert(val, Equals, t.result)
	}

	// test nil
	nilTbl := []struct {
		lhs interface{}
		op  opcode.Op
		rhs interface{}
	}{
		{nil, opcode.EQ, nil},
		{nil, opcode.EQ, 1},
		{nil, opcode.NE, nil},
		{nil, opcode.NE, 1},
		{nil, opcode.LT, nil},
		{nil, opcode.LT, 1},
		{nil, opcode.LE, nil},
		{nil, opcode.LE, 1},
		{nil, opcode.GT, nil},
		{nil, opcode.GT, 1},
		{nil, opcode.GE, nil},
		{nil, opcode.GE, 1},
	}

	for _, t := range nilTbl {
		expr := NewBinaryOperation(t.op, Value{t.lhs}, Value{t.rhs})
		v, err := expr.Eval(nil, nil)
		c.Assert(err, IsNil)
		c.Assert(v, IsNil)
	}

	// test error
	mock := mockExpr{
		isStatic: false,
		err:      errors.New("must error"),
	}

	errTbl := []struct {
		arg interface{}
		op  opcode.Op
	}{
		{1, opcode.EQ},
		{1.1, opcode.NE},
		{mysql.NewDecimalFromInt(1, 0), opcode.LT},
		{1, opcode.LE},
		{1.1, opcode.GT},
		{1, opcode.GE},
	}

	for _, t := range errTbl {
		expr := NewBinaryOperation(t.op, Value{t.arg}, mock)
		_, err := expr.Eval(nil, nil)
		c.Assert(err, NotNil)
		c.Assert(expr.Clone(), NotNil)

		expr = NewBinaryOperation(t.op, mock, Value{t.arg})
		_, err = expr.Eval(nil, nil)
		c.Assert(err, NotNil)

		c.Assert(expr.Clone(), NotNil)
	}

	mock.err = nil
	mock.val = "abc"

	for _, t := range errTbl {
		expr := NewBinaryOperation(t.op, Value{t.arg}, mock)
		_, err := expr.Eval(nil, nil)
		c.Assert(err, NotNil)

		expr = NewBinaryOperation(t.op, mock, Value{t.arg})
		_, err = expr.Eval(nil, nil)
		c.Assert(err, NotNil)
	}

	expr := BinaryOperation{Op: opcode.Plus, L: Value{1}, R: Value{1}}
	_, err := expr.evalComparisonOp(nil, nil)
	c.Assert(err, NotNil)
}
Пример #18
0
func (s *testBinOpSuite) TestNumericOp(c *C) {
	tbl := []struct {
		lhs interface{}
		op  opcode.Op
		rhs interface{}
		ret interface{}
	}{
		// plus
		{1, opcode.Plus, 1, 2},
		{1, opcode.Plus, uint64(1), 2},
		{1, opcode.Plus, "1", 2},
		{1, opcode.Plus, mysql.NewDecimalFromInt(1, 0), 2},
		{uint64(1), opcode.Plus, 1, 2},
		{uint64(1), opcode.Plus, uint64(1), 2},
		{1, opcode.Plus, []byte("1"), 2},
		{1, opcode.Plus, mysql.Hex{Value: 1}, 2},
		{1, opcode.Plus, mysql.Bit{Value: 1, Width: 1}, 2},
		{1, opcode.Plus, mysql.Enum{Name: "a", Value: 1}, 2},
		{1, opcode.Plus, mysql.Set{Name: "a", Value: 1}, 2},

		// minus
		{1, opcode.Minus, 1, 0},
		{1, opcode.Minus, uint64(1), 0},
		{1, opcode.Minus, float64(1), 0},
		{1, opcode.Minus, mysql.NewDecimalFromInt(1, 0), 0},
		{uint64(1), opcode.Minus, 1, 0},
		{uint64(1), opcode.Minus, uint64(1), 0},
		{mysql.NewDecimalFromInt(1, 0), opcode.Minus, 1, 0},
		{"1", opcode.Minus, []byte("1"), 0},

		// mul
		{1, opcode.Mul, 1, 1},
		{1, opcode.Mul, uint64(1), 1},
		{1, opcode.Mul, float64(1), 1},
		{1, opcode.Mul, mysql.NewDecimalFromInt(1, 0), 1},
		{uint64(1), opcode.Mul, 1, 1},
		{uint64(1), opcode.Mul, uint64(1), 1},
		{mysql.Time{}, opcode.Mul, 0, 0},
		{mysql.ZeroDuration, opcode.Mul, 0, 0},
		{mysql.Time{Time: time.Now(), Fsp: 0, Type: mysql.TypeDatetime}, opcode.Mul, 0, 0},
		{mysql.Time{Time: time.Now(), Fsp: 6, Type: mysql.TypeDatetime}, opcode.Mul, 0, 0},
		{mysql.Duration{Duration: 100000000, Fsp: 6}, opcode.Mul, 0, 0},

		// div
		{1, opcode.Div, float64(1), 1},
		{1, opcode.Div, float64(0), nil},
		{1, opcode.Div, 2, 0.5},
		{1, opcode.Div, 0, nil},

		// int div
		{1, opcode.IntDiv, 2, 0},
		{1, opcode.IntDiv, uint64(2), 0},
		{1, opcode.IntDiv, 0, nil},
		{1, opcode.IntDiv, uint64(0), nil},
		{uint64(1), opcode.IntDiv, 2, 0},
		{uint64(1), opcode.IntDiv, uint64(2), 0},
		{uint64(1), opcode.IntDiv, 0, nil},
		{uint64(1), opcode.IntDiv, uint64(0), nil},
		{1.0, opcode.IntDiv, 2.0, 0},
		{1.0, opcode.IntDiv, 0, nil},

		// mod
		{10, opcode.Mod, 2, 0},
		{10, opcode.Mod, uint64(2), 0},
		{10, opcode.Mod, 0, nil},
		{10, opcode.Mod, uint64(0), nil},
		{-10, opcode.Mod, uint64(2), 0},
		{uint64(10), opcode.Mod, 2, 0},
		{uint64(10), opcode.Mod, uint64(2), 0},
		{uint64(10), opcode.Mod, 0, nil},
		{uint64(10), opcode.Mod, uint64(0), nil},
		{uint64(10), opcode.Mod, -2, 0},
		{float64(10), opcode.Mod, 2, 0},
		{float64(10), opcode.Mod, 0, nil},
		{mysql.NewDecimalFromInt(10, 0), opcode.Mod, 2, 0},
		{mysql.NewDecimalFromInt(10, 0), opcode.Mod, 0, nil},
	}

	for _, t := range tbl {
		expr := NewBinaryOperation(t.op, Value{t.lhs}, Value{t.rhs})
		v, err := expr.Eval(nil, nil)
		c.Assert(err, IsNil)
		switch v.(type) {
		case nil:
			c.Assert(t.ret, IsNil)
		default:
			// we use float64 as the result type check for all.
			f, err := types.ToFloat64(v)
			c.Assert(err, IsNil)

			r, err := types.ToFloat64(t.ret)
			c.Assert(err, IsNil)
			c.Assert(r, Equals, f)
		}
	}

	// test error
	expr := &BinaryOperation{}
	_, err := expr.evalPlus(1, 1)
	c.Assert(err, NotNil)

	_, err = expr.evalMinus(1, 1)
	c.Assert(err, NotNil)

	_, err = expr.evalMul(1, 1)
	c.Assert(err, NotNil)

	_, err = expr.evalDiv("abc", 1)
	c.Assert(err, NotNil)

	_, err = expr.evalDiv(float64(1), "abc")
	c.Assert(err, NotNil)

	_, err = expr.evalDiv(1, "abc")
	c.Assert(err, NotNil)

	_, err = expr.evalIntDiv("abc", 1)
	c.Assert(err, NotNil)

	_, err = expr.evalIntDiv(1, "abc")
	c.Assert(err, NotNil)

	_, err = expr.evalMod("abc", 1)
	c.Assert(err, NotNil)

	expr.L = Value{1}
	expr.R = Value{1}
	_, err = expr.evalArithmeticOp(nil, nil)
	c.Assert(err, NotNil)

	expr.L = mockExpr{err: errors.New("must error")}
	_, err = expr.evalArithmeticOp(nil, nil)
	c.Assert(err, NotNil)

	expr.L = Value{"abc"}
	expr.R = Value{1}
	_, err = expr.evalArithmeticOp(nil, nil)
	c.Assert(err, NotNil)

	expr.L = Value{[]byte("abc")}
	expr.R = Value{1}
	_, err = expr.evalArithmeticOp(nil, nil)
	c.Assert(err, NotNil)

	expr.L = Value{1}
	expr.R = Value{"abc"}
	_, err = expr.evalArithmeticOp(nil, nil)
	c.Assert(err, NotNil)

	expr.Op = 0
	_, err = expr.Eval(nil, nil)
	c.Assert(err, NotNil)

	expr.L = NewTestRow(1, 2)
	expr.R = Value{nil}
	expr.Op = opcode.Plus

	_, err = expr.Eval(nil, nil)
	c.Assert(err, NotNil)

	expr.Op = opcode.LE
	_, err = expr.Eval(nil, nil)
	c.Assert(err, NotNil)

	expr.R = NewTestRow(1, 2)
	expr.Op = opcode.Plus
	_, err = expr.Eval(nil, nil)
	c.Assert(err, NotNil)

	expr.L = NewTestRow(1, 2)
	expr.R = NewTestRow(1, 2)
	expr.Op = opcode.Plus
	_, err = expr.Eval(nil, nil)
	c.Assert(err, NotNil)
}
Пример #19
0
func (s *testCompareSuite) TestCompare(c *check.C) {
	cmpTbl := []struct {
		lhs interface{}
		rhs interface{}
		ret int // 0, 1, -1
	}{
		{float64(1), float64(1), 0},
		{float64(1), "1", 0},
		{int64(1), int64(1), 0},
		{int64(-1), uint64(1), -1},
		{int64(-1), "-1", 0},
		{uint64(1), uint64(1), 0},
		{uint64(1), int64(-1), 1},
		{uint64(1), "1", 0},
		{mysql.NewDecimalFromInt(1, 0), mysql.NewDecimalFromInt(1, 0), 0},
		{mysql.NewDecimalFromInt(1, 0), "1", 0},
		{mysql.NewDecimalFromInt(1, 0), []byte("1"), 0},
		{"1", "1", 0},
		{"1", int64(-1), 1},
		{"1", float64(2), -1},
		{"1", uint64(1), 0},
		{"1", mysql.NewDecimalFromInt(1, 0), 0},
		{"2011-01-01 11:11:11", mysql.Time{Time: time.Now(), Type: mysql.TypeDatetime, Fsp: 0}, -1},
		{"12:00:00", mysql.ZeroDuration, 1},
		{mysql.ZeroDuration, mysql.ZeroDuration, 0},
		{mysql.Time{Time: time.Now().Add(time.Second * 10), Type: mysql.TypeDatetime, Fsp: 0},
			mysql.Time{Time: time.Now(), Type: mysql.TypeDatetime, Fsp: 0}, 1},

		{nil, 2, -1},
		{nil, nil, 0},

		{false, nil, 1},
		{false, true, -1},
		{true, true, 0},
		{false, false, 0},
		{true, 2, -1},

		{float64(1.23), nil, 1},
		{float64(0.0), float64(3.45), -1},
		{float64(354.23), float64(3.45), 1},
		{float64(3.452), float64(3.452), 0},

		{int(432), nil, 1},
		{-4, int(32), -1},
		{int(4), -32, 1},
		{int(432), int64(12), 1},
		{int(23), int64(128), -1},
		{int(123), int64(123), 0},
		{int(432), int(12), 1},
		{int(23), int(123), -1},
		{int64(133), int(183), -1},

		{uint64(133), uint64(183), -1},
		{uint64(2), int64(-2), 1},
		{uint64(2), int64(1), 1},

		{"", nil, 1},
		{"", "24", -1},
		{"aasf", "4", 1},
		{"", "", 0},

		{[]byte(""), nil, 1},
		{[]byte(""), []byte("sff"), -1},

		{mysql.Time{}, nil, 1},
		{mysql.Time{}, mysql.Time{Time: time.Now(), Type: mysql.TypeDatetime, Fsp: 3}, -1},
		{mysql.Time{Time: time.Now(), Type: mysql.TypeDatetime, Fsp: 3}, "0000-00-00 00:00:00", 1},

		{mysql.Duration{Duration: time.Duration(34), Fsp: 2}, nil, 1},
		{mysql.Duration{Duration: time.Duration(34), Fsp: 2}, mysql.Duration{Duration: time.Duration(29034), Fsp: 2}, -1},
		{mysql.Duration{Duration: time.Duration(3340), Fsp: 2}, mysql.Duration{Duration: time.Duration(34), Fsp: 2}, 1},
		{mysql.Duration{Duration: time.Duration(34), Fsp: 2}, mysql.Duration{Duration: time.Duration(34), Fsp: 2}, 0},

		{[]byte{}, []byte{}, 0},
		{[]byte("abc"), []byte("ab"), 1},
		{[]byte("123"), 1234, -1},
		{[]byte{}, nil, 1},

		{[]interface{}{1, 2, 3}, []interface{}{1, 2, 3}, 0},
		{[]interface{}{1, 3, 3}, []interface{}{1, 2, 3}, 1},
		{[]interface{}{1, 2, 3}, []interface{}{2, 2, 3}, -1},

		{mysql.Hex{Value: 1}, 1, 0},
		{mysql.Hex{Value: 0x4D7953514C}, "MySQL", 0},
		{mysql.Hex{Value: 0}, uint64(10), -1},
		{mysql.Hex{Value: 1}, float64(0), 1},
		{mysql.Hex{Value: 1}, mysql.NewDecimalFromInt(1, 0), 0},
		{mysql.Hex{Value: 1}, mysql.Bit{Value: 0, Width: 1}, 1},
		{mysql.Hex{Value: 1}, mysql.Hex{Value: 1}, 0},

		{mysql.Bit{Value: 1, Width: 1}, 1, 0},
		{mysql.Bit{Value: 0x41, Width: 8}, "A", 0},
		{mysql.Bit{Value: 1, Width: 1}, uint64(10), -1},
		{mysql.Bit{Value: 1, Width: 1}, float64(0), 1},
		{mysql.Bit{Value: 1, Width: 1}, mysql.NewDecimalFromInt(1, 0), 0},
		{mysql.Bit{Value: 1, Width: 1}, mysql.Hex{Value: 2}, -1},
		{mysql.Bit{Value: 1, Width: 1}, mysql.Bit{Value: 1, Width: 1}, 0},

		{mysql.Enum{Name: "a", Value: 1}, 1, 0},
		{mysql.Enum{Name: "a", Value: 1}, "a", 0},
		{mysql.Enum{Name: "a", Value: 1}, uint64(10), -1},
		{mysql.Enum{Name: "a", Value: 1}, float64(0), 1},
		{mysql.Enum{Name: "a", Value: 1}, mysql.NewDecimalFromInt(1, 0), 0},
		{mysql.Enum{Name: "a", Value: 1}, mysql.Hex{Value: 2}, -1},
		{mysql.Enum{Name: "a", Value: 1}, mysql.Bit{Value: 1, Width: 1}, 0},
		{mysql.Enum{Name: "a", Value: 1}, mysql.Hex{Value: 1}, 0},
		{mysql.Enum{Name: "a", Value: 1}, mysql.Enum{Name: "a", Value: 1}, 0},

		{mysql.Set{Name: "a", Value: 1}, 1, 0},
		{mysql.Set{Name: "a", Value: 1}, "a", 0},
		{mysql.Set{Name: "a", Value: 1}, uint64(10), -1},
		{mysql.Set{Name: "a", Value: 1}, float64(0), 1},
		{mysql.Set{Name: "a", Value: 1}, mysql.NewDecimalFromInt(1, 0), 0},
		{mysql.Set{Name: "a", Value: 1}, mysql.Hex{Value: 2}, -1},
		{mysql.Set{Name: "a", Value: 1}, mysql.Bit{Value: 1, Width: 1}, 0},
		{mysql.Set{Name: "a", Value: 1}, mysql.Hex{Value: 1}, 0},
		{mysql.Set{Name: "a", Value: 1}, mysql.Enum{Name: "a", Value: 1}, 0},
		{mysql.Set{Name: "a", Value: 1}, mysql.Set{Name: "a", Value: 1}, 0},
	}

	for i, t := range cmpTbl {
		comment := check.Commentf("%d %v %v", i, t.lhs, t.rhs)
		ret, err := Compare(t.lhs, t.rhs)
		c.Assert(err, check.IsNil)
		c.Assert(ret, check.Equals, t.ret, comment)

		ret, err = Compare(t.rhs, t.lhs)
		c.Assert(err, check.IsNil)
		c.Assert(ret, check.Equals, -t.ret, comment)
	}
}