Skip to content

Commit

Permalink
expression, types: fix datetime and year comparison error (#20233)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ling Jin authored Dec 18, 2020
1 parent e9b11b7 commit b232a23
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 2 deletions.
8 changes: 7 additions & 1 deletion expression/builtin_cast.go
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,13 @@ func (b *builtinCastIntAsTimeSig) evalTime(row chunk.Row) (res types.Time, isNul
if isNull || err != nil {
return res, isNull, err
}
res, err = types.ParseTimeFromNum(b.ctx.GetSessionVars().StmtCtx, val, b.tp.Tp, int8(b.tp.Decimal))

if b.args[0].GetType().Tp == mysql.TypeYear {
res, err = types.ParseTimeFromYear(b.ctx.GetSessionVars().StmtCtx, val)
} else {
res, err = types.ParseTimeFromNum(b.ctx.GetSessionVars().StmtCtx, val, b.tp.Tp, int8(b.tp.Decimal))
}

if err != nil {
return types.ZeroTime, true, handleInvalidTimeError(b.ctx, err)
}
Expand Down
10 changes: 9 additions & 1 deletion expression/builtin_cast_vec.go
Original file line number Diff line number Diff line change
Expand Up @@ -376,11 +376,19 @@ func (b *builtinCastIntAsTimeSig) vecEvalTime(input *chunk.Chunk, result *chunk.
i64s := buf.Int64s()
stmt := b.ctx.GetSessionVars().StmtCtx
fsp := int8(b.tp.Decimal)

var tm types.Time
for i := 0; i < n; i++ {
if buf.IsNull(i) {
continue
}
tm, err := types.ParseTimeFromNum(stmt, i64s[i], b.tp.Tp, fsp)

if b.args[0].GetType().Tp == mysql.TypeYear {
tm, err = types.ParseTimeFromYear(stmt, i64s[i])
} else {
tm, err = types.ParseTimeFromNum(stmt, i64s[i], b.tp.Tp, fsp)
}

if err != nil {
if err = handleInvalidTimeError(b.ctx, err); err != nil {
return err
Expand Down
3 changes: 3 additions & 0 deletions expression/builtin_compare.go
Original file line number Diff line number Diff line change
Expand Up @@ -1059,6 +1059,9 @@ func getBaseCmpType(lhs, rhs types.EvalType, lft, rft *types.FieldType) types.Ev
} else if ((lhs == types.ETInt || lft.Hybrid()) || lhs == types.ETDecimal) &&
((rhs == types.ETInt || rft.Hybrid()) || rhs == types.ETDecimal) {
return types.ETDecimal
} else if types.IsTemporalWithDate(lft.Tp) && rft.Tp == mysql.TypeYear ||
lft.Tp == mysql.TypeYear && types.IsTemporalWithDate(rft.Tp) {
return types.ETDatetime
}
return types.ETReal
}
Expand Down
35 changes: 35 additions & 0 deletions expression/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7131,6 +7131,41 @@ func (s *testIntegrationSuite) TestIssue16505(c *C) {
tk.MustExec("drop table t;")
}

func (s *testIntegrationSuite) TestIssue20121(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("use test")
// testcase for Datetime vs Year
tk.MustExec("drop table if exists t")
tk.MustExec("create table t(a datetime, b year)")
tk.MustExec("insert into t values('2000-05-03 16:44:44', 2018)")
tk.MustExec("insert into t values('2020-10-01 11:11:11', 2000)")
tk.MustExec("insert into t values('2020-10-01 11:11:11', 2070)")
tk.MustExec("insert into t values('2020-10-01 11:11:11', 1999)")

tk.MustQuery("select * from t where t.a < t.b").Check(testkit.Rows("2000-05-03 16:44:44 2018", "2020-10-01 11:11:11 2070"))
tk.MustQuery("select * from t where t.a > t.b").Check(testkit.Rows("2020-10-01 11:11:11 2000", "2020-10-01 11:11:11 1999"))

// testcase for Date vs Year
tk.MustExec("drop table if exists tt")
tk.MustExec("create table tt(a date, b year)")
tk.MustExec("insert into tt values('2019-11-11', 2000)")
tk.MustExec("insert into tt values('2019-11-11', 2020)")
tk.MustExec("insert into tt values('2019-11-11', 2022)")

tk.MustQuery("select * from tt where tt.a > tt.b").Check(testkit.Rows("2019-11-11 2000"))
tk.MustQuery("select * from tt where tt.a < tt.b").Check(testkit.Rows("2019-11-11 2020", "2019-11-11 2022"))

// testcase for Timestamp vs Year
tk.MustExec("drop table if exists ttt")
tk.MustExec("create table ttt(a timestamp, b year)")
tk.MustExec("insert into ttt values('2019-11-11 11:11:11', 2019)")
tk.MustExec("insert into ttt values('2019-11-11 11:11:11', 2000)")
tk.MustExec("insert into ttt values('2019-11-11 11:11:11', 2022)")

tk.MustQuery("select * from ttt where ttt.a > ttt.b").Check(testkit.Rows("2019-11-11 11:11:11 2019", "2019-11-11 11:11:11 2000"))
tk.MustQuery("select * from ttt where ttt.a < ttt.b").Check(testkit.Rows("2019-11-11 11:11:11 2022"))
}

func (s *testIntegrationSuite) TestIssue16779(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("use test")
Expand Down
11 changes: 11 additions & 0 deletions types/time.go
Original file line number Diff line number Diff line change
Expand Up @@ -1950,6 +1950,17 @@ func ParseDate(sc *stmtctx.StatementContext, str string) (Time, error) {
return ParseTime(sc, str, mysql.TypeDate, MinFsp)
}

// ParseTimeFromYear parse a `YYYY` formed year to corresponded Datetime type.
// Note: the invoker must promise the `year` is in the range [MinYear, MaxYear].
func ParseTimeFromYear(sc *stmtctx.StatementContext, year int64) (Time, error) {
if year == 0 {
return NewTime(ZeroCoreTime, mysql.TypeDate, DefaultFsp), nil
}

dt := FromDate(int(year), 0, 0, 0, 0, 0, 0)
return NewTime(dt, mysql.TypeDatetime, DefaultFsp), nil
}

// ParseTimeFromNum parses a formatted int64,
// returns the value which type is tp.
func ParseTimeFromNum(sc *stmtctx.StatementContext, num int64, tp byte, fsp int8) (Time, error) {
Expand Down

0 comments on commit b232a23

Please sign in to comment.