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 } }
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 } }
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 }
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 } }
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 }
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 }
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 }
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 } }
// 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") } }