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(e.sc) 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(e.sc) 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(types.MyDecimal) var zero types.MyDecimal types.DecimalSub(&zero, aDatum.GetMysqlDuration().ToNumber(), to) u.SetMysqlDecimal(to) case types.KindMysqlTime: dec := aDatum.GetMysqlTime().ToNumber() var zero, to types.MyDecimal types.DecimalSub(&zero, dec, &to) u.SetMysqlDecimal(&to) case types.KindString, types.KindBytes: f, err := types.StrToFloat(e.sc, aDatum.GetString()) e.err = errors.Trace(err) u.SetFloat64(-f) case types.KindMysqlDecimal: dec := aDatum.GetMysqlDecimal() var zero, to types.MyDecimal types.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 }
// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_from-unixtime func builtinFromUnixTime(args []types.Datum, ctx context.Context) (d types.Datum, err error) { sc := ctx.GetSessionVars().StmtCtx unixTimeStamp, err := args[0].ToDecimal(sc) if err != nil { return d, errors.Trace(err) } // 0 <= unixTimeStamp <= INT32_MAX if unixTimeStamp.IsNegative() { return } integralPart, err := unixTimeStamp.ToInt() if err == types.ErrTruncated { err = nil } if err != nil { return d, errors.Trace(err) } if integralPart > int64(math.MaxInt32) { return } // Split the integral part and fractional part of a decimal timestamp. // e.g. for timestamp 12345.678, // first get the integral part 12345, // then (12345.678 - 12345) * (10^9) to get the decimal part and convert it to nanosecond precision. integerDecimalTp := new(types.MyDecimal).FromInt(integralPart) fracDecimalTp := new(types.MyDecimal) err = types.DecimalSub(unixTimeStamp, integerDecimalTp, fracDecimalTp) if err != nil { return d, errors.Trace(err) } nano := new(types.MyDecimal).FromInt(int64(time.Second)) x := new(types.MyDecimal) err = types.DecimalMul(fracDecimalTp, nano, x) if err != nil { return d, errors.Trace(err) } fractionalPart, err := x.ToInt() // here fractionalPart is result multiplying the original fractional part by 10^9. if err == types.ErrTruncated { err = nil } if err != nil { return d, errors.Trace(err) } _, fracDigitsNumber := unixTimeStamp.PrecisionAndFrac() fsp := fracDigitsNumber if fracDigitsNumber > types.MaxFsp { fsp = types.MaxFsp } tr, err := types.RoundFrac(time.Unix(integralPart, fractionalPart), fsp) if err != nil { return d, errors.Trace(err) } t := types.Time{ Time: types.FromGoTime(tr), Type: mysql.TypeDatetime, Fsp: fsp, } if args[0].Kind() == types.KindString { // Keep consistent with MySQL. t.Fsp = types.MaxFsp } d.SetMysqlTime(t) if len(args) == 1 { return } return builtinDateFormat([]types.Datum{d, args[1]}, ctx) }