Skip to content

Commit

Permalink
expression: wrong result of timestampadd(month,1,date '2024-01-31') (p…
Browse files Browse the repository at this point in the history
  • Loading branch information
ti-chi-bot authored May 22, 2024
1 parent 7ee9048 commit dce26c2
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 6 deletions.
19 changes: 13 additions & 6 deletions expression/builtin_time.go
Original file line number Diff line number Diff line change
Expand Up @@ -6969,6 +6969,13 @@ func (b *builtinTimestampAddSig) evalString(row chunk.Row) (string, bool, error)
tb = tm1.AddDate(0, 0, 7*int(v))
case "MONTH":
tb = tm1.AddDate(0, int(v), 0)

// For corner case: timestampadd(month,1,date '2024-01-31') = "2024-02-29", timestampadd(month,1,date '2024-01-30') = "2024-02-29"
// `tb.Month()` refers to the actual result, `t.Month()+v` refers to the expect result.
// Actual result may be greater than expect result, we need to judge and modify it.
for int(tb.Month())%12 != (int(tm1.Month())+int(v))%12 {
tb = tb.AddDate(0, 0, -1)
}
case "QUARTER":
tb = tm1.AddDate(0, 3*int(v), 0)
case "YEAR":
Expand Down Expand Up @@ -7381,12 +7388,12 @@ func CalAppropriateTime(minTime, maxTime, minSafeTime time.Time) time.Time {
}

// For a SafeTS t and a time range [t1, t2]:
// 1. If t < t1, we will use t1 as the result,
// and with it, a read request may fail because it's an unreached SafeTS.
// 2. If t1 <= t <= t2, we will use t as the result, and with it,
// a read request won't fail.
// 2. If t2 < t, we will use t2 as the result,
// and with it, a read request won't fail because it's bigger than the latest SafeTS.
// 1. If t < t1, we will use t1 as the result,
// and with it, a read request may fail because it's an unreached SafeTS.
// 2. If t1 <= t <= t2, we will use t as the result, and with it,
// a read request won't fail.
// 2. If t2 < t, we will use t2 as the result,
// and with it, a read request won't fail because it's bigger than the latest SafeTS.
func calAppropriateTime(minTime, maxTime, minSafeTime time.Time) time.Time {
if minSafeTime.Before(minTime) || minSafeTime.After(maxTime) {
logutil.BgLogger().Warn("calAppropriateTime",
Expand Down
12 changes: 12 additions & 0 deletions expression/builtin_time_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2492,6 +2492,18 @@ func TestTimestampAdd(t *testing.T) {
{"WEEK", 1, "2003-01-02 23:59:59", "2003-01-09 23:59:59"},
{"MICROSECOND", 1, 950501, "1995-05-01 00:00:00.000001"},
{"DAY", 28768, 0, ""},

// issue41052
{"MONTH", 1, "2024-01-31", "2024-02-29 00:00:00"},
{"MONTH", 1, "2024-01-30", "2024-02-29 00:00:00"},
{"MONTH", 1, "2024-01-29", "2024-02-29 00:00:00"},
{"MONTH", 1, "2024-01-28", "2024-02-28 00:00:00"},
{"MONTH", 1, "2024-10-31", "2024-11-30 00:00:00"},
{"MONTH", 3, "2024-01-31", "2024-04-30 00:00:00"},
{"MONTH", 15, "2024-01-31", "2025-04-30 00:00:00"},
{"MONTH", 10, "2024-10-31", "2025-08-31 00:00:00"},
{"MONTH", 1, "2024-11-30", "2024-12-30 00:00:00"},
{"MONTH", 13, "2024-11-30", "2025-12-30 00:00:00"},
}

fc := funcs[ast.TimestampAdd]
Expand Down

0 comments on commit dce26c2

Please sign in to comment.