Exemple #1
0
func (o *BinaryOperation) coerceArithmetic(a interface{}) (interface{}, error) {
	switch x := a.(type) {
	case string:
		// MySQL will convert string to float for arithmetic operation
		f, err := types.StrToFloat(x)
		if err != nil {
			return nil, err
		}
		return f, err
	case mysql.Time:
		// TODO: if time has no precision, return int64
		return x.ToNumber(), nil
	case mysql.Duration:
		// TODO: if duration has no precision, return int64
		return x.ToNumber(), nil
	case []byte:
		// []byte is the same as string, converted to float for arithmetic operator.
		f, err := types.StrToFloat(string(x))
		if err != nil {
			return nil, err
		}
		return f, err
	default:
		return x, nil
	}
}
Exemple #2
0
func coerceArithmetic(a interface{}) (interface{}, error) {
	switch x := a.(type) {
	case string:
		// MySQL will convert string to float for arithmetic operation
		f, err := types.StrToFloat(x)
		if err != nil {
			return nil, errors.Trace(err)
		}
		return f, errors.Trace(err)
	case mysql.Time:
		// if time has no precision, return int64
		v := x.ToNumber()
		if x.Fsp == 0 {
			return v.IntPart(), nil
		}
		return v, nil
	case mysql.Duration:
		// if duration has no precision, return int64
		v := x.ToNumber()
		if x.Fsp == 0 {
			return v.IntPart(), nil
		}
		return v, nil
	case []byte:
		// []byte is the same as string, converted to float for arithmetic operator.
		f, err := types.StrToFloat(string(x))
		if err != nil {
			return nil, errors.Trace(err)
		}
		return f, errors.Trace(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 x, nil
	}
}
Exemple #3
0
func compareFloatString(a float64, s string) (int, error) {
	// MySQL will convert string to a float point value
	// MySQL use a very loose conversation, e.g, 123.abc -> 123
	// we should do a trade off whether supporting this feature or using a strict mode
	// now we use a strict mode
	b, err := types.StrToFloat(s)
	if err != nil {
		return 0, err
	}
	return types.CompareFloat64(a, b), nil
}
Exemple #4
0
func coerceArithmetic(a types.Datum) (d types.Datum, err error) {
	switch a.Kind() {
	case types.KindString, types.KindBytes:
		// MySQL will convert string to float for arithmetic operation
		f, err := types.StrToFloat(a.GetString())
		if err != nil {
			return d, errors.Trace(err)
		}
		d.SetFloat64(f)
		return d, errors.Trace(err)
	case types.KindMysqlTime:
		// if time has no precision, return int64
		t := a.GetMysqlTime()
		de := t.ToNumber()
		if t.Fsp == 0 {
			d.SetInt64(de.IntPart())
			return d, nil
		}
		d.SetMysqlDecimal(de)
		return d, nil
	case types.KindMysqlDuration:
		// if duration has no precision, return int64
		du := a.GetMysqlDuration()
		de := du.ToNumber()
		if du.Fsp == 0 {
			d.SetInt64(de.IntPart())
			return d, nil
		}
		d.SetMysqlDecimal(de)
		return d, nil
	case types.KindMysqlHex:
		d.SetFloat64(a.GetMysqlHex().ToNumber())
		return d, nil
	case types.KindMysqlBit:
		d.SetFloat64(a.GetMysqlBit().ToNumber())
		return d, nil
	case types.KindMysqlEnum:
		d.SetFloat64(a.GetMysqlEnum().ToNumber())
		return d, nil
	case types.KindMysqlSet:
		d.SetFloat64(a.GetMysqlSet().ToNumber())
		return d, nil
	default:
		return a, nil
	}
}
Exemple #5
0
func (c *Col) normalizeIntegerFromString(v string) (val int64, errCode int) {
	v = strings.Trim(v, " \t\r\n")
	if c.Tp == mysql.TypeYear {
		yyal, err := mysql.ParseYear(v)
		if err != nil {
			errCode = errCodeOverflowUpper
		}
		val = int64(yyal)
	} else {
		fval, ferr := types.StrToFloat(v)
		if ferr != nil {
			errCode = errCodeType
		} else {
			val, errCode = c.normalizeIntegerFromFloat(fval)
		}
	}
	return
}
Exemple #6
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.IsNull() {
		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:
			var to = new(mysql.MyDecimal)
			var zero mysql.MyDecimal
			mysql.DecimalSub(&zero, aDatum.GetMysqlDuration().ToNumber(), to)
			u.SetMysqlDecimal(to)
		case types.KindMysqlTime:
			dec := aDatum.GetMysqlTime().ToNumber()
			var zero, to mysql.MyDecimal
			mysql.DecimalSub(&zero, dec, &to)
			u.SetMysqlDecimal(&to)
		case types.KindString, types.KindBytes:
			f, err := types.StrToFloat(aDatum.GetString())
			e.err = errors.Trace(err)
			u.SetFloat64(-f)
		case types.KindMysqlDecimal:
			dec := aDatum.GetMysqlDecimal()
			var zero, to mysql.MyDecimal
			mysql.DecimalSub(&zero, dec, &to)
			u.SetMysqlDecimal(&to)
		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
}
Exemple #7
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
}
Exemple #8
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
	}
}
Exemple #9
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)
		if a == nil {
			return
		}

		n, err := types.ToBool(a)
		if err != nil {
			return types.UndOp(a, op)
		} else if n == 0 {
			return int8(1), nil
		}
		return int8(0), nil
	case opcode.BitNeg:
		a := Eval(u.V, ctx, args)
		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)

		switch x := a.(type) {
		case nil:
			return nil, 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
		default:
			return types.UndOp(a, op)
		}
	case opcode.Minus:
		a := Eval(u.V, ctx, args)

		switch x := a.(type) {
		case nil:
			return nil, 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
		default:
			return types.UndOp(a, op)
		}
	default:
		panic("should never happen")
	}
}