From 097c3d50c84e16fcb37a4b7ed85be2a17b591891 Mon Sep 17 00:00:00 2001 From: WangXiangUSTC Date: Mon, 1 Apr 2019 12:51:35 +0800 Subject: [PATCH 1/2] types: fix incorrect time fraction parsing method --- types/time.go | 40 ++++++++++++++++++++++++++++++++++++---- types/time_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/types/time.go b/types/time.go index d626c08018fc3..6ad62302e5e9c 100644 --- a/types/time.go +++ b/types/time.go @@ -443,7 +443,13 @@ func (t Time) RoundFrac(sc *stmtctx.StatementContext, fsp int) (Time, error) { // GetFsp gets the fsp of a string. func GetFsp(s string) (fsp int) { - fsp = len(s) - strings.LastIndex(s, ".") - 1 + index := GetFracIndex(s) + if index < 0 { + fsp = 0 + } else { + fsp = len(s) - index - 1 + } + if fsp == len(s) { fsp = 0 } else if fsp > 6 { @@ -452,6 +458,22 @@ func GetFsp(s string) (fsp int) { return } +// GetFracIndex finds the last '.' for get fracStr, index = -1 means fracStr not found. +// but for format like '2019.01.01 00:00:00', the index should be -1. +func GetFracIndex(s string) (index int) { + index = -1 + for i := len(s) - 1; i >= 0; i-- { + if unicode.IsPunct(rune(s[i])) { + if s[i] == '.' { + index = i + } + break + } + } + + return index +} + // RoundFrac rounds fractional seconds precision with new fsp and returns a new one. // We will use the “round half up” rule, e.g, >= 0.5 -> 1, < 0.5 -> 0, // so 2011:11:11 10:10:10.888888 round 0 -> 2011:11:11 10:10:11 @@ -640,9 +662,10 @@ func ParseDateFormat(format string) []string { // See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-literals.html. // The only delimiter recognized between a date and time part and a fractional seconds part is the decimal point. func splitDateTime(format string) (seps []string, fracStr string) { - if i := strings.LastIndex(format, "."); i > 0 { - fracStr = strings.TrimSpace(format[i+1:]) - format = format[:i] + index := GetFracIndex(format) + if index > 0 { + fracStr = format[index+1:] + format = format[:index] } seps = ParseDateFormat(format) @@ -727,6 +750,15 @@ func parseDatetime(sc *stmtctx.StatementContext, str string, fsp int, isFloat bo sc.AppendWarning(ErrTruncatedWrongValue.GenWithStackByArgs("datetime", str)) err = nil } + case 2: + // YYYY-MM is not valid + if len(fracStr) == 0 { + return ZeroDatetime, errors.Trace(ErrIncorrectDatetimeValue.GenWithStackByArgs(str)) + } + + // YYYY-MM.DD, DD is treat as fracStr + err = scanTimeArgs(append(seps, fracStr), &year, &month, &day) + fracStr = "" case 3: // YYYY-MM-DD err = scanTimeArgs(seps, &year, &month, &day) diff --git a/types/time_test.go b/types/time_test.go index 65175757740f6..4d47212be182c 100644 --- a/types/time_test.go +++ b/types/time_test.go @@ -62,6 +62,9 @@ func (s *testTimeSuite) TestDateTime(c *C) { {"170102036", "2017-01-02 03:06:00"}, {"170102039.", "2017-01-02 03:09:00"}, {"170102037.11", "2017-01-02 03:07:11.00"}, + {"2018-01-01 18", "2018-01-01 18:00:00"}, + {"2018/01/01-00:00:00", "2018-01-01 00:00:00"}, + {"2018.01.01 00:00:00", "2018-01-01 00:00:00"}, } for _, test := range table { @@ -83,6 +86,9 @@ func (s *testTimeSuite) TestDateTime(c *C) { {"2017-01-05 23:59:59.575601", 0, "2017-01-06 00:00:00"}, {"2017-01-31 23:59:59.575601", 0, "2017-02-01 00:00:00"}, {"2017-00-05 23:59:58.575601", 3, "2017-00-05 23:59:58.576"}, + {"2017.00.05 23:59:58.575601", 3, "2017-00-05 23:59:58.576"}, + {"2017/00/05 23:59:58.575601", 3, "2017-00-05 23:59:58.576"}, + {"2017/00/05-23:59:58.575601", 3, "2017-00-05 23:59:58.576"}, } for _, test := range fspTbl { @@ -103,6 +109,8 @@ func (s *testTimeSuite) TestDateTime(c *C) { "1000-09-31 00:00:00", "1001-02-29 00:00:00", "20170118.999", + "2018-01", + "2018.01", } for _, test := range errTable { @@ -152,6 +160,8 @@ func (s *testTimeSuite) TestDate(c *C) { {"2015-06-01 12:12:12", "2015-06-01"}, {"0001-01-01 00:00:00", "0001-01-01"}, {"0001-01-01", "0001-01-01"}, + {"2019.01.01", "2019-01-01"}, + {"2019/01/01", "2019-01-01"}, } for _, test := range table { @@ -162,6 +172,7 @@ func (s *testTimeSuite) TestDate(c *C) { errTable := []string{ "0121231", + "2019.01", } for _, test := range errTable { @@ -1307,3 +1318,18 @@ func (s *testTimeSuite) TestGetFormatType(c *C) { c.Assert(isDuration, Equals, true) c.Assert(isDate, Equals, false) } + +func (s *testTimeSuite) TestgetFracIndex(c *C) { + testCases := []struct { + str string + expectIndex int + }{ + {"2019.01.01 00:00:00", -1}, + {"2019.01.01 00:00:00.1", 19}, + {"12345.6", 5}, + } + for _, testCase := range testCases { + index := types.GetFracIndex(testCase.str) + c.Assert(index, Equals, testCase.expectIndex) + } +} From 5f1bc72554f74f02c9c90c2d5b017b6782cfa8fa Mon Sep 17 00:00:00 2001 From: WangXiangUSTC Date: Tue, 2 Apr 2019 18:48:01 +0800 Subject: [PATCH 2/2] update test --- types/time_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/time_test.go b/types/time_test.go index 4d47212be182c..9021c61614a36 100644 --- a/types/time_test.go +++ b/types/time_test.go @@ -62,7 +62,7 @@ func (s *testTimeSuite) TestDateTime(c *C) { {"170102036", "2017-01-02 03:06:00"}, {"170102039.", "2017-01-02 03:09:00"}, {"170102037.11", "2017-01-02 03:07:11.00"}, - {"2018-01-01 18", "2018-01-01 18:00:00"}, + {"2018.01.01", "2018-01-01 00:00:00.00"}, {"2018/01/01-00:00:00", "2018-01-01 00:00:00"}, {"2018.01.01 00:00:00", "2018-01-01 00:00:00"}, }