This is an automated email from the ASF dual-hosted git repository. morningman pushed a commit to branch branch-1.2-lts in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-1.2-lts by this push: new eb22e5e8d7 Fixed datetime-diff overflow bug. (#17141) eb22e5e8d7 is described below commit eb22e5e8d73728670aea699e1be56f9ac3e37639 Author: ZhaoChangle <zhaochan...@selectdb.com> AuthorDate: Sun Feb 26 21:25:07 2023 +0800 Fixed datetime-diff overflow bug. (#17141) cherry-pick #16935 --- .../function_date_or_datetime_computation.h | 8 +++- be/src/vec/runtime/vdatetime_value.cpp | 12 +---- be/src/vec/runtime/vdatetime_value.h | 55 ++++++++++------------ .../datetime_functions/test_time_diff.out | 19 ++++++++ .../datetime_functions/test_time_diff.groovy | 25 ++++++++++ 5 files changed, 78 insertions(+), 41 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 d98f47248e..c60263f758 100644 --- a/be/src/vec/functions/function_date_or_datetime_computation.h +++ b/be/src/vec/functions/function_date_or_datetime_computation.h @@ -17,6 +17,8 @@ #pragma once +#include <cstdint> + #include "common/logging.h" #include "fmt/format.h" #include "runtime/datetime_value.h" @@ -238,7 +240,8 @@ struct SubtractYearsImpl : SubtractIntervalImpl<AddYearsImpl<DateType>, DateType using ReturnType = RETURN_TYPE; \ static constexpr auto name = #FN_NAME; \ static constexpr auto is_nullable = false; \ - static inline Int32 execute(const ArgType1& t0, const ArgType2& t1, bool& is_null) { \ + static inline ReturnType::FieldType execute(const ArgType1& t0, const ArgType2& t1, \ + bool& is_null) { \ const auto& ts0 = reinterpret_cast<const DateValueType1&>(t0); \ const auto& ts1 = reinterpret_cast<const DateValueType2&>(t1); \ is_null = !ts0.is_valid_date() || !ts1.is_valid_date(); \ @@ -275,7 +278,8 @@ TIME_DIFF_FUNCTION_IMPL(SecondsDiffImpl, seconds_diff, SECOND); using ReturnType = DataTypeInt32; \ static constexpr auto name = #NAME; \ static constexpr auto is_nullable = false; \ - static inline int64_t execute(const ArgType& t0, const Int32 mode, bool& is_null) { \ + static inline ReturnType::FieldType execute(const ArgType& t0, const Int32 mode, \ + bool& is_null) { \ const auto& ts0 = reinterpret_cast<const DateValueType&>(t0); \ is_null = !ts0.is_valid_date(); \ return ts0.FUNCTION; \ diff --git a/be/src/vec/runtime/vdatetime_value.cpp b/be/src/vec/runtime/vdatetime_value.cpp index 378ed79556..d5086ab6b0 100644 --- a/be/src/vec/runtime/vdatetime_value.cpp +++ b/be/src/vec/runtime/vdatetime_value.cpp @@ -1529,14 +1529,6 @@ bool VecDateTimeValue::from_date_format_str(const char* format, int format_len, return check_range_and_set_time(year, month, day, hour, minute, second, _type); } -template <typename T> -int64_t VecDateTimeValue::second_diff(const DateV2Value<T>& rhs) const { - int day_diff = daynr() - rhs.daynr(); - int time_diff = (hour() * 3600 + minute() * 60 + second()) - - (rhs.hour() * 3600 + rhs.minute() * 60 + rhs.second()); - return day_diff * 3600 * 24 + time_diff; -} - template <TimeUnit unit> bool VecDateTimeValue::date_add_interval(const TimeInterval& interval) { if (!is_valid_date()) return false; @@ -3346,9 +3338,9 @@ template void VecDateTimeValue::create_from_date_v2<DateV2ValueType>( template void VecDateTimeValue::create_from_date_v2<DateTimeV2ValueType>( DateV2Value<DateTimeV2ValueType>& value, TimeType type); -template int64_t VecDateTimeValue::second_diff<DateV2ValueType>( +template int64_t VecDateTimeValue::second_diff<DateV2Value<DateV2ValueType>>( const DateV2Value<DateV2ValueType>& rhs) const; -template int64_t VecDateTimeValue::second_diff<DateTimeV2ValueType>( +template int64_t VecDateTimeValue::second_diff<DateV2Value<DateTimeV2ValueType>>( const DateV2Value<DateTimeV2ValueType>& rhs) const; #define DELARE_DATE_ADD_INTERVAL(DateValueType1, DateValueType2) \ diff --git a/be/src/vec/runtime/vdatetime_value.h b/be/src/vec/runtime/vdatetime_value.h index dd8c12cec2..0db31dae20 100644 --- a/be/src/vec/runtime/vdatetime_value.h +++ b/be/src/vec/runtime/vdatetime_value.h @@ -21,6 +21,7 @@ #include <stdint.h> #include <chrono> +#include <climits> #include <cstddef> #include <iostream> @@ -142,6 +143,10 @@ const int TIME_MAX_SECOND = 59; const int TIME_MAX_VALUE = 10000 * TIME_MAX_HOUR + 100 * TIME_MAX_MINUTE + TIME_MAX_SECOND; const int TIME_MAX_VALUE_SECONDS = 3600 * TIME_MAX_HOUR + 60 * TIME_MAX_MINUTE + TIME_MAX_SECOND; +constexpr int HOUR_PER_DAY = 24; +constexpr int64_t SECOND_PER_HOUR = 3600; +constexpr int64_t SECOND_PER_MINUTE = 60; + constexpr size_t const_length(const char* str) { return (str == nullptr || *str == 0) ? 0 : const_length(str + 1) + 1; } @@ -384,7 +389,7 @@ public: return true; }; - uint64_t daynr() const { return calc_daynr(_year, _month, _day); } + int32_t daynr() const { return calc_daynr(_year, _month, _day); } int year() const { return _year; } int month() const { return _month; } @@ -395,6 +400,9 @@ public: int minute() const { return _minute; } int second() const { return _second; } int neg() const { return _neg; } + int64_t time_part_to_seconds() const { + return _hour * SECOND_PER_HOUR + _minute * SECOND_PER_MINUTE + _second; + } bool check_loss_accuracy_cast_to_date() { auto loss_accuracy = _hour != 0 || _minute != 0 || _second != 0; @@ -608,20 +616,14 @@ public: return _s_max_datetime_value; } - int64_t second_diff(const VecDateTimeValue& rhs) const { - int day_diff = daynr() - rhs.daynr(); - int time_diff = (hour() * 3600 + minute() * 60 + second()) - - (rhs.hour() * 3600 + rhs.minute() * 60 + rhs.second()); - return day_diff * 3600 * 24 + time_diff; + template <typename T> + int64_t time_part_diff(const T& rhs) const { + return time_part_to_seconds() - rhs.time_part_to_seconds(); } template <typename T> - int64_t second_diff(const DateV2Value<T>& rhs) const; - - int64_t time_part_diff(const VecDateTimeValue& rhs) const { - int time_diff = (hour() * 3600 + minute() * 60 + second()) - - (rhs.hour() * 3600 + rhs.minute() * 60 + rhs.second()); - return time_diff; + int64_t second_diff(const T& rhs) const { + return (daynr() - rhs.daynr()) * SECOND_PER_HOUR * HOUR_PER_DAY + time_part_diff(rhs); } void set_type(int type); @@ -728,8 +730,7 @@ template <typename T> class DateV2Value { public: static constexpr bool is_datetime = std::is_same_v<T, DateTimeV2ValueType>; - using underlying_value = - std::conditional_t<std::is_same_v<T, DateTimeV2ValueType>, uint64_t, uint32_t>; + using underlying_value = std::conditional_t<is_datetime, uint64_t, uint32_t>; // Constructor DateV2Value<T>() : date_v2_value_(0, 0, 0, 0, 0, 0, 0) {} @@ -838,7 +839,7 @@ public: return true; }; - uint32_t daynr() const { + int32_t daynr() const { return calc_daynr(date_v2_value_.year_, date_v2_value_.month_, date_v2_value_.day_); } @@ -874,6 +875,10 @@ public: } } + int64_t time_part_to_seconds() const { + return hour() * SECOND_PER_HOUR + minute() * SECOND_PER_MINUTE + second(); + } + uint16_t year() const { return date_v2_value_.year_; } uint8_t month() const { return date_v2_value_.month_; } int quarter() const { return (date_v2_value_.month_ - 1) / 3 + 1; } @@ -1063,23 +1068,15 @@ public: } } + //only calculate the diff of dd:mm:ss template <typename RHS> - int64_t second_diff(const DateV2Value<RHS>& rhs) const { - int day_diff = daynr() - rhs.daynr(); - return day_diff * 3600 * 24 + (hour() * 3600 + minute() * 60 + second()) - - (rhs.hour() * 3600 + rhs.minute() * 60 + rhs.second()); + int64_t time_part_diff(const RHS& rhs) const { + return time_part_to_seconds() - rhs.time_part_to_seconds(); } - int64_t second_diff(const VecDateTimeValue& rhs) const { - int day_diff = daynr() - rhs.daynr(); - return day_diff * 3600 * 24 + (hour() * 3600 + minute() * 60 + second()) - - (rhs.hour() * 3600 + rhs.minute() * 60 + rhs.second()); - }; - - int64_t time_part_diff(const VecDateTimeValue& rhs) const { - int time_diff = (hour() * 3600 + minute() * 60 + second()) - - (rhs.hour() * 3600 + rhs.minute() * 60 + rhs.second()); - return time_diff; + template <typename RHS> + int64_t second_diff(const RHS& rhs) const { + return (daynr() - rhs.daynr()) * SECOND_PER_HOUR * HOUR_PER_DAY + time_part_diff(rhs); } bool can_cast_to_date_without_loss_accuracy() { diff --git a/regression-test/data/query_p0/sql_functions/datetime_functions/test_time_diff.out b/regression-test/data/query_p0/sql_functions/datetime_functions/test_time_diff.out new file mode 100644 index 0000000000..972698e802 --- /dev/null +++ b/regression-test/data/query_p0/sql_functions/datetime_functions/test_time_diff.out @@ -0,0 +1,19 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !sql -- +36270723 + +-- !sql -- +35745123 + +-- !sql -- +63093603 + +-- !sql -- +62412288 + +-- !sql -- +34711459380 + +-- !sql -- +63113904000 + diff --git a/regression-test/suites/query_p0/sql_functions/datetime_functions/test_time_diff.groovy b/regression-test/suites/query_p0/sql_functions/datetime_functions/test_time_diff.groovy new file mode 100644 index 0000000000..bd159f2892 --- /dev/null +++ b/regression-test/suites/query_p0/sql_functions/datetime_functions/test_time_diff.groovy @@ -0,0 +1,25 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +suite("test_time_diff") { + qt_sql """SELECT minutes_diff('2020-02-02 15:30:00', '1951-02-16 15:27:00'); """ + qt_sql """SELECT minutes_diff('2020-02-02 15:30:00', '1952-02-16 15:27:00'); """ + qt_sql """SELECT minutes_diff('2020-02-02 15:30:00', '1900-02-16 15:27:00'); """ + qt_sql """SELECT hours_diff('9020-02-02 15:30:00', '1900-02-16 15:27:00'); """ + qt_sql """SELECT seconds_diff('3000-02-02 15:30:00', '1900-02-16 15:27:00'); """ + qt_sql """SELECT seconds_diff('3000-01-01 00:00:00', '1000-01-01 00:00:00'); """ +} \ No newline at end of file --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org