From 92e7b9fd919c59e80837f548f29e11315ff90c8a Mon Sep 17 00:00:00 2001 From: Song Guo Date: Sun, 5 May 2019 19:17:45 +0800 Subject: [PATCH 1/5] types: Fix checkMonthDay() to correctly handle leap year (#10342) --- types/time.go | 6 +-- types/time_test.go | 111 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 3 deletions(-) diff --git a/types/time.go b/types/time.go index f0e0ab615e0e4..d1d0917445ad9 100644 --- a/types/time.go +++ b/types/time.go @@ -1457,7 +1457,7 @@ func checkDateRange(t MysqlTime) error { func checkMonthDay(year, month, day int, allowInvalidDate bool) error { if month < 0 || month > 12 { - return errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(month)) + return errors.Trace(ErrIncorrectDatetimeValue.GenWithStackByArgs(month)) } maxDay := 31 @@ -1465,13 +1465,13 @@ func checkMonthDay(year, month, day int, allowInvalidDate bool) error { if month > 0 { maxDay = maxDaysInMonth[month-1] } - if month == 2 && year%4 != 0 { + if month == 2 && !isLeapYear(uint16(year)) { maxDay = 28 } } if day < 0 || day > maxDay { - return errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(day)) + return errors.Trace(ErrIncorrectDatetimeValue.GenWithStackByArgs(day)) } return nil } diff --git a/types/time_test.go b/types/time_test.go index 9021c61614a36..50a815e7fc62c 100644 --- a/types/time_test.go +++ b/types/time_test.go @@ -1333,3 +1333,114 @@ func (s *testTimeSuite) TestgetFracIndex(c *C) { c.Assert(index, Equals, testCase.expectIndex) } } + +func (s *testTimeSuite) TestTimeOverflow(c *C) { + sc := mock.NewContext().GetSessionVars().StmtCtx + sc.IgnoreZeroInDate = true + defer testleak.AfterTest(c)() + table := []struct { + Input string + Output bool + }{ + {"2012-12-31 11:30:45", false}, + {"12-12-31 11:30:45", false}, + {"2012-12-31", false}, + {"20121231", false}, + {"2012-02-29", false}, + {"2018-01-01 18", false}, + {"18-01-01 18", false}, + {"2018.01.01", false}, + {"2018.01.01 00:00:00", false}, + {"2018/01/01-00:00:00", false}, + } + + for _, test := range table { + t, err := types.ParseDatetime(sc, test.Input) + c.Assert(err, IsNil) + isOverflow, err := types.DateTimeIsOverflow(sc, t) + c.Assert(err, IsNil) + c.Assert(isOverflow, Equals, test.Output) + } +} + +func (s *testTimeSuite) TestTruncateFrac(c *C) { + cols := []struct { + input time.Time + fsp int + output time.Time + }{ + {time.Date(2011, 11, 11, 10, 10, 10, 888888, time.UTC), 0, time.Date(2011, 11, 11, 10, 10, 10, 11, time.UTC)}, + {time.Date(2011, 11, 11, 10, 10, 10, 111111, time.UTC), 0, time.Date(2011, 11, 11, 10, 10, 10, 10, time.UTC)}, + } + + for _, col := range cols { + res, err := types.TruncateFrac(col.input, col.fsp) + c.Assert(res.Second(), Equals, col.output.Second()) + c.Assert(err, IsNil) + } +} +func (s *testTimeSuite) TestTimeSub(c *C) { + tbl := []struct { + Arg1 string + Arg2 string + Ret string + }{ + {"2017-01-18 01:01:01", "2017-01-18 00:00:01", "01:01:00"}, + {"2017-01-18 01:01:01", "2017-01-18 01:01:01", "00:00:00"}, + {"2019-04-12 18:20:00", "2019-04-12 14:00:00", "04:20:00"}, + } + + sc := &stmtctx.StatementContext{ + TimeZone: time.UTC, + } + for _, t := range tbl { + v1, err := types.ParseTime(nil, t.Arg1, mysql.TypeDatetime, types.MaxFsp) + c.Assert(err, IsNil) + v2, err := types.ParseTime(nil, t.Arg2, mysql.TypeDatetime, types.MaxFsp) + c.Assert(err, IsNil) + dur, err := types.ParseDuration(sc, t.Ret, types.MaxFsp) + c.Assert(err, IsNil) + rec := v1.Sub(sc, &v2) + c.Assert(rec, Equals, dur) + } +} + +func (s *testTimeSuite) TestCheckMonthDay(c *C) { + dates := []struct { + date types.MysqlTime + isValidDate bool + }{ + {types.FromDate(1900, 2, 29, 0, 0, 0, 0), false}, + {types.FromDate(1900, 2, 28, 0, 0, 0, 0), true}, + {types.FromDate(2000, 2, 29, 0, 0, 0, 0), true}, + {types.FromDate(2000, 1, 1, 0, 0, 0, 0), true}, + {types.FromDate(1900, 1, 1, 0, 0, 0, 0), true}, + {types.FromDate(1900, 1, 31, 0, 0, 0, 0), true}, + {types.FromDate(1900, 4, 1, 0, 0, 0, 0), true}, + {types.FromDate(1900, 4, 31, 0, 0, 0, 0), false}, + {types.FromDate(1900, 4, 30, 0, 0, 0, 0), true}, + {types.FromDate(2000, 2, 30, 0, 0, 0, 0), false}, + {types.FromDate(2000, 13, 1, 0, 0, 0, 0), false}, + {types.FromDate(4000, 2, 29, 0, 0, 0, 0), true}, + {types.FromDate(3200, 2, 29, 0, 0, 0, 0), true}, + } + + sc := &stmtctx.StatementContext{ + TimeZone: time.UTC, + AllowInvalidDate: false, + } + + for _, t := range dates { + tt := types.Time{ + Time: t.date, + Type: mysql.TypeDate, + Fsp: types.DefaultFsp, + } + err := tt.Check(sc) + if t.isValidDate { + c.Check(err, IsNil) + } else { + c.Check(types.ErrIncorrectDatetimeValue.Equal(err), IsTrue) + } + } +} From 6c452cc8f7dd81c1013956da2ab33102eb82be8a Mon Sep 17 00:00:00 2001 From: Guo Song Date: Fri, 10 May 2019 16:29:34 +0800 Subject: [PATCH 2/5] remove non-exist test --- types/time_test.go | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/types/time_test.go b/types/time_test.go index 50a815e7fc62c..004318568ac8c 100644 --- a/types/time_test.go +++ b/types/time_test.go @@ -1363,22 +1363,6 @@ func (s *testTimeSuite) TestTimeOverflow(c *C) { } } -func (s *testTimeSuite) TestTruncateFrac(c *C) { - cols := []struct { - input time.Time - fsp int - output time.Time - }{ - {time.Date(2011, 11, 11, 10, 10, 10, 888888, time.UTC), 0, time.Date(2011, 11, 11, 10, 10, 10, 11, time.UTC)}, - {time.Date(2011, 11, 11, 10, 10, 10, 111111, time.UTC), 0, time.Date(2011, 11, 11, 10, 10, 10, 10, time.UTC)}, - } - - for _, col := range cols { - res, err := types.TruncateFrac(col.input, col.fsp) - c.Assert(res.Second(), Equals, col.output.Second()) - c.Assert(err, IsNil) - } -} func (s *testTimeSuite) TestTimeSub(c *C) { tbl := []struct { Arg1 string From 7de8c872195fef97cd70dda0a1f5be7b21b05496 Mon Sep 17 00:00:00 2001 From: Guo Song Date: Fri, 10 May 2019 16:41:17 +0800 Subject: [PATCH 3/5] remove some tests --- types/time_test.go | 55 ---------------------------------------------- 1 file changed, 55 deletions(-) diff --git a/types/time_test.go b/types/time_test.go index 004318568ac8c..262ef62c92cac 100644 --- a/types/time_test.go +++ b/types/time_test.go @@ -1334,61 +1334,6 @@ func (s *testTimeSuite) TestgetFracIndex(c *C) { } } -func (s *testTimeSuite) TestTimeOverflow(c *C) { - sc := mock.NewContext().GetSessionVars().StmtCtx - sc.IgnoreZeroInDate = true - defer testleak.AfterTest(c)() - table := []struct { - Input string - Output bool - }{ - {"2012-12-31 11:30:45", false}, - {"12-12-31 11:30:45", false}, - {"2012-12-31", false}, - {"20121231", false}, - {"2012-02-29", false}, - {"2018-01-01 18", false}, - {"18-01-01 18", false}, - {"2018.01.01", false}, - {"2018.01.01 00:00:00", false}, - {"2018/01/01-00:00:00", false}, - } - - for _, test := range table { - t, err := types.ParseDatetime(sc, test.Input) - c.Assert(err, IsNil) - isOverflow, err := types.DateTimeIsOverflow(sc, t) - c.Assert(err, IsNil) - c.Assert(isOverflow, Equals, test.Output) - } -} - -func (s *testTimeSuite) TestTimeSub(c *C) { - tbl := []struct { - Arg1 string - Arg2 string - Ret string - }{ - {"2017-01-18 01:01:01", "2017-01-18 00:00:01", "01:01:00"}, - {"2017-01-18 01:01:01", "2017-01-18 01:01:01", "00:00:00"}, - {"2019-04-12 18:20:00", "2019-04-12 14:00:00", "04:20:00"}, - } - - sc := &stmtctx.StatementContext{ - TimeZone: time.UTC, - } - for _, t := range tbl { - v1, err := types.ParseTime(nil, t.Arg1, mysql.TypeDatetime, types.MaxFsp) - c.Assert(err, IsNil) - v2, err := types.ParseTime(nil, t.Arg2, mysql.TypeDatetime, types.MaxFsp) - c.Assert(err, IsNil) - dur, err := types.ParseDuration(sc, t.Ret, types.MaxFsp) - c.Assert(err, IsNil) - rec := v1.Sub(sc, &v2) - c.Assert(rec, Equals, dur) - } -} - func (s *testTimeSuite) TestCheckMonthDay(c *C) { dates := []struct { date types.MysqlTime From c84365aeb48e6f4b4e87099e7ca3ea190adbaa6d Mon Sep 17 00:00:00 2001 From: Guo Song Date: Sat, 11 May 2019 10:16:41 +0800 Subject: [PATCH 4/5] revert error type --- types/time.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/types/time.go b/types/time.go index d1d0917445ad9..104f85578f58b 100644 --- a/types/time.go +++ b/types/time.go @@ -1457,7 +1457,7 @@ func checkDateRange(t MysqlTime) error { func checkMonthDay(year, month, day int, allowInvalidDate bool) error { if month < 0 || month > 12 { - return errors.Trace(ErrIncorrectDatetimeValue.GenWithStackByArgs(month)) + return errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(month)) } maxDay := 31 @@ -1471,7 +1471,7 @@ func checkMonthDay(year, month, day int, allowInvalidDate bool) error { } if day < 0 || day > maxDay { - return errors.Trace(ErrIncorrectDatetimeValue.GenWithStackByArgs(day)) + return errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(day)) } return nil } From 4f980489db28169a07d955f26c32a542aa84f358 Mon Sep 17 00:00:00 2001 From: Guo Song Date: Sat, 11 May 2019 10:19:17 +0800 Subject: [PATCH 5/5] fix --- 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 262ef62c92cac..d6c1b2d1bb5a7 100644 --- a/types/time_test.go +++ b/types/time_test.go @@ -1369,7 +1369,7 @@ func (s *testTimeSuite) TestCheckMonthDay(c *C) { if t.isValidDate { c.Check(err, IsNil) } else { - c.Check(types.ErrIncorrectDatetimeValue.Equal(err), IsTrue) + c.Check(types.ErrInvalidTimeFormat.Equal(err), IsTrue) } } }