Skip to content

Commit

Permalink
expression: Fix some datetime related cases that is inconsistent with…
Browse files Browse the repository at this point in the history
… MySQL (#7636)
  • Loading branch information
spongedu authored and zz-jason committed Sep 7, 2018
1 parent 8c44f56 commit 6fb1a63
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 13 deletions.
2 changes: 1 addition & 1 deletion expression/builtin_cast.go
Original file line number Diff line number Diff line change
Expand Up @@ -968,7 +968,7 @@ func (b *builtinCastDecimalAsTimeSig) evalTime(row chunk.Row) (res types.Time, i
return res, isNull, errors.Trace(err)
}
sc := b.ctx.GetSessionVars().StmtCtx
res, err = types.ParseTime(sc, string(val.ToString()), b.tp.Tp, b.tp.Decimal)
res, err = types.ParseTimeFromFloatString(sc, string(val.ToString()), b.tp.Tp, b.tp.Decimal)
if err != nil {
return res, false, errors.Trace(err)
}
Expand Down
20 changes: 14 additions & 6 deletions expression/builtin_time.go
Original file line number Diff line number Diff line change
Expand Up @@ -993,7 +993,10 @@ func (b *builtinMonthSig) evalInt(row chunk.Row) (int64, bool, error) {
}

if date.IsZero() {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(date.String())))
if b.ctx.GetSessionVars().SQLMode.HasNoZeroDateMode() {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(date.String())))
}
return 0, false, nil
}

return int64(date.Time.Month()), false, nil
Expand Down Expand Up @@ -1030,9 +1033,9 @@ func (b *builtinMonthNameSig) evalString(row chunk.Row) (string, bool, error) {
return "", true, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
mon := arg.Time.Month()
if arg.IsZero() || mon < 0 || mon > len(types.MonthNames) {
if (arg.IsZero() && b.ctx.GetSessionVars().SQLMode.HasNoZeroDateMode()) || mon < 0 || mon > len(types.MonthNames) {
return "", true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(arg.String())))
} else if mon == 0 {
} else if mon == 0 || arg.IsZero() {
return "", true, nil
}
return types.MonthNames[mon-1], false, nil
Expand Down Expand Up @@ -1111,7 +1114,10 @@ func (b *builtinDayOfMonthSig) evalInt(row chunk.Row) (int64, bool, error) {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
if arg.IsZero() {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(arg.String())))
if b.ctx.GetSessionVars().SQLMode.HasNoZeroDateMode() {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(arg.String())))
}
return 0, false, nil
}
return int64(arg.Time.Day()), false, nil
}
Expand Down Expand Up @@ -1393,9 +1399,11 @@ func (b *builtinYearSig) evalInt(row chunk.Row) (int64, bool, error) {
}

if date.IsZero() {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(date.String())))
if b.ctx.GetSessionVars().SQLMode.HasNoZeroDateMode() {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(date.String())))
}
return 0, false, nil
}

return int64(date.Time.Year()), false, nil
}

Expand Down
104 changes: 103 additions & 1 deletion expression/builtin_time_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,13 +169,115 @@ func (s *testEvaluatorSuite) TestDate(c *C) {
Week interface{}
WeekOfYear interface{}
YearWeek interface{}
}{
{nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil},
{"0000-00-00 00:00:00", 0, 0, nil, 0, nil, nil, nil, nil, nil, nil, nil},
{"0000-00-00", 0, 0, nil, 0, nil, nil, nil, nil, nil, nil, nil},
}

dtblNil := tblToDtbl(tblNil)
for _, t := range dtblNil {
fc := funcs[ast.Year]
f, err := fc.getFunction(s.ctx, s.datumsToConstants(t["Input"]))
c.Assert(err, IsNil)
v, err := evalBuiltinFunc(f, chunk.Row{})
c.Assert(err, IsNil)
c.Assert(v, testutil.DatumEquals, t["Year"][0])

fc = funcs[ast.Month]
f, err = fc.getFunction(s.ctx, s.datumsToConstants(t["Input"]))
c.Assert(err, IsNil)
v, err = evalBuiltinFunc(f, chunk.Row{})
c.Assert(err, IsNil)
c.Assert(v, testutil.DatumEquals, t["Month"][0])

fc = funcs[ast.MonthName]
f, err = fc.getFunction(s.ctx, s.datumsToConstants(t["Input"]))
c.Assert(err, IsNil)
v, err = evalBuiltinFunc(f, chunk.Row{})
c.Assert(err, IsNil)
c.Assert(v, testutil.DatumEquals, t["MonthName"][0])

fc = funcs[ast.DayOfMonth]
f, err = fc.getFunction(s.ctx, s.datumsToConstants(t["Input"]))
c.Assert(err, IsNil)
v, err = evalBuiltinFunc(f, chunk.Row{})
c.Assert(err, IsNil)
c.Assert(v, testutil.DatumEquals, t["DayOfMonth"][0])

fc = funcs[ast.DayOfWeek]
f, err = fc.getFunction(s.ctx, s.datumsToConstants(t["Input"]))
c.Assert(err, IsNil)
v, err = evalBuiltinFunc(f, chunk.Row{})
c.Assert(err, IsNil)
c.Assert(v, testutil.DatumEquals, t["DayOfWeek"][0])

fc = funcs[ast.DayOfYear]
f, err = fc.getFunction(s.ctx, s.datumsToConstants(t["Input"]))
c.Assert(err, IsNil)
v, err = evalBuiltinFunc(f, chunk.Row{})
c.Assert(err, IsNil)
c.Assert(v, testutil.DatumEquals, t["DayOfYear"][0])

fc = funcs[ast.Weekday]
f, err = fc.getFunction(s.ctx, s.datumsToConstants(t["Input"]))
c.Assert(err, IsNil)
c.Assert(f, NotNil)
v, err = evalBuiltinFunc(f, chunk.Row{})
c.Assert(err, IsNil)
c.Assert(v, testutil.DatumEquals, t["WeekDay"][0])

fc = funcs[ast.DayName]
f, err = fc.getFunction(s.ctx, s.datumsToConstants(t["Input"]))
c.Assert(err, IsNil)
v, err = evalBuiltinFunc(f, chunk.Row{})
c.Assert(err, IsNil)
c.Assert(v, testutil.DatumEquals, t["DayName"][0])

fc = funcs[ast.Week]
f, err = fc.getFunction(s.ctx, s.datumsToConstants(t["Input"]))
c.Assert(err, IsNil)
v, err = evalBuiltinFunc(f, chunk.Row{})
c.Assert(err, IsNil)
c.Assert(v, testutil.DatumEquals, t["Week"][0])

fc = funcs[ast.WeekOfYear]
f, err = fc.getFunction(s.ctx, s.datumsToConstants(t["Input"]))
c.Assert(err, IsNil)
v, err = evalBuiltinFunc(f, chunk.Row{})
c.Assert(err, IsNil)
c.Assert(v, testutil.DatumEquals, t["WeekOfYear"][0])

fc = funcs[ast.YearWeek]
f, err = fc.getFunction(s.ctx, s.datumsToConstants(t["Input"]))
c.Assert(err, IsNil)
v, err = evalBuiltinFunc(f, chunk.Row{})
c.Assert(err, IsNil)
c.Assert(v, testutil.DatumEquals, t["YearWeek"][0])
}

// test nil with 'NO_ZERO_DATE' set in sql_mode
tblNil = []struct {
Input interface{}
Year interface{}
Month interface{}
MonthName interface{}
DayOfMonth interface{}
DayOfWeek interface{}
DayOfYear interface{}
WeekDay interface{}
DayName interface{}
Week interface{}
WeekOfYear interface{}
YearWeek interface{}
}{
{nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil},
{"0000-00-00 00:00:00", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil},
{"0000-00-00", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil},
}

dtblNil := tblToDtbl(tblNil)
dtblNil = tblToDtbl(tblNil)
s.ctx.GetSessionVars().SetSystemVar("sql_mode", "NO_ZERO_DATE")
for _, t := range dtblNil {
fc := funcs[ast.Year]
f, err := fc.getFunction(s.ctx, s.datumsToConstants(t["Input"]))
Expand Down
48 changes: 43 additions & 5 deletions expression/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1091,10 +1091,16 @@ func (s *testIntegrationSuite) TestTimeBuiltin(c *C) {
_, err := tk.Exec(`insert into t select year("aa")`)
c.Assert(err, NotNil)
c.Assert(terror.ErrorEqual(err, types.ErrInvalidTimeFormat), IsTrue, Commentf("err %v", err))
_, err = tk.Exec(`insert into t select year("0000-00-00 00:00:00")`)
tk.MustExec(`insert into t select year("0000-00-00 00:00:00")`)
tk.MustExec(`set sql_mode="NO_ZERO_DATE";`)
tk.MustExec(`insert into t select year("0000-00-00 00:00:00")`)
tk.MustQuery("show warnings").Check(testutil.RowsWithSep("|", "Warning|1292|Incorrect datetime value: '0000-00-00 00:00:00.000000'"))
tk.MustExec(`set sql_mode="NO_ZERO_DATE,STRICT_TRANS_TABLES";`)
_, err = tk.Exec(`insert into t select year("0000-00-00 00:00:00");`)
c.Assert(err, NotNil)
c.Assert(types.ErrIncorrectDatetimeValue.Equal(err), IsTrue, Commentf("err %v", err))
tk.MustExec(`insert into t select 1`)
tk.MustExec(`set sql_mode="STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION";`)
_, err = tk.Exec(`update t set a = year("aa")`)
c.Assert(terror.ErrorEqual(err, types.ErrInvalidTimeFormat), IsTrue, Commentf("err %v", err))
_, err = tk.Exec(`delete from t where a = year("aa")`)
Expand All @@ -1114,9 +1120,16 @@ func (s *testIntegrationSuite) TestTimeBuiltin(c *C) {
_, err = tk.Exec(`insert into t select month("aa")`)
c.Assert(err, NotNil)
c.Assert(terror.ErrorEqual(err, types.ErrInvalidTimeFormat), IsTrue)
_, err = tk.Exec(`insert into t select month("0000-00-00 00:00:00")`)
tk.MustExec(`insert into t select month("0000-00-00 00:00:00")`)
tk.MustExec(`set sql_mode="NO_ZERO_DATE";`)
tk.MustExec(`insert into t select month("0000-00-00 00:00:00")`)
tk.MustQuery("show warnings").Check(testutil.RowsWithSep("|", "Warning|1292|Incorrect datetime value: '0000-00-00 00:00:00.000000'"))
tk.MustExec(`set sql_mode="NO_ZERO_DATE,STRICT_TRANS_TABLES";`)
_, err = tk.Exec(`insert into t select month("0000-00-00 00:00:00");`)
c.Assert(err, NotNil)
c.Assert(types.ErrIncorrectDatetimeValue.Equal(err), IsTrue)
c.Assert(types.ErrIncorrectDatetimeValue.Equal(err), IsTrue, Commentf("err %v", err))
tk.MustExec(`insert into t select 1`)
tk.MustExec(`set sql_mode="STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION";`)
tk.MustExec(`insert into t select 1`)
_, err = tk.Exec(`update t set a = month("aa")`)
c.Assert(terror.ErrorEqual(err, types.ErrInvalidTimeFormat), IsTrue)
Expand Down Expand Up @@ -1442,6 +1455,14 @@ func (s *testIntegrationSuite) TestTimeBuiltin(c *C) {
result = tk.MustQuery(`select dayOfYear(null), dayOfYear("2017-08-12"), dayOfYear("0000-00-00"), dayOfYear("2017-00-00"), dayOfYear("0000-00-00 12:12:12"), dayOfYear("2017-00-00 12:12:12")`)
result.Check(testkit.Rows("<nil> 224 <nil> <nil> <nil> <nil>"))
result = tk.MustQuery(`select dayOfMonth(null), dayOfMonth("2017-08-12"), dayOfMonth("0000-00-00"), dayOfMonth("2017-00-00"), dayOfMonth("0000-00-00 12:12:12"), dayOfMonth("2017-00-00 12:12:12")`)
result.Check(testkit.Rows("<nil> 12 0 0 0 0"))

tk.MustExec("set sql_mode = 'NO_ZERO_DATE'")
result = tk.MustQuery(`select dayOfWeek(null), dayOfWeek("2017-08-12"), dayOfWeek("0000-00-00"), dayOfWeek("2017-00-00"), dayOfWeek("0000-00-00 12:12:12"), dayOfWeek("2017-00-00 12:12:12")`)
result.Check(testkit.Rows("<nil> 7 <nil> <nil> <nil> <nil>"))
result = tk.MustQuery(`select dayOfYear(null), dayOfYear("2017-08-12"), dayOfYear("0000-00-00"), dayOfYear("2017-00-00"), dayOfYear("0000-00-00 12:12:12"), dayOfYear("2017-00-00 12:12:12")`)
result.Check(testkit.Rows("<nil> 224 <nil> <nil> <nil> <nil>"))
result = tk.MustQuery(`select dayOfMonth(null), dayOfMonth("2017-08-12"), dayOfMonth("0000-00-00"), dayOfMonth("2017-00-00"), dayOfMonth("0000-00-00 12:12:12"), dayOfMonth("2017-00-00 12:12:12")`)
result.Check(testkit.Rows("<nil> 12 <nil> 0 0 0"))

tk.MustExec(`drop table if exists t`)
Expand All @@ -1458,6 +1479,13 @@ func (s *testIntegrationSuite) TestTimeBuiltin(c *C) {

_, err = tk.Exec("insert into t value(dayOfMonth('2017-00-00'))")
c.Assert(types.ErrIncorrectDatetimeValue.Equal(err), IsTrue)
tk.MustExec("insert into t value(dayOfMonth('0000-00-00'))")
tk.MustExec(`update t set a = dayOfMonth("0000-00-00")`)
tk.MustExec("set sql_mode = 'NO_ZERO_DATE';")
tk.MustExec("insert into t value(dayOfMonth('0000-00-00'))")
tk.MustQuery("show warnings").Check(testutil.RowsWithSep("|", "Warning|1292|Incorrect datetime value: '0000-00-00 00:00:00.000000'"))
tk.MustExec(`update t set a = dayOfMonth("0000-00-00")`)
tk.MustExec("set sql_mode = 'NO_ZERO_DATE,STRICT_TRANS_TABLES';")
_, err = tk.Exec("insert into t value(dayOfMonth('0000-00-00'))")
c.Assert(types.ErrIncorrectDatetimeValue.Equal(err), IsTrue)
tk.MustExec("insert into t value(0)")
Expand Down Expand Up @@ -1539,8 +1567,15 @@ func (s *testIntegrationSuite) TestTimeBuiltin(c *C) {
tk.MustExec(`insert into t value("abc")`)
tk.MustExec("set sql_mode = 'STRICT_TRANS_TABLES'")

_, err = tk.Exec("insert into t value(monthname('0000-00-00'))")
c.Assert(types.ErrIncorrectDatetimeValue.Equal(err), IsTrue)
tk.MustExec("insert into t value(monthname('0000-00-00'))")
tk.MustExec(`update t set a = monthname("0000-00-00")`)
tk.MustExec("set sql_mode = 'NO_ZERO_DATE'")
tk.MustExec("insert into t value(monthname('0000-00-00'))")
tk.MustQuery("show warnings").Check(testutil.RowsWithSep("|", "Warning|1292|Incorrect datetime value: '0000-00-00 00:00:00.000000'"))
tk.MustExec(`update t set a = monthname("0000-00-00")`)
tk.MustExec("set sql_mode = ''")
tk.MustExec("insert into t value(monthname('0000-00-00'))")
tk.MustExec("set sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_DATE'")
_, err = tk.Exec(`update t set a = monthname("0000-00-00")`)
c.Assert(types.ErrIncorrectDatetimeValue.Equal(err), IsTrue)
_, err = tk.Exec(`delete from t where a = monthname(123)`)
Expand Down Expand Up @@ -1880,6 +1915,9 @@ func (s *testIntegrationSuite) TestBuiltin(c *C) {
result = tk.MustQuery(`select cast(cast('2017-01-01 01:01:11.12' as date) as datetime(2));`)
result.Check(testkit.Rows("2017-01-01 00:00:00.00"))

result = tk.MustQuery(`select cast(20170118.999 as datetime);`)
result.Check(testkit.Rows("2017-01-18 00:00:00"))

// for ISNULL
tk.MustExec("drop table if exists t")
tk.MustExec("create table t (a int, b int, c int, d char(10), e datetime, f float, g decimal(10, 3))")
Expand Down

0 comments on commit 6fb1a63

Please sign in to comment.