From 5c877e6e50ba86027915f39b66536a343ee12d80 Mon Sep 17 00:00:00 2001 From: zhangstar333 <87313068+zhangstar333@users.noreply.github.com> Date: Fri, 29 Mar 2024 16:51:49 +0800 Subject: [PATCH] [bug](function) fix milliseconds_diff function return wrong result (#32897) * [bug](function) fix milliseconds_diff function return wrong result --- .../function_date_or_datetime_computation.h | 18 ++++++++++++++---- be/src/vec/runtime/vdatetime_value.h | 8 ++++---- .../date-time-functions/timediff.md | 11 +++++++++-- .../date-time-functions/timediff.md | 10 +++++++++- 4 files changed, 36 insertions(+), 11 deletions(-) diff --git a/be/src/vec/functions/function_date_or_datetime_computation.h b/be/src/vec/functions/function_date_or_datetime_computation.h index bca886df2adc74..609113a0bd5c6f 100644 --- a/be/src/vec/functions/function_date_or_datetime_computation.h +++ b/be/src/vec/functions/function_date_or_datetime_computation.h @@ -315,15 +315,25 @@ struct TimeDiffImpl { static constexpr auto name = "timediff"; static constexpr auto is_nullable = false; - static inline ReturnType ::FieldType execute(const ArgType1& t0, const ArgType2& t1, - bool& is_null) { + static constexpr int64_t limit_value = 3020399000000; // 838:59:59 convert to microsecond + static inline ReturnType::FieldType execute(const ArgType1& t0, const ArgType2& t1, + bool& is_null) { const auto& ts0 = reinterpret_cast(t0); const auto& ts1 = reinterpret_cast(t1); is_null = !ts0.is_valid_date() || !ts1.is_valid_date(); if constexpr (UsingTimev2) { - return ts0.microsecond_diff(ts1); + // refer to https://dev.mysql.com/doc/refman/5.7/en/time.html + // the time type value between '-838:59:59' and '838:59:59', so the return value should limited + int64_t diff_m = ts0.microsecond_diff(ts1); + if (diff_m > limit_value) { + return (double)limit_value; + } else if (diff_m < -1 * limit_value) { + return (double)(-1 * limit_value); + } else { + return (double)diff_m; + } } else { - return (1000 * 1000) * ts0.second_diff(ts1); + return (double)((1000 * 1000) * ts0.second_diff(ts1)); } } static DataTypes get_variadic_argument_types() { diff --git a/be/src/vec/runtime/vdatetime_value.h b/be/src/vec/runtime/vdatetime_value.h index e3ea87de1f2c39..416dea46d97f37 100644 --- a/be/src/vec/runtime/vdatetime_value.h +++ b/be/src/vec/runtime/vdatetime_value.h @@ -1111,13 +1111,13 @@ class DateV2Value { return (daynr() - rhs.daynr()) * SECOND_PER_HOUR * HOUR_PER_DAY + time_part_diff(rhs); } + // used by INT microseconds_diff(DATETIME enddate, DATETIME startdate) + // return it's int type, so shouldn't have any limit. + // when used by TIME TIMEDIFF(DATETIME expr1, DATETIME expr2), it's return time type, should have limited. template - double microsecond_diff(const RHS& rhs) const { + int64_t microsecond_diff(const RHS& rhs) const { int64_t diff_m = (daynr() - rhs.daynr()) * SECOND_PER_HOUR * HOUR_PER_DAY * 1000 * 1000 + time_part_diff_microsecond(rhs); - if (diff_m > (int64_t)3020399 * 1000 * 1000) { - diff_m = (int64_t)3020399 * 1000 * 1000; - } return diff_m; } diff --git a/docs/en/docs/sql-manual/sql-functions/date-time-functions/timediff.md b/docs/en/docs/sql-manual/sql-functions/date-time-functions/timediff.md index 156fb49de73255..505b2197b4eede 100644 --- a/docs/en/docs/sql-manual/sql-functions/date-time-functions/timediff.md +++ b/docs/en/docs/sql-manual/sql-functions/date-time-functions/timediff.md @@ -34,8 +34,8 @@ under the License. TIMEDIFF returns the difference between two DATETIMEs The TIMEDIFF function returns the result of expr1 - expr2 expressed as a time value, with a return value of TIME type - -The results are limited to TIME values ranging from - 838:59:59 to 838:59:59. +Due to the valid range of TIME type being '-838:59:59' to '838:59:59', +So when the return value of the calculation result is less than the left boundary or greater than the right boundary, the corresponding boundary value will be taken. #### example @@ -60,6 +60,13 @@ mysql> SELECT TIMEDIFF('2019-01-01 00:00:00', NULL); +---------------------------------------+ | NULL | +---------------------------------------+ + +mysql >SELECT timediff('2020-02-02 15:30:00', '1951-02-16 15:27:00') as res; ++-----------+ +| res | ++-----------+ +| 838:59:59 | ++-----------+ ``` ### keywords TIMEDIFF diff --git a/docs/zh-CN/docs/sql-manual/sql-functions/date-time-functions/timediff.md b/docs/zh-CN/docs/sql-manual/sql-functions/date-time-functions/timediff.md index c1d1a107d5295e..7fd018a3f495db 100644 --- a/docs/zh-CN/docs/sql-manual/sql-functions/date-time-functions/timediff.md +++ b/docs/zh-CN/docs/sql-manual/sql-functions/date-time-functions/timediff.md @@ -33,7 +33,8 @@ under the License. TIMEDIFF返回两个DATETIME之间的差值 -TIMEDIFF函数返回表示为时间值的expr1 - expr2的结果,返回值为TIME类型 +TIMEDIFF函数返回表示为时间值的expr1 - expr2的结果,返回值为TIME类型, 由于TIME类型的合法有效范围为'-838:59:59' to '838:59:59', +所以当计算结果的返回值小于左边界或大于右边界时,会取对应的边界值. ### example @@ -58,6 +59,13 @@ mysql> SELECT TIMEDIFF('2019-01-01 00:00:00', NULL); +---------------------------------------+ | NULL | +---------------------------------------+ + +mysql >SELECT timediff('2020-02-02 15:30:00', '1951-02-16 15:27:00') as res; ++-----------+ +| res | ++-----------+ +| 838:59:59 | ++-----------+ ``` ### keywords