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

Reply via email to