Skip to content

Commit

Permalink
This is an automated cherry-pick of pingcap#53101
Browse files Browse the repository at this point in the history
Signed-off-by: ti-chi-bot <[email protected]>
  • Loading branch information
xzhangxian1008 authored and ti-chi-bot committed May 21, 2024
1 parent a36abf3 commit 852fcf9
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 0 deletions.
86 changes: 86 additions & 0 deletions expression/builtin_time.go
Original file line number Diff line number Diff line change
Expand Up @@ -6948,6 +6948,92 @@ func (b *builtinTimestampAddSig) Clone() builtinFunc {
return newSig
}

<<<<<<< HEAD:expression/builtin_time.go
=======
var (
minDatetimeInGoTime, _ = types.MinDatetime.GoTime(time.Local)
minDatetimeNanos = float64(minDatetimeInGoTime.Unix())*1e9 + float64(minDatetimeInGoTime.Nanosecond())
maxDatetimeInGoTime, _ = types.MaxDatetime.GoTime(time.Local)
maxDatetimeNanos = float64(maxDatetimeInGoTime.Unix())*1e9 + float64(maxDatetimeInGoTime.Nanosecond())
minDatetimeMonths = float64(types.MinDatetime.Year()*12 + types.MinDatetime.Month() - 1) // 0001-01-01 00:00:00
maxDatetimeMonths = float64(types.MaxDatetime.Year()*12 + types.MaxDatetime.Month() - 1) // 9999-12-31 00:00:00
)

func validAddTime(nano1 float64, nano2 float64) bool {
return nano1+nano2 >= minDatetimeNanos && nano1+nano2 <= maxDatetimeNanos
}

func validAddMonth(month1 float64, year, month int) bool {
tmp := month1 + float64(year)*12 + float64(month-1)
return tmp >= minDatetimeMonths && tmp <= maxDatetimeMonths
}

func addUnitToTime(unit string, t time.Time, v float64) (time.Time, bool, error) {
s := math.Trunc(v * 1000000)
// round to the nearest int
v = math.Round(v)
var tb time.Time
nano := float64(t.Unix())*1e9 + float64(t.Nanosecond())
switch unit {
case "MICROSECOND":
if !validAddTime(v*float64(time.Microsecond), nano) {
return tb, true, nil
}
tb = t.Add(time.Duration(v) * time.Microsecond)
case "SECOND":
if !validAddTime(s*float64(time.Microsecond), nano) {
return tb, true, nil
}
tb = t.Add(time.Duration(s) * time.Microsecond)
case "MINUTE":
if !validAddTime(v*float64(time.Minute), nano) {
return tb, true, nil
}
tb = t.Add(time.Duration(v) * time.Minute)
case "HOUR":
if !validAddTime(v*float64(time.Hour), nano) {
return tb, true, nil
}
tb = t.Add(time.Duration(v) * time.Hour)
case "DAY":
if !validAddTime(v*24*float64(time.Hour), nano) {
return tb, true, nil
}
tb = t.AddDate(0, 0, int(v))
case "WEEK":
if !validAddTime(v*24*7*float64(time.Hour), nano) {
return tb, true, nil
}
tb = t.AddDate(0, 0, 7*int(v))
case "MONTH":
if !validAddMonth(v, t.Year(), int(t.Month())) {
return tb, true, nil
}
tb = t.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(t.Month())+int(v))%12 {
tb = tb.AddDate(0, 0, -1)
}
case "QUARTER":
if !validAddMonth(v*3, t.Year(), int(t.Month())) {
return tb, true, nil
}
tb = t.AddDate(0, 3*int(v), 0)
case "YEAR":
if !validAddMonth(v*12, t.Year(), int(t.Month())) {
return tb, true, nil
}
tb = t.AddDate(int(v), 0, 0)
default:
return tb, false, types.ErrWrongValue.GenWithStackByArgs(types.TimeStr, unit)
}
return tb, false, nil
}

>>>>>>> 536cf0068bc (expression: wrong result of timestampadd(month,1,date '2024-01-31') (#53101)):pkg/expression/builtin_time.go
// evalString evals a builtinTimestampAddSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_timestampadd
func (b *builtinTimestampAddSig) evalString(row chunk.Row) (string, bool, error) {
Expand Down
26 changes: 26 additions & 0 deletions expression/builtin_time_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2497,6 +2497,32 @@ 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, ""},
<<<<<<< HEAD:expression/builtin_time_test.go
=======
{"QUARTER", 3, "1995-05-01", "1996-02-01 00:00:00"},
{"SECOND", 1.1, "1995-05-01", "1995-05-01 00:00:01.100000"},
{"SECOND", -1, "1995-05-01", "1995-04-30 23:59:59"},
{"SECOND", -1.1, "1995-05-01", "1995-04-30 23:59:58.900000"},
{"SECOND", 9.9999e-6, "1995-05-01", "1995-05-01 00:00:00.000009"},
{"SECOND", 9.9999e-7, "1995-05-01", "1995-05-01 00:00:00"},
{"SECOND", -9.9999e-6, "1995-05-01", "1995-04-30 23:59:59.999991"},
{"SECOND", -9.9999e-7, "1995-05-01", "1995-05-01 00:00:00"},
{"MINUTE", 1.5, "1995-05-01 00:00:00", "1995-05-01 00:02:00"},
{"MINUTE", 1.5, "1995-05-01 00:00:00.000000", "1995-05-01 00:02:00"},
{"MICROSECOND", -100, "1995-05-01 00:00:00.0001", "1995-05-01 00:00:00"},

// 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"},
>>>>>>> 536cf0068bc (expression: wrong result of timestampadd(month,1,date '2024-01-31') (#53101)):pkg/expression/builtin_time_test.go
}

fc := funcs[ast.TimestampAdd]
Expand Down

0 comments on commit 852fcf9

Please sign in to comment.