Skip to content

Commit

Permalink
types: fix the incorrect behavior of "%y"/"%Y" for STR_TO_DATE() (pin…
Browse files Browse the repository at this point in the history
  • Loading branch information
FateTHarlaown authored and zz-jason committed Jan 8, 2019
1 parent 106bc7e commit 884db0a
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 7 deletions.
40 changes: 40 additions & 0 deletions executor/executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3493,3 +3493,43 @@ func (s *testSuite3) TearDownTest(c *C) {
tk.MustExec(fmt.Sprintf("drop table %v", tableName))
}
}

func (s *testSuite) TestStrToDateBuiltin(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustQuery(`select str_to_date('18/10/22','%y/%m/%d') from dual`).Check(testkit.Rows("2018-10-22"))
tk.MustQuery(`select str_to_date('a18/10/22','%y/%m/%d') from dual`).Check(testkit.Rows("<nil>"))
tk.MustQuery(`select str_to_date('69/10/22','%y/%m/%d') from dual`).Check(testkit.Rows("2069-10-22"))
tk.MustQuery(`select str_to_date('70/10/22','%y/%m/%d') from dual`).Check(testkit.Rows("1970-10-22"))
tk.MustQuery(`select str_to_date('8/10/22','%y/%m/%d') from dual`).Check(testkit.Rows("2008-10-22"))
tk.MustQuery(`select str_to_date('8/10/22','%Y/%m/%d') from dual`).Check(testkit.Rows("2008-10-22"))
tk.MustQuery(`select str_to_date('18/10/22','%Y/%m/%d') from dual`).Check(testkit.Rows("2018-10-22"))
tk.MustQuery(`select str_to_date('a18/10/22','%Y/%m/%d') from dual`).Check(testkit.Rows("<nil>"))
tk.MustQuery(`select str_to_date('69/10/22','%Y/%m/%d') from dual`).Check(testkit.Rows("2069-10-22"))
tk.MustQuery(`select str_to_date('70/10/22','%Y/%m/%d') from dual`).Check(testkit.Rows("1970-10-22"))
tk.MustQuery(`select str_to_date('018/10/22','%Y/%m/%d') from dual`).Check(testkit.Rows("0018-10-22"))
tk.MustQuery(`select str_to_date('2018/10/22','%Y/%m/%d') from dual`).Check(testkit.Rows("2018-10-22"))
tk.MustQuery(`select str_to_date('018/10/22','%y/%m/%d') from dual`).Check(testkit.Rows("<nil>"))
tk.MustQuery(`select str_to_date('18/10/22','%y0/%m/%d') from dual`).Check(testkit.Rows("<nil>"))
tk.MustQuery(`select str_to_date('18/10/22','%Y0/%m/%d') from dual`).Check(testkit.Rows("<nil>"))
tk.MustQuery(`select str_to_date('18a/10/22','%y/%m/%d') from dual`).Check(testkit.Rows("<nil>"))
tk.MustQuery(`select str_to_date('18a/10/22','%Y/%m/%d') from dual`).Check(testkit.Rows("<nil>"))
tk.MustQuery(`select str_to_date('20188/10/22','%Y/%m/%d') from dual`).Check(testkit.Rows("<nil>"))
tk.MustQuery(`select str_to_date('2018510522','%Y5%m5%d') from dual`).Check(testkit.Rows("2018-10-22"))
tk.MustQuery(`select str_to_date('2018^10^22','%Y^%m^%d') from dual`).Check(testkit.Rows("2018-10-22"))
tk.MustQuery(`select str_to_date('2018@10@22','%Y@%m@%d') from dual`).Check(testkit.Rows("2018-10-22"))
tk.MustQuery(`select str_to_date('2018%10%22','%Y%%m%%d') from dual`).Check(testkit.Rows("<nil>"))
tk.MustQuery(`select str_to_date('2018(10(22','%Y(%m(%d') from dual`).Check(testkit.Rows("2018-10-22"))
tk.MustQuery(`select str_to_date('2018\10\22','%Y\%m\%d') from dual`).Check(testkit.Rows("<nil>"))
tk.MustQuery(`select str_to_date('2018=10=22','%Y=%m=%d') from dual`).Check(testkit.Rows("2018-10-22"))
tk.MustQuery(`select str_to_date('2018+10+22','%Y+%m+%d') from dual`).Check(testkit.Rows("2018-10-22"))
tk.MustQuery(`select str_to_date('2018_10_22','%Y_%m_%d') from dual`).Check(testkit.Rows("2018-10-22"))
tk.MustQuery(`select str_to_date('69510522','%y5%m5%d') from dual`).Check(testkit.Rows("2069-10-22"))
tk.MustQuery(`select str_to_date('69^10^22','%y^%m^%d') from dual`).Check(testkit.Rows("2069-10-22"))
tk.MustQuery(`select str_to_date('18@10@22','%y@%m@%d') from dual`).Check(testkit.Rows("2018-10-22"))
tk.MustQuery(`select str_to_date('18%10%22','%y%%m%%d') from dual`).Check(testkit.Rows("<nil>"))
tk.MustQuery(`select str_to_date('18(10(22','%y(%m(%d') from dual`).Check(testkit.Rows("2018-10-22"))
tk.MustQuery(`select str_to_date('18\10\22','%y\%m\%d') from dual`).Check(testkit.Rows("<nil>"))
tk.MustQuery(`select str_to_date('18+10+22','%y+%m+%d') from dual`).Check(testkit.Rows("2018-10-22"))
tk.MustQuery(`select str_to_date('18=10=22','%y=%m=%d') from dual`).Check(testkit.Rows("2018-10-22"))
tk.MustQuery(`select str_to_date('18_10_22','%y_%m_%d') from dual`).Check(testkit.Rows("2018-10-22"))
}
12 changes: 12 additions & 0 deletions types/format_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,17 @@ func (s *testTimeSuite) TestStrToDate(c *C) {
{`10:13 PM`, `%l:%i %p`, types.FromDate(0, 0, 0, 22, 13, 0, 0)},
{`12:00:00 AM`, `%h:%i:%s %p`, types.FromDate(0, 0, 0, 0, 0, 0, 0)},
{`12:00:00 PM`, `%h:%i:%s %p`, types.FromDate(0, 0, 0, 12, 0, 0, 0)},
{`18/10/22`, `%y/%m/%d`, types.FromDate(2018, 10, 22, 0, 0, 0, 0)},
{`8/10/22`, `%y/%m/%d`, types.FromDate(2008, 10, 22, 0, 0, 0, 0)},
{`69/10/22`, `%y/%m/%d`, types.FromDate(2069, 10, 22, 0, 0, 0, 0)},
{`70/10/22`, `%y/%m/%d`, types.FromDate(1970, 10, 22, 0, 0, 0, 0)},
{`18/10/22`, `%Y/%m/%d`, types.FromDate(2018, 10, 22, 0, 0, 0, 0)},
{`2018/10/22`, `%Y/%m/%d`, types.FromDate(2018, 10, 22, 0, 0, 0, 0)},
{`8/10/22`, `%Y/%m/%d`, types.FromDate(2008, 10, 22, 0, 0, 0, 0)},
{`69/10/22`, `%Y/%m/%d`, types.FromDate(2069, 10, 22, 0, 0, 0, 0)},
{`70/10/22`, `%Y/%m/%d`, types.FromDate(1970, 10, 22, 0, 0, 0, 0)},
{`18/10/22`, `%Y/%m/%d`, types.FromDate(2018, 10, 22, 0, 0, 0, 0)},
{`100/10/22`, `%Y/%m/%d`, types.FromDate(100, 10, 22, 0, 0, 0, 0)},
}
for i, tt := range tests {
var t types.Time
Expand All @@ -121,6 +132,7 @@ func (s *testTimeSuite) TestStrToDate(c *C) {
{`23:60:12`, `%T`}, // invalid minute
{`18`, `%l`},
{`00:21:22 AM`, `%h:%i:%s %p`},
{`100/10/22`, `%y/%m/%d`},
}
for _, tt := range errTests {
var t types.Time
Expand Down
33 changes: 26 additions & 7 deletions types/time.go
Original file line number Diff line number Diff line change
Expand Up @@ -2165,6 +2165,8 @@ var dateFormatParserTable = map[string]dateFormatParser{
"%S": secondsNumeric, // Seconds (00..59)
"%T": time24Hour, // Time, 24-hour (hh:mm:ss)
"%Y": yearNumericFourDigits, // Year, numeric, four digits
// Deprecated since MySQL 5.7.5
"%y": yearNumericTwoDigits, // Year, numeric (two digits)
// TODO: Add the following...
// "%a": abbreviatedWeekday, // Abbreviated weekday name (Sun..Sat)
// "%D": dayOfMonthWithSuffix, // Day of the month with English suffix (0th, 1st, 2nd, 3rd)
Expand All @@ -2176,8 +2178,6 @@ var dateFormatParserTable = map[string]dateFormatParser{
// "%w": dayOfWeek, // Day of the week (0=Sunday..6=Saturday)
// "%X": yearOfWeek, // Year for the week where Sunday is the first day of the week, numeric, four digits; used with %V
// "%x": yearOfWeek, // Year for the week, where Monday is the first day of the week, numeric, four digits; used with %v
// Deprecated since MySQL 5.7.5
// "%y": yearTwoDigits, // Year, numeric (two digits)
}

// GetFormatType checks the type(Duration, Date or Datetime) of a format string.
Expand Down Expand Up @@ -2235,7 +2235,7 @@ func matchDateWithToken(t *MysqlTime, date string, token string, ctx map[string]
}

func parseDigits(input string, count int) (int, bool) {
if len(input) < count {
if count <= 0 || len(input) < count {
return 0, false
}

Expand Down Expand Up @@ -2432,12 +2432,31 @@ func microSeconds(t *MysqlTime, input string, ctx map[string]int) (string, bool)
}

func yearNumericFourDigits(t *MysqlTime, input string, ctx map[string]int) (string, bool) {
v, succ := parseDigits(input, 4)
if !succ {
return yearNumericNDigits(t, input, ctx, 4)
}

func yearNumericTwoDigits(t *MysqlTime, input string, ctx map[string]int) (string, bool) {
return yearNumericNDigits(t, input, ctx, 2)
}

func yearNumericNDigits(t *MysqlTime, input string, ctx map[string]int, n int) (string, bool) {
effectiveCount, effectiveValue := 0, 0
for effectiveCount+1 <= n {
value, succeed := parseDigits(input, effectiveCount+1)
if !succeed {
break
}
effectiveCount++
effectiveValue = value
}
if effectiveCount == 0 {
return input, false
}
t.year = uint16(v)
return input[4:], true
if effectiveCount <= 2 {
effectiveValue = adjustYear(effectiveValue)
}
t.year = uint16(effectiveValue)
return input[effectiveCount:], true
}

func dayOfYearThreeDigits(t *MysqlTime, input string, ctx map[string]int) (string, bool) {
Expand Down

0 comments on commit 884db0a

Please sign in to comment.