From 9ce91e4518cb838c0ac2dc7b994cb5ddbdfd6d9f Mon Sep 17 00:00:00 2001 From: cryo Date: Tue, 30 Dec 2025 21:09:38 +0800 Subject: [PATCH] expression: fix handling of zero month/day in DATE function (#65150) close pingcap/tidb#59417 --- pkg/expression/builtin_time.go | 4 ++ pkg/expression/builtin_time_vec.go | 15 ++++-- .../integration_test/integration_test.go | 2 +- .../r/expression/builtin.result | 50 +++++++++++++++++++ .../integrationtest/t/expression/builtin.test | 19 +++++++ tests/llmtest/testdata/expression.json | 6 +-- 6 files changed, 89 insertions(+), 7 deletions(-) diff --git a/pkg/expression/builtin_time.go b/pkg/expression/builtin_time.go index 22e8ca4dee..b6f12305d8 100644 --- a/pkg/expression/builtin_time.go +++ b/pkg/expression/builtin_time.go @@ -310,6 +310,10 @@ func (b *builtinDateSig) evalTime(ctx EvalContext, row chunk.Row) (types.Time, b if expr.IsZero() && sqlMode(ctx).HasNoZeroDateMode() { return types.ZeroTime, true, handleInvalidTimeError(ctx, types.ErrWrongValue.GenWithStackByArgs(types.DateTimeStr, expr.String())) } + // for issue 59417, should return NULL when month or day is zero and sql_mode contains NO_ZERO_IN_DATE + if !expr.IsZero() && expr.InvalidZero() && sqlMode(ctx).HasNoZeroInDateMode() { + return types.ZeroTime, true, handleInvalidTimeError(ctx, types.ErrWrongValue.GenWithStackByArgs(types.DateTimeStr, expr.String())) + } expr.SetCoreTime(types.FromDate(expr.Year(), expr.Month(), expr.Day(), 0, 0, 0, 0)) expr.SetType(mysql.TypeDate) diff --git a/pkg/expression/builtin_time_vec.go b/pkg/expression/builtin_time_vec.go index 81966a9c48..c1e570d4ce 100644 --- a/pkg/expression/builtin_time_vec.go +++ b/pkg/expression/builtin_time_vec.go @@ -99,10 +99,19 @@ func (b *builtinDateSig) vecEvalTime(ctx EvalContext, input *chunk.Chunk, result return err } result.SetNull(i, true) - } else { - times[i].SetCoreTime(types.FromDate(times[i].Year(), times[i].Month(), times[i].Day(), 0, 0, 0, 0)) - times[i].SetType(mysql.TypeDate) + continue } + // for issue 59417, should return NULL when month or day is zero and sql_mode contains NO_ZERO_IN_DATE + if !times[i].IsZero() && times[i].InvalidZero() && sqlMode(ctx).HasNoZeroInDateMode() { + if err := handleInvalidTimeError(ctx, types.ErrWrongValue.GenWithStackByArgs(types.DateTimeStr, times[i].String())); err != nil { + return err + } + result.SetNull(i, true) + continue + } + + times[i].SetCoreTime(types.FromDate(times[i].Year(), times[i].Month(), times[i].Day(), 0, 0, 0, 0)) + times[i].SetType(mysql.TypeDate) } return nil } diff --git a/pkg/expression/integration_test/integration_test.go b/pkg/expression/integration_test/integration_test.go index e9bb3103d8..3f7309d141 100644 --- a/pkg/expression/integration_test/integration_test.go +++ b/pkg/expression/integration_test/integration_test.go @@ -2832,7 +2832,7 @@ func TestTimeBuiltin(t *testing.T) { result = tk.MustQuery(`select date("2019-09-12"), date("2019-09-12 12:12:09"), date("2019-09-12 12:12:09.121212");`) result.Check(testkit.Rows("2019-09-12 2019-09-12 2019-09-12")) result = tk.MustQuery(`select date("0000-00-00"), date("0000-00-00 12:12:09"), date("0000-00-00 00:00:00.121212"), date("0000-00-00 00:00:00.000000");`) - result.Check(testkit.Rows(" 0000-00-00 0000-00-00 ")) + result.Check(testkit.Rows(" ")) result = tk.MustQuery(`select date("aa"), date(12.1), date("");`) result.Check(testkit.Rows(" ")) diff --git a/tests/integrationtest/r/expression/builtin.result b/tests/integrationtest/r/expression/builtin.result index 59c612eda1..48e5a70650 100644 --- a/tests/integrationtest/r/expression/builtin.result +++ b/tests/integrationtest/r/expression/builtin.result @@ -3418,3 +3418,53 @@ SELECT UTC_TIMESTAMP(2147483647); Error 1426 (42000): Too-big precision 2147483647 specified for 'utc_timestamp'. Maximum is 6. SELECT UTC_TIMESTAMP(2147483648); Error 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your TiDB version for the right syntax to use +set sql_mode = 'NO_ZERO_IN_DATE'; +select date(0), date('0000-00-00'); +date(0) date('0000-00-00') +0000-00-00 0000-00-00 +show warnings; +Level Code Message +select date('0000-00-01'), date('0000-12-00'), date('2024-00-00'); +date('0000-00-01') date('0000-12-00') date('2024-00-00') +NULL NULL NULL +show warnings; +Level Code Message +Warning 1292 Incorrect datetime value: '0000-00-01 00:00:00.000000' +Warning 1292 Incorrect datetime value: '0000-12-00 00:00:00.000000' +Warning 1292 Incorrect datetime value: '2024-00-00 00:00:00.000000' +select date('0000-12-01'), date('2024-00-01'), date('2024-12-00'); +date('0000-12-01') date('2024-00-01') date('2024-12-00') +0000-12-01 NULL NULL +show warnings; +Level Code Message +Warning 1292 Incorrect datetime value: '2024-00-01 00:00:00.000000' +Warning 1292 Incorrect datetime value: '2024-12-00 00:00:00.000000' +select date('2024-12-01'); +date('2024-12-01') +2024-12-01 +show warnings; +Level Code Message +drop table if exists t; +create table t(test_date DATETIME); +SET sql_mode = ''; +INSERT INTO t VALUES (0),('0000-00-00'),('0000-00-01'),('0000-12-00'),('2024-00-00'),('0000-12-01'),('2024-00-01'),('2024-12-00'),('2024-12-01'); +SET sql_mode = 'NO_ZERO_IN_DATE'; +SELECT DATE(test_date) FROM t; +DATE(test_date) +0000-00-00 +0000-00-00 +NULL +NULL +NULL +0000-12-01 +NULL +NULL +2024-12-01 +show warnings; +Level Code Message +Warning 1292 Incorrect datetime value: '0000-00-01 00:00:00' +Warning 1292 Incorrect datetime value: '0000-12-00 00:00:00' +Warning 1292 Incorrect datetime value: '2024-00-00 00:00:00' +Warning 1292 Incorrect datetime value: '2024-00-01 00:00:00' +Warning 1292 Incorrect datetime value: '2024-12-00 00:00:00' +drop table if exists t; diff --git a/tests/integrationtest/t/expression/builtin.test b/tests/integrationtest/t/expression/builtin.test index 733cf7940e..46dc9d9850 100644 --- a/tests/integrationtest/t/expression/builtin.test +++ b/tests/integrationtest/t/expression/builtin.test @@ -1649,3 +1649,22 @@ SELECT UTC_TIMESTAMP(-1); SELECT UTC_TIMESTAMP(2147483647); -- error 1064 SELECT UTC_TIMESTAMP(2147483648); + +# Issue 59417 +set sql_mode = 'NO_ZERO_IN_DATE'; +select date(0), date('0000-00-00'); +show warnings; +select date('0000-00-01'), date('0000-12-00'), date('2024-00-00'); +show warnings; +select date('0000-12-01'), date('2024-00-01'), date('2024-12-00'); +show warnings; +select date('2024-12-01'); +show warnings; +drop table if exists t; +create table t(test_date DATETIME); +SET sql_mode = ''; +INSERT INTO t VALUES (0),('0000-00-00'),('0000-00-01'),('0000-12-00'),('2024-00-00'),('0000-12-01'),('2024-00-01'),('2024-12-00'),('2024-12-01'); +SET sql_mode = 'NO_ZERO_IN_DATE'; +SELECT DATE(test_date) FROM t; +show warnings; +drop table if exists t; \ No newline at end of file diff --git a/tests/llmtest/testdata/expression.json b/tests/llmtest/testdata/expression.json index ec814c01b0..14c2b5524a 100644 --- a/tests/llmtest/testdata/expression.json +++ b/tests/llmtest/testdata/expression.json @@ -12401,9 +12401,9 @@ { "sql": "SELECT DATE('2024-00-15')", "args": null, - "pass": false, - "known": true, - "comment": "https://github.com/pingcap/tidb/issues/59417" + "pass": true, + "known": false, + "comment": "" }, { "sql": "SELECT DATE('2023-02-29')",