Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

types: fix incorrect time fraction parsing method #9933

Merged
merged 9 commits into from
Apr 1, 2019
40 changes: 36 additions & 4 deletions types/time.go
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,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 @@ -453,6 +459,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 @@ -655,9 +677,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 @@ -742,6 +765,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 @@ -64,6 +64,9 @@ func (s *testTimeSuite) TestDateTime(c *C) {
{"170102037.11", "2017-01-02 03:07:11.00"},
{"2018-01-01 18", "2018-01-01 18:00:00"},
{"18-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"},
}

for _, test := range table {
Expand All @@ -85,6 +88,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 @@ -105,6 +111,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 @@ -154,6 +162,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 @@ -164,6 +174,7 @@ func (s *testTimeSuite) TestDate(c *C) {

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

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