From cbed6e78614f89f8fea60ffc205c5bca9519f8ac Mon Sep 17 00:00:00 2001 From: xzhangxian1008 Date: Wed, 8 May 2024 13:21:44 +0800 Subject: [PATCH 1/5] fix and add tests --- pkg/expression/builtin_time.go | 5 +++++ pkg/expression/builtin_time_test.go | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/pkg/expression/builtin_time.go b/pkg/expression/builtin_time.go index 62b7cfba02285..76422b33bf714 100644 --- a/pkg/expression/builtin_time.go +++ b/pkg/expression/builtin_time.go @@ -6232,6 +6232,11 @@ func addUnitToTime(unit string, t time.Time, v float64) (time.Time, bool, error) 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" + for tb.Month() != t.Month()+1 { + tb = tb.AddDate(0, 0, -1) + } case "QUARTER": if !validAddMonth(v*3, t.Year(), int(t.Month())) { return tb, true, nil diff --git a/pkg/expression/builtin_time_test.go b/pkg/expression/builtin_time_test.go index 93e2f8918a641..86afcbf3a1bb8 100644 --- a/pkg/expression/builtin_time_test.go +++ b/pkg/expression/builtin_time_test.go @@ -2580,6 +2580,13 @@ func TestTimestampAdd(t *testing.T) { {"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"}, } fc := funcs[ast.TimestampAdd] From 8b6b41044b228b227632bece2d1933489b9b51a4 Mon Sep 17 00:00:00 2001 From: xzhangxian1008 Date: Thu, 9 May 2024 14:07:38 +0800 Subject: [PATCH 2/5] more fix --- pkg/expression/builtin_time.go | 2 +- pkg/expression/builtin_time_test.go | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/expression/builtin_time.go b/pkg/expression/builtin_time.go index 76422b33bf714..67d79820fbc48 100644 --- a/pkg/expression/builtin_time.go +++ b/pkg/expression/builtin_time.go @@ -6234,7 +6234,7 @@ func addUnitToTime(unit string, t time.Time, v float64) (time.Time, bool, error) 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" - for tb.Month() != t.Month()+1 { + for int(tb.Month()) != (int(t.Month())+int(v))%12 { tb = tb.AddDate(0, 0, -1) } case "QUARTER": diff --git a/pkg/expression/builtin_time_test.go b/pkg/expression/builtin_time_test.go index 86afcbf3a1bb8..a22830babfcdf 100644 --- a/pkg/expression/builtin_time_test.go +++ b/pkg/expression/builtin_time_test.go @@ -2587,6 +2587,9 @@ func TestTimestampAdd(t *testing.T) { {"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"}, } fc := funcs[ast.TimestampAdd] From 3b3d253169f45288627e024d2d9f96a201699bd8 Mon Sep 17 00:00:00 2001 From: xzhangxian1008 Date: Thu, 9 May 2024 16:53:01 +0800 Subject: [PATCH 3/5] fix --- pkg/expression/builtin_time.go | 3 ++- pkg/expression/builtin_time_test.go | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/expression/builtin_time.go b/pkg/expression/builtin_time.go index 67d79820fbc48..846c9925ee0b4 100644 --- a/pkg/expression/builtin_time.go +++ b/pkg/expression/builtin_time.go @@ -6234,7 +6234,8 @@ func addUnitToTime(unit string, t time.Time, v float64) (time.Time, bool, error) 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" - for int(tb.Month()) != (int(t.Month())+int(v))%12 { + for int(tb.Month())%12 != (int(t.Month())+int(v))%12 { + time.Sleep(10 * time.Millisecond) tb = tb.AddDate(0, 0, -1) } case "QUARTER": diff --git a/pkg/expression/builtin_time_test.go b/pkg/expression/builtin_time_test.go index a22830babfcdf..f251301e3504a 100644 --- a/pkg/expression/builtin_time_test.go +++ b/pkg/expression/builtin_time_test.go @@ -2590,6 +2590,8 @@ func TestTimestampAdd(t *testing.T) { {"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] From 4c5ebb2f38343af4aa24d9f71848c0d8aec593c1 Mon Sep 17 00:00:00 2001 From: xzhangxian1008 Date: Fri, 10 May 2024 10:31:23 +0800 Subject: [PATCH 4/5] remove useless codes --- pkg/expression/builtin_time.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/expression/builtin_time.go b/pkg/expression/builtin_time.go index 846c9925ee0b4..980a241e21a5e 100644 --- a/pkg/expression/builtin_time.go +++ b/pkg/expression/builtin_time.go @@ -6235,7 +6235,6 @@ func addUnitToTime(unit string, t time.Time, v float64) (time.Time, bool, error) // For corner case: timestampadd(month,1,date '2024-01-31') = "2024-02-29", timestampadd(month,1,date '2024-01-30') = "2024-02-29" for int(tb.Month())%12 != (int(t.Month())+int(v))%12 { - time.Sleep(10 * time.Millisecond) tb = tb.AddDate(0, 0, -1) } case "QUARTER": From 4e080f5f7d2711abc01532efb3969d6b42a2c6cc Mon Sep 17 00:00:00 2001 From: xzhangxian1008 Date: Fri, 10 May 2024 10:57:40 +0800 Subject: [PATCH 5/5] add comment --- pkg/expression/builtin_time.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/expression/builtin_time.go b/pkg/expression/builtin_time.go index 980a241e21a5e..7b1d0d6527e3f 100644 --- a/pkg/expression/builtin_time.go +++ b/pkg/expression/builtin_time.go @@ -6234,6 +6234,8 @@ func addUnitToTime(unit string, t time.Time, v float64) (time.Time, bool, error) 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) }