Skip to content

Commit

Permalink
types: fix incorrect time fraction parsing method (#10001)
Browse files Browse the repository at this point in the history
  • Loading branch information
WangXiangUSTC authored and zz-jason committed Apr 4, 2019
1 parent 9b4940b commit e2a2cc4
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 4 deletions.
40 changes: 36 additions & 4 deletions types/time.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
26 changes: 26 additions & 0 deletions types/time_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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", "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"},
}

for _, test := range table {
Expand All @@ -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 {
Expand All @@ -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 {
Expand Down Expand Up @@ -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 {
Expand All @@ -162,6 +172,7 @@ func (s *testTimeSuite) TestDate(c *C) {

errTable := []string{
"0121231",
"2019.01",
}

for _, test := range errTable {
Expand Down Expand Up @@ -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)
}
}

0 comments on commit e2a2cc4

Please sign in to comment.