diff --git a/expression/builtin_time.go b/expression/builtin_time.go index 8518e205b468c..942d918a41afd 100644 --- a/expression/builtin_time.go +++ b/expression/builtin_time.go @@ -4871,7 +4871,7 @@ func (c *timestampFunctionClass) getFunction(ctx sessionctx.Context, args []Expr } isFloat := false switch args[0].GetType().Tp { - case mysql.TypeFloat, mysql.TypeDouble, mysql.TypeNewDecimal: + case mysql.TypeFloat, mysql.TypeDouble, mysql.TypeNewDecimal, mysql.TypeLonglong: isFloat = true } bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETDatetime, evalTps...) diff --git a/expression/integration_test.go b/expression/integration_test.go index d43190ed2e9c2..26ca448fe697b 100755 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -2161,6 +2161,44 @@ func (s *testIntegrationSuite2) TestTimeBuiltin(c *C) { result = tk.MustQuery("select time(\"-- --1\");") result.Check(testkit.Rows("00:00:00")) tk.MustQuery("show warnings;").Check(testkit.Rows("Warning 1292 Truncated incorrect time value: '-- --1'")) + + // fix issue #15185 + result = tk.MustQuery(`select timestamp(11111.1111)`) + result.Check(testkit.Rows("2001-11-11 00:00:00.0000")) + result = tk.MustQuery(`select timestamp(cast(11111.1111 as decimal(60, 5)))`) + result.Check(testkit.Rows("2001-11-11 00:00:00.00000")) + result = tk.MustQuery(`select timestamp(1021121141105.4324)`) + result.Check(testkit.Rows("0102-11-21 14:11:05.4324")) + result = tk.MustQuery(`select timestamp(cast(1021121141105.4324 as decimal(60, 5)))`) + result.Check(testkit.Rows("0102-11-21 14:11:05.43240")) + result = tk.MustQuery(`select timestamp(21121141105.101)`) + result.Check(testkit.Rows("2002-11-21 14:11:05.101")) + result = tk.MustQuery(`select timestamp(cast(21121141105.101 as decimal(60, 5)))`) + result.Check(testkit.Rows("2002-11-21 14:11:05.10100")) + result = tk.MustQuery(`select timestamp(1121141105.799055)`) + result.Check(testkit.Rows("2000-11-21 14:11:05.799055")) + result = tk.MustQuery(`select timestamp(cast(1121141105.799055 as decimal(60, 5)))`) + result.Check(testkit.Rows("2000-11-21 14:11:05.79906")) + result = tk.MustQuery(`select timestamp(121141105.123)`) + result.Check(testkit.Rows("2000-01-21 14:11:05.123")) + result = tk.MustQuery(`select timestamp(cast(121141105.123 as decimal(60, 5)))`) + result.Check(testkit.Rows("2000-01-21 14:11:05.12300")) + result = tk.MustQuery(`select timestamp(1141105)`) + result.Check(testkit.Rows("0114-11-05 00:00:00")) + result = tk.MustQuery(`select timestamp(cast(1141105 as decimal(60, 5)))`) + result.Check(testkit.Rows("0114-11-05 00:00:00.00000")) + result = tk.MustQuery(`select timestamp(41105.11)`) + result.Check(testkit.Rows("2004-11-05 00:00:00.00")) + result = tk.MustQuery(`select timestamp(cast(41105.11 as decimal(60, 5)))`) + result.Check(testkit.Rows("2004-11-05 00:00:00.00000")) + result = tk.MustQuery(`select timestamp(1105.3)`) + result.Check(testkit.Rows("2000-11-05 00:00:00.0")) + result = tk.MustQuery(`select timestamp(cast(1105.3 as decimal(60, 5)))`) + result.Check(testkit.Rows("2000-11-05 00:00:00.00000")) + result = tk.MustQuery(`select timestamp(105)`) + result.Check(testkit.Rows("2000-01-05 00:00:00")) + result = tk.MustQuery(`select timestamp(cast(105 as decimal(60, 5)))`) + result.Check(testkit.Rows("2000-01-05 00:00:00.00000")) } func (s *testIntegrationSuite) TestOpBuiltin(c *C) { diff --git a/types/time.go b/types/time.go index 1be95d49b5a73..6ea4aceeaca42 100644 --- a/types/time.go +++ b/types/time.go @@ -816,6 +816,28 @@ func parseDatetime(sc *stmtctx.StatementContext, str string, fsp int8, isFloat b switch len(seps) { case 1: l := len(seps[0]) + // Values specified as numbers + if isFloat { + numOfTime, err := StrToInt(sc, seps[0], false) + if err != nil { + return ZeroDatetime, errors.Trace(ErrWrongValue.GenWithStackByArgs(DateTimeStr, str)) + } + + dateTime, err := ParseDatetimeFromNum(sc, numOfTime) + if err != nil { + return ZeroDatetime, errors.Trace(ErrWrongValue.GenWithStackByArgs(DateTimeStr, str)) + } + + year, month, day, hour, minute, second = + dateTime.Year(), dateTime.Month(), dateTime.Day(), dateTime.Hour(), dateTime.Minute(), dateTime.Second() + if l >= 9 && l <= 14 { + hhmmss = true + } + + break + } + + // Values specified as strings switch l { case 14: // No delimiter. // YYYYMMDDHHMMSS @@ -1613,11 +1635,6 @@ func parseDateTimeFromNum(sc *stmtctx.StatementContext, num int64) (Time, error) return getTime(sc, num, t.Type()) } - // Check YYYYMMDD. - if num < 10000101 { - return t, errors.Trace(ErrWrongValue.GenWithStackByArgs(TimeStr, strconv.FormatInt(num, 10))) - } - // Adjust hour/min/second. if num <= 99991231 { num = num * 1000000 diff --git a/types/time_test.go b/types/time_test.go index 063a7fdf05b18..5b97af3827543 100644 --- a/types/time_test.go +++ b/types/time_test.go @@ -614,7 +614,7 @@ func (s *testTimeSuite) TestParseTimeFromNum(c *C) { {2010101011, true, types.ZeroDatetimeStr, true, types.ZeroDatetimeStr, true, types.ZeroDateStr}, {201010101, false, "2000-02-01 01:01:01", false, "2000-02-01 01:01:01", false, "2000-02-01"}, {20101010, false, "2010-10-10 00:00:00", false, "2010-10-10 00:00:00", false, "2010-10-10"}, - {2010101, true, types.ZeroDatetimeStr, true, types.ZeroDatetimeStr, true, types.ZeroDateStr}, + {2010101, false, "0201-01-01 00:00:00", true, types.ZeroDatetimeStr, false, "0201-01-01"}, {201010, false, "2020-10-10 00:00:00", false, "2020-10-10 00:00:00", false, "2020-10-10"}, {20101, false, "2002-01-01 00:00:00", false, "2002-01-01 00:00:00", false, "2002-01-01"}, {2010, true, types.ZeroDatetimeStr, true, types.ZeroDatetimeStr, true, types.ZeroDateStr}, @@ -747,6 +747,39 @@ func (s *testTimeSuite) TestToNumber(c *C) { } } +func (s *testTimeSuite) TestParseTimeFromFloatString(c *C) { + sc := mock.NewContext().GetSessionVars().StmtCtx + sc.IgnoreZeroInDate = true + defer testleak.AfterTest(c)() + table := []struct { + Input string + Fsp int8 + ExpectError bool + Expect string + }{ + {"20170118.123", 3, false, "2017-01-18 00:00:00.000"}, + {"121231113045.123345", 6, false, "2012-12-31 11:30:45.123345"}, + {"20121231113045.123345", 6, false, "2012-12-31 11:30:45.123345"}, + {"121231113045.9999999", 6, false, "2012-12-31 11:30:46.000000"}, + {"170105084059.575601", 6, false, "2017-01-05 08:40:59.575601"}, + {"201705051315111.22", 2, true, "0000-00-00 00:00:00.00"}, + {"2011110859.1111", 4, true, "0000-00-00 00:00:00.0000"}, + {"2011110859.1111", 4, true, "0000-00-00 00:00:00.0000"}, + {"191203081.1111", 4, true, "0000-00-00 00:00:00.0000"}, + {"43128.121105", 6, true, "0000-00-00 00:00:00.000000"}, + } + + for _, test := range table { + t, err := types.ParseTimeFromFloatString(sc, test.Input, mysql.TypeDatetime, test.Fsp) + if test.ExpectError { + c.Assert(err, NotNil) + } else { + c.Assert(err, IsNil) + c.Assert(t.String(), Equals, test.Expect) + } + } +} + func (s *testTimeSuite) TestParseFrac(c *C) { defer testleak.AfterTest(c)() tbl := []struct { @@ -1027,7 +1060,7 @@ func (s *testTimeSuite) TestParseDateFormat(c *C) { } } -func (s *testTimeSuite) TestTamestampDiff(c *C) { +func (s *testTimeSuite) TestTimestampDiff(c *C) { tests := []struct { unit string t1 types.CoreTime