diff --git a/expression/builtin_time.go b/expression/builtin_time.go index 96455e57190be..3af2bf4c36987 100644 --- a/expression/builtin_time.go +++ b/expression/builtin_time.go @@ -1573,7 +1573,6 @@ func (c *fromUnixTimeFunctionClass) getFunction(ctx sessionctx.Context, args []E argTps = append(argTps, types.ETString) } - _, isArg0Con := args[0].(*Constant) isArg0Str := args[0].GetType().EvalType() == types.ETString bf := newBaseBuiltinFuncWithTp(ctx, args, retTp, argTps...) @@ -1583,19 +1582,10 @@ func (c *fromUnixTimeFunctionClass) getFunction(ctx sessionctx.Context, args []E } // Calculate the time fsp. - switch { - case isArg0Str: - bf.tp.Decimal = int(types.MaxFsp) - case isArg0Con: - arg0, arg0IsNull, err0 := args[0].EvalDecimal(ctx, chunk.Row{}) - if err0 != nil { - return nil, err0 - } - - bf.tp.Decimal = int(types.MaxFsp) - if !arg0IsNull { - fsp := int(arg0.GetDigitsFrac()) - bf.tp.Decimal = mathutil.Min(fsp, int(types.MaxFsp)) + bf.tp.Decimal = int(types.MaxFsp) + if !isArg0Str { + if args[0].GetType().Decimal != types.UnspecifiedLength { + bf.tp.Decimal = mathutil.Min(bf.tp.Decimal, args[0].GetType().Decimal) } } @@ -1638,14 +1628,9 @@ func evalFromUnixTime(ctx sessionctx.Context, fsp int, row chunk.Row, arg Expres if err != nil && !terror.ErrorEqual(err, types.ErrTruncated) { return res, true, err } - fracDigitsNumber := int(unixTimeStamp.GetDigitsFrac()) if fsp < 0 { fsp = types.MaxFsp } - fsp = mathutil.Max(fracDigitsNumber, fsp) - if fsp > types.MaxFsp { - fsp = types.MaxFsp - } sc := ctx.GetSessionVars().StmtCtx tmp := time.Unix(integralPart, fractionalPart).In(sc.TimeZone) diff --git a/expression/builtin_time_test.go b/expression/builtin_time_test.go index ed7e784cc231a..347c69b8824ad 100644 --- a/expression/builtin_time_test.go +++ b/expression/builtin_time_test.go @@ -1150,16 +1150,16 @@ func (s *testEvaluatorSuite) TestFromUnixTime(c *C) { fractionalPart int64 decimal float64 format string - ansLen int + expect string }{ - {false, 1451606400, 0, 0, "", 19}, - {true, 1451606400, 123456000, 1451606400.123456, "", 26}, - {true, 1451606400, 999999000, 1451606400.999999, "", 26}, - {true, 1451606400, 999999900, 1451606400.9999999, "", 19}, - {false, 1451606400, 0, 0, `%Y %D %M %h:%i:%s %x`, 19}, - {true, 1451606400, 123456000, 1451606400.123456, `%Y %D %M %h:%i:%s %x`, 26}, - {true, 1451606400, 999999000, 1451606400.999999, `%Y %D %M %h:%i:%s %x`, 26}, - {true, 1451606400, 999999900, 1451606400.9999999, `%Y %D %M %h:%i:%s %x`, 19}, + {false, 1451606400, 0, 0, "", "2016-01-01 08:00:00"}, + {true, 1451606400, 123456000, 1451606400.123456, "", "2016-01-01 08:00:00.123456"}, + {true, 1451606400, 999999000, 1451606400.999999, "", "2016-01-01 08:00:00.999999"}, + {true, 1451606400, 999999900, 1451606400.9999999, "", "2016-01-01 08:00:01.000000"}, + {false, 1451606400, 0, 0, `%Y %D %M %h:%i:%s %x`, "2016-01-01 08:00:00"}, + {true, 1451606400, 123456000, 1451606400.123456, `%Y %D %M %h:%i:%s %x`, "2016-01-01 08:00:00.123456"}, + {true, 1451606400, 999999000, 1451606400.999999, `%Y %D %M %h:%i:%s %x`, "2016-01-01 08:00:00.999999"}, + {true, 1451606400, 999999900, 1451606400.9999999, `%Y %D %M %h:%i:%s %x`, "2016-01-01 08:00:01.000000"}, } sc := s.ctx.GetSessionVars().StmtCtx originTZ := sc.TimeZone @@ -1176,23 +1176,32 @@ func (s *testEvaluatorSuite) TestFromUnixTime(c *C) { timestamp.SetFloat64(t.decimal) } // result of from_unixtime() is dependent on specific time zone. - unixTime := time.Unix(t.integralPart, t.fractionalPart).Round(time.Microsecond).String()[:t.ansLen] if len(t.format) == 0 { - f, err := fc.getFunction(s.ctx, s.datumsToConstants([]types.Datum{timestamp})) + constants := s.datumsToConstants([]types.Datum{timestamp}) + if !t.isDecimal { + constants[0].GetType().Decimal = 0 + } + + f, err := fc.getFunction(s.ctx, constants) c.Assert(err, IsNil) + v, err := evalBuiltinFunc(f, chunk.Row{}) c.Assert(err, IsNil) ans := v.GetMysqlTime() - c.Assert(ans.String(), Equals, unixTime) + c.Assert(ans.String(), Equals, t.expect, Commentf("%+v", t)) } else { format := types.NewStringDatum(t.format) - f, err := fc.getFunction(s.ctx, s.datumsToConstants([]types.Datum{timestamp, format})) + constants := s.datumsToConstants([]types.Datum{timestamp, format}) + if !t.isDecimal { + constants[0].GetType().Decimal = 0 + } + f, err := fc.getFunction(s.ctx, constants) c.Assert(err, IsNil) v, err := evalBuiltinFunc(f, chunk.Row{}) c.Assert(err, IsNil) - result, err := builtinDateFormat(s.ctx, []types.Datum{types.NewStringDatum(unixTime), format}) + result, err := builtinDateFormat(s.ctx, []types.Datum{types.NewStringDatum(t.expect), format}) c.Assert(err, IsNil) - c.Assert(v.GetString(), Equals, result.GetString()) + c.Assert(v.GetString(), Equals, result.GetString(), Commentf("%+v", t)) } } diff --git a/expression/integration_test.go b/expression/integration_test.go index 13c0b9932ae5e..61fcfe5871fb0 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -2474,6 +2474,14 @@ func (s *testIntegrationSuite) TestBuiltin(c *C) { result = tk.MustQuery("select from_unixtime(1451606400)") unixTime := time.Unix(1451606400, 0).String()[:19] result.Check(testkit.Rows(unixTime)) + result = tk.MustQuery("select from_unixtime(14516064000/10)") + result.Check(testkit.Rows("2016-01-01 08:00:00.0000")) + result = tk.MustQuery("select from_unixtime('14516064000'/10)") + result.Check(testkit.Rows("2016-01-01 08:00:00.000000")) + result = tk.MustQuery("select from_unixtime(cast(1451606400 as DECIMAL))") + result.Check(testkit.Rows("2016-01-01 08:00:00")) + result = tk.MustQuery("select from_unixtime(cast(1451606400 as DECIMAL(65,1)))") + result.Check(testkit.Rows("2016-01-01 08:00:00.0")) result = tk.MustQuery("select from_unixtime(1451606400.123456)") unixTime = time.Unix(1451606400, 123456000).String()[:26] result.Check(testkit.Rows(unixTime)) @@ -2485,6 +2493,14 @@ func (s *testIntegrationSuite) TestBuiltin(c *C) { result.Check(testkit.Rows(unixTime)) result = tk.MustQuery("select from_unixtime(1511247196661)") result.Check(testkit.Rows("")) + result = tk.MustQuery("select from_unixtime('1451606400.123');") + result.Check(testkit.Rows("2016-01-01 08:00:00.123000")) + + tk.MustExec("drop table if exists t;") + tk.MustExec("create table t(a int);") + tk.MustExec("insert into t value(1451606400);") + result = tk.MustQuery("select from_unixtime(a) from t;") + result.Check(testkit.Rows("2016-01-01 08:00:00")) // test strcmp result = tk.MustQuery("select strcmp('abc', 'def')")