diff --git a/executor/executor_test.go b/executor/executor_test.go index 3c1b25e140a92..b6b93338cd432 100644 --- a/executor/executor_test.go +++ b/executor/executor_test.go @@ -4601,3 +4601,19 @@ func (s *testSuite) TestPrepareLoadData(c *C) { tk := testkit.NewTestKit(c, s.store) tk.MustGetErrCode(`prepare stmt from "load data local infile '/tmp/load_data_test.csv' into table test";`, mysql.ErrUnsupportedPs) } + +func (s *testSuite) TestIssue22231(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t_issue_22231") + tk.MustExec("create table t_issue_22231(a datetime)") + tk.MustExec("insert into t_issue_22231 values('2020--05-20 01:22:12')") + tk.MustQuery("select * from t_issue_22231 where a >= '2020-05-13 00:00:00 00:00:00' and a <= '2020-05-28 23:59:59 00:00:00'").Check(testkit.Rows("2020-05-20 01:22:12")) + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1292 Truncated incorrect datetime value: '2020-05-13 00:00:00 00:00:00'", "Warning 1292 Truncated incorrect datetime value: '2020-05-28 23:59:59 00:00:00'")) + + tk.MustQuery("select cast('2020-10-22 10:31-10:12' as datetime)").Check(testkit.Rows("2020-10-22 10:31:10")) + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1292 Truncated incorrect datetime value: '2020-10-22 10:31-10:12'")) + tk.MustQuery("select cast('2020-05-28 23:59:59 00:00:00' as datetime)").Check(testkit.Rows("2020-05-28 23:59:59")) + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1292 Truncated incorrect datetime value: '2020-05-28 23:59:59 00:00:00'")) + tk.MustExec("drop table if exists t_issue_22231") +} diff --git a/types/time.go b/types/time.go index 32a181610c258..6e564815ff67d 100644 --- a/types/time.go +++ b/types/time.go @@ -643,8 +643,8 @@ func ParseDateFormat(format string) []string { return nil } - // Date format must start and end with number. - if !isDigit(format[0]) || !isDigit(format[len(format)-1]) { + // Date format must start with number. + if !isDigit(format[0]) { return nil } @@ -690,7 +690,14 @@ func isValidSeparator(c byte, prevParts int) bool { return true } - return prevParts == 2 && (c == ' ' || c == 'T') + if prevParts == 2 && (c == ' ' || c == 'T') { + return true + } + + if prevParts > 4 && !isDigit(c) { + return true + } + return false } // See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-literals.html. @@ -718,6 +725,8 @@ func parseDatetime(sc *stmtctx.StatementContext, str string, fsp int, isFloat bo seps, fracStr := splitDateTime(str) var truncatedOrIncorrect bool switch len(seps) { + case 0: + return ZeroDatetime, errors.Trace(ErrWrongValue.GenWithStackByArgs(DateTimeStr, str)) case 1: l := len(seps[0]) // Values specified as numbers @@ -808,6 +817,7 @@ func parseDatetime(sc *stmtctx.StatementContext, str string, fsp int, isFloat bo err = nil } case 2: +<<<<<<< HEAD // YYYY-MM is not valid if len(fracStr) == 0 { return ZeroDatetime, errors.Trace(ErrIncorrectDatetimeValue.GenWithStackByArgs(str)) @@ -816,6 +826,9 @@ func parseDatetime(sc *stmtctx.StatementContext, str string, fsp int, isFloat bo // YYYY-MM.DD, DD is treat as fracStr err = scanTimeArgs(append(seps, fracStr), &year, &month, &day) fracStr = "" +======= + return ZeroDatetime, errors.Trace(ErrWrongValue.GenWithStackByArgs(DateTimeStr, str)) +>>>>>>> d1d5cc433... time: fix parse datetime won't truncate the reluctant string (#22232) case 3: // YYYY-MM-DD err = scanTimeArgs(seps, &year, &month, &day) @@ -831,7 +844,18 @@ func parseDatetime(sc *stmtctx.StatementContext, str string, fsp int, isFloat bo err = scanTimeArgs(seps, &year, &month, &day, &hour, &minute, &second) hhmmss = true default: +<<<<<<< HEAD return ZeroDatetime, errors.Trace(ErrIncorrectDatetimeValue.GenWithStackByArgs(str)) +======= + // For case like `2020-05-28 23:59:59 00:00:00`, the seps should be > 6, the reluctant parts should be truncated. + seps = seps[:6] + // YYYY-MM-DD HH-MM-SS + if sc != nil { + sc.AppendWarning(ErrTruncatedWrongVal.GenWithStackByArgs("datetime", str)) + } + err = scanTimeArgs(seps, &year, &month, &day, &hour, &minute, &second) + hhmmss = true +>>>>>>> d1d5cc433... time: fix parse datetime won't truncate the reluctant string (#22232) } if err != nil { return ZeroDatetime, errors.Trace(err) diff --git a/types/time_test.go b/types/time_test.go index 6cd776d20d63d..6466487172e56 100644 --- a/types/time_test.go +++ b/types/time_test.go @@ -71,6 +71,15 @@ func (s *testTimeSuite) TestDateTime(c *C) { {"2018.01.01 00:00:00", "2018-01-01 00:00:00"}, {"2018/01/01-00:00:00", "2018-01-01 00:00:00"}, {"4710072", "2047-10-07 02:00:00"}, + {"2016-06-01 00:00:00 00:00:00", "2016-06-01 00:00:00"}, + {"2020-06-01 00:00:00ads!,?*da;dsx", "2020-06-01 00:00:00"}, + + // For issue 22231 + {"2020-05-28 23:59:59 00:00:00", "2020-05-28 23:59:59"}, + {"2020-05-28 23:59:59-00:00:00", "2020-05-28 23:59:59"}, + {"2020-05-28 23:59:59T T00:00:00", "2020-05-28 23:59:59"}, + {"2020-10-22 10:31-10:12", "2020-10-22 10:31:10"}, + {"2018.01.01 01:00:00", "2018-01-01 01:00:00"}, } for _, test := range table { @@ -119,11 +128,21 @@ func (s *testTimeSuite) TestDateTime(c *C) { "20170118.999", "2018-01", "2018.01", +<<<<<<< HEAD +======= + "20170118-12:34", + "20170118-1234", + "170118-1234", + "170118-12", + "1710-10", + "1710-1000", +>>>>>>> d1d5cc433... time: fix parse datetime won't truncate the reluctant string (#22232) } for _, test := range errTable { _, err := types.ParseDatetime(sc, test) - c.Assert(err, NotNil) + c.Assert(err != nil || sc.WarningCount() > 0, Equals, true) + sc.SetWarnings(nil) } } @@ -1038,7 +1057,7 @@ func (s *testTimeSuite) TestParseDateFormat(c *C) { {"2011-11-11 10:10:10", []string{"2011", "11", "11", "10", "10", "10"}}, {"xx2011-11-11 10:10:10", nil}, {"T10:10:10", nil}, - {"2011-11-11x", nil}, + {"2011-11-11x", []string{"2011", "11", "11x"}}, {"xxx 10:10:10", nil}, }