zclllyybb commented on code in PR #56200:
URL: https://github.com/apache/doris/pull/56200#discussion_r2366896858


##########
regression-test/suites/nereids_p0/sql_functions/datetime_functions/test_date_function_v2.groovy:
##########


Review Comment:
   再测一下两个参数都带精度,精度不同的情况,分别在FE和BE执行,确认规划正常。



##########
be/src/vec/functions/function_date_or_datetime_computation.h:
##########
@@ -1281,5 +1281,155 @@ class FunctionTime : public IFunction {
         return Status::OK();
     }
 };
+
+struct AddTimeImpl {
+    static constexpr auto name = "add_time";
+};
+
+struct SubTimeImpl {
+    static constexpr auto name = "sub_time";
+};
+
+template <PrimitiveType PType, typename Impl>
+struct TimeComputeImpl {
+    static constexpr auto name = Impl::name;
+    static constexpr PrimitiveType ReturnType = PType;
+    static constexpr PrimitiveType ArgType1 = PType;
+    static constexpr PrimitiveType ArgType2 = TYPE_TIMEV2;
+    using ColumnType1 = typename PrimitiveTypeTraits<PType>::ColumnType;
+    using ColumnType2 = typename PrimitiveTypeTraits<TYPE_TIMEV2>::ColumnType;
+    using InputType1 = typename 
PrimitiveTypeTraits<PType>::DataType::FieldType;
+    using InputType2 = typename 
PrimitiveTypeTraits<TYPE_TIMEV2>::DataType::FieldType;
+    using ReturnNativeType = InputType1;
+    using ReturnDataType = typename PrimitiveTypeTraits<PType>::DataType;
+    ReturnNativeType execute(const InputType1& arg1, const InputType2& arg2) {
+        if constexpr (PType == TYPE_DATETIMEV2) {
+            DateV2Value<DateTimeV2ValueType> dtv1 =
+                    binary_cast<InputType1, 
DateV2Value<DateTimeV2ValueType>>(arg1);
+            auto tv2 = static_cast<TimeValue::TimeType>(arg2);
+            bool neg = std::string_view(name) == "sub_time";
+            TimeInterval interval(TimeUnit::MICROSECOND, tv2, neg);
+            bool out_range = dtv1.template 
date_add_interval<TimeUnit::MICROSECOND>(interval);
+            if (!out_range) {
+                throw Exception(ErrorCode::INVALID_ARGUMENT,
+                                "datetime value is out of range in function 
{}", name);
+            }
+            return binary_cast<DateV2Value<DateTimeV2ValueType>, 
ReturnNativeType>(dtv1);
+        } else if constexpr (PType == TYPE_TIMEV2) {
+            auto tv1 = static_cast<TimeValue::TimeType>(arg1);
+            auto tv2 = static_cast<TimeValue::TimeType>(arg2);
+            bool neg = std::string_view(name) == "sub_time";
+            double res = TimeValue::limit_with_bound(neg ? tv1 - tv2 : tv1 + 
tv2);
+            return res;
+        } else {
+            throw Exception(ErrorCode::INVALID_ARGUMENT, "not support type for 
function {}", name);

Review Comment:
   走到这说明FE和BE没对上,是INTERNAL_ERROR。INVALID_ARGUMENT代表用户输入能够造成的问题



##########
be/src/vec/functions/function_date_or_datetime_computation.h:
##########
@@ -1281,5 +1281,155 @@ class FunctionTime : public IFunction {
         return Status::OK();
     }
 };
+
+struct AddTimeImpl {
+    static constexpr auto name = "add_time";
+};
+
+struct SubTimeImpl {
+    static constexpr auto name = "sub_time";
+};
+
+template <PrimitiveType PType, typename Impl>
+struct TimeComputeImpl {
+    static constexpr auto name = Impl::name;
+    static constexpr PrimitiveType ReturnType = PType;
+    static constexpr PrimitiveType ArgType1 = PType;
+    static constexpr PrimitiveType ArgType2 = TYPE_TIMEV2;
+    using ColumnType1 = typename PrimitiveTypeTraits<PType>::ColumnType;
+    using ColumnType2 = typename PrimitiveTypeTraits<TYPE_TIMEV2>::ColumnType;
+    using InputType1 = typename 
PrimitiveTypeTraits<PType>::DataType::FieldType;
+    using InputType2 = typename 
PrimitiveTypeTraits<TYPE_TIMEV2>::DataType::FieldType;
+    using ReturnNativeType = InputType1;
+    using ReturnDataType = typename PrimitiveTypeTraits<PType>::DataType;
+    ReturnNativeType execute(const InputType1& arg1, const InputType2& arg2) {
+        if constexpr (PType == TYPE_DATETIMEV2) {
+            DateV2Value<DateTimeV2ValueType> dtv1 =
+                    binary_cast<InputType1, 
DateV2Value<DateTimeV2ValueType>>(arg1);
+            auto tv2 = static_cast<TimeValue::TimeType>(arg2);
+            bool neg = std::string_view(name) == "sub_time";
+            TimeInterval interval(TimeUnit::MICROSECOND, tv2, neg);
+            bool out_range = dtv1.template 
date_add_interval<TimeUnit::MICROSECOND>(interval);
+            if (!out_range) {
+                throw Exception(ErrorCode::INVALID_ARGUMENT,
+                                "datetime value is out of range in function 
{}", name);
+            }
+            return binary_cast<DateV2Value<DateTimeV2ValueType>, 
ReturnNativeType>(dtv1);
+        } else if constexpr (PType == TYPE_TIMEV2) {
+            auto tv1 = static_cast<TimeValue::TimeType>(arg1);
+            auto tv2 = static_cast<TimeValue::TimeType>(arg2);
+            bool neg = std::string_view(name) == "sub_time";
+            double res = TimeValue::limit_with_bound(neg ? tv1 - tv2 : tv1 + 
tv2);
+            return res;
+        } else {
+            throw Exception(ErrorCode::INVALID_ARGUMENT, "not support type for 
function {}", name);
+        }
+    }
+
+    static DataTypes get_variadic_argument_types() {
+        return {std::make_shared<typename 
PrimitiveTypeTraits<PType>::DataType>(),
+                std::make_shared<typename 
PrimitiveTypeTraits<TYPE_TIMEV2>::DataType>()};
+    }
+};
+
+template <typename Transform>
+class FunctionAddTime : public IFunction {
+public:
+    using ColumnType1 = typename Transform::ColumnType1;
+    using ColumnType2 = typename Transform::ColumnType2;
+    using NativeType1 = typename Transform::InputType1;
+    using NativeType2 = typename Transform::InputType2;
+    using ReturnNativeType = typename Transform::ReturnNativeType;
+    static constexpr auto name = Transform::name;
+    static constexpr bool has_variadic_argument =

Review Comment:
   这里不用这些判断,这个基模板的实现模板是固定的,has_variadic_argument就是true。



##########
be/src/vec/functions/function_date_or_datetime_computation.h:
##########
@@ -1281,5 +1281,155 @@ class FunctionTime : public IFunction {
         return Status::OK();
     }
 };
+
+struct AddTimeImpl {
+    static constexpr auto name = "add_time";
+};
+
+struct SubTimeImpl {
+    static constexpr auto name = "sub_time";
+};
+
+template <PrimitiveType PType, typename Impl>
+struct TimeComputeImpl {

Review Comment:
   这一层模板可以去掉



##########
be/src/vec/functions/function_date_or_datetime_computation.h:
##########
@@ -1281,5 +1281,155 @@ class FunctionTime : public IFunction {
         return Status::OK();
     }
 };
+
+struct AddTimeImpl {
+    static constexpr auto name = "add_time";
+};
+
+struct SubTimeImpl {
+    static constexpr auto name = "sub_time";
+};
+
+template <PrimitiveType PType, typename Impl>
+struct TimeComputeImpl {
+    static constexpr auto name = Impl::name;
+    static constexpr PrimitiveType ReturnType = PType;
+    static constexpr PrimitiveType ArgType1 = PType;
+    static constexpr PrimitiveType ArgType2 = TYPE_TIMEV2;
+    using ColumnType1 = typename PrimitiveTypeTraits<PType>::ColumnType;
+    using ColumnType2 = typename PrimitiveTypeTraits<TYPE_TIMEV2>::ColumnType;
+    using InputType1 = typename 
PrimitiveTypeTraits<PType>::DataType::FieldType;
+    using InputType2 = typename 
PrimitiveTypeTraits<TYPE_TIMEV2>::DataType::FieldType;
+    using ReturnNativeType = InputType1;
+    using ReturnDataType = typename PrimitiveTypeTraits<PType>::DataType;
+    ReturnNativeType execute(const InputType1& arg1, const InputType2& arg2) {
+        if constexpr (PType == TYPE_DATETIMEV2) {
+            DateV2Value<DateTimeV2ValueType> dtv1 =
+                    binary_cast<InputType1, 
DateV2Value<DateTimeV2ValueType>>(arg1);
+            auto tv2 = static_cast<TimeValue::TimeType>(arg2);
+            bool neg = std::string_view(name) == "sub_time";

Review Comment:
   不要依赖名字,给Impl类加个neg



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/SubTime.java:
##########
@@ -0,0 +1,76 @@
+// 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.
+
+package org.apache.doris.nereids.trees.expressions.functions.scalar;
+
+import org.apache.doris.catalog.FunctionSignature;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import 
org.apache.doris.nereids.trees.expressions.functions.ComputeSignatureForDateArithmetic;
+import 
org.apache.doris.nereids.trees.expressions.functions.DateAddSubMonotonic;
+import 
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
+import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
+import org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
+import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
+import org.apache.doris.nereids.types.DateTimeV2Type;
+import org.apache.doris.nereids.types.TimeV2Type;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/**
+ * ScalarFunction 'sub_time'.
+ */
+public class SubTime extends ScalarFunction implements BinaryExpression, 
ExplicitlyCastableSignature,
+        ComputeSignatureForDateArithmetic, PropagateNullable, 
DateAddSubMonotonic {
+
+    private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+            
FunctionSignature.ret(DateTimeV2Type.SYSTEM_DEFAULT).args(DateTimeV2Type.SYSTEM_DEFAULT,

Review Comment:
   
得同时兼容两种格式,参照ComputeSignatureForDateArithmetic实现一个ComputeSignatureForTimeArithmetic吧,这个顺序不变,但literal情况优先匹配到timev2。



##########
be/src/vec/functions/function_date_or_datetime_computation.h:
##########
@@ -1281,5 +1281,155 @@ class FunctionTime : public IFunction {
         return Status::OK();
     }
 };
+
+struct AddTimeImpl {
+    static constexpr auto name = "add_time";
+};
+
+struct SubTimeImpl {
+    static constexpr auto name = "sub_time";
+};
+
+template <PrimitiveType PType, typename Impl>
+struct TimeComputeImpl {
+    static constexpr auto name = Impl::name;
+    static constexpr PrimitiveType ReturnType = PType;
+    static constexpr PrimitiveType ArgType1 = PType;
+    static constexpr PrimitiveType ArgType2 = TYPE_TIMEV2;
+    using ColumnType1 = typename PrimitiveTypeTraits<PType>::ColumnType;
+    using ColumnType2 = typename PrimitiveTypeTraits<TYPE_TIMEV2>::ColumnType;
+    using InputType1 = typename 
PrimitiveTypeTraits<PType>::DataType::FieldType;
+    using InputType2 = typename 
PrimitiveTypeTraits<TYPE_TIMEV2>::DataType::FieldType;
+    using ReturnNativeType = InputType1;
+    using ReturnDataType = typename PrimitiveTypeTraits<PType>::DataType;
+    ReturnNativeType execute(const InputType1& arg1, const InputType2& arg2) {
+        if constexpr (PType == TYPE_DATETIMEV2) {
+            DateV2Value<DateTimeV2ValueType> dtv1 =
+                    binary_cast<InputType1, 
DateV2Value<DateTimeV2ValueType>>(arg1);
+            auto tv2 = static_cast<TimeValue::TimeType>(arg2);
+            bool neg = std::string_view(name) == "sub_time";
+            TimeInterval interval(TimeUnit::MICROSECOND, tv2, neg);
+            bool out_range = dtv1.template 
date_add_interval<TimeUnit::MICROSECOND>(interval);
+            if (!out_range) {
+                throw Exception(ErrorCode::INVALID_ARGUMENT,
+                                "datetime value is out of range in function 
{}", name);
+            }
+            return binary_cast<DateV2Value<DateTimeV2ValueType>, 
ReturnNativeType>(dtv1);
+        } else if constexpr (PType == TYPE_TIMEV2) {
+            auto tv1 = static_cast<TimeValue::TimeType>(arg1);
+            auto tv2 = static_cast<TimeValue::TimeType>(arg2);
+            bool neg = std::string_view(name) == "sub_time";
+            double res = TimeValue::limit_with_bound(neg ? tv1 - tv2 : tv1 + 
tv2);
+            return res;
+        } else {
+            throw Exception(ErrorCode::INVALID_ARGUMENT, "not support type for 
function {}", name);
+        }
+    }
+
+    static DataTypes get_variadic_argument_types() {
+        return {std::make_shared<typename 
PrimitiveTypeTraits<PType>::DataType>(),
+                std::make_shared<typename 
PrimitiveTypeTraits<TYPE_TIMEV2>::DataType>()};
+    }
+};
+
+template <typename Transform>
+class FunctionAddTime : public IFunction {
+public:
+    using ColumnType1 = typename Transform::ColumnType1;
+    using ColumnType2 = typename Transform::ColumnType2;
+    using NativeType1 = typename Transform::InputType1;
+    using NativeType2 = typename Transform::InputType2;
+    using ReturnNativeType = typename Transform::ReturnNativeType;
+    static constexpr auto name = Transform::name;
+    static constexpr bool has_variadic_argument =
+            
!std::is_void_v<decltype(has_variadic_argument_types(std::declval<Transform>()))>;
+
+    static FunctionPtr create() { return 
std::make_shared<FunctionAddTime<Transform>>(); }
+    String get_name() const override { return name; }
+    size_t get_number_of_arguments() const override { return 2; }
+    DataTypes get_variadic_argument_types_impl() const override {
+        if constexpr (has_variadic_argument) {
+            return Transform::get_variadic_argument_types();
+        }
+        return {};
+    }
+    DataTypePtr get_return_type_impl(const ColumnsWithTypeAndName& arguments) 
const override {
+        return std::make_shared<typename Transform::ReturnDataType>();
+    }
+
+    Status execute_impl(FunctionContext* context, Block& block, const 
ColumnNumbers& arguments,
+                        uint32_t result, size_t input_rows_count) const 
override {
+        DCHECK_EQ(arguments.size(), 2);
+        const auto& [left_col, left_const] =
+                unpack_if_const(block.get_by_position(arguments[0]).column);
+        const auto& [right_col, right_const] =
+                unpack_if_const(block.get_by_position(arguments[1]).column);
+        ColumnPtr nest_col1 = remove_nullable(left_col);
+        ColumnPtr nest_col2 = remove_nullable(right_col);
+        auto res = 
ColumnVector<Transform::ReturnType>::create(input_rows_count, 0);
+
+        if (left_const && right_const) {
+            execute_constant_constant(
+                    assert_cast<const typename 
Transform::ColumnType1&>(*nest_col1).get_element(0),
+                    assert_cast<const typename 
Transform::ColumnType2&>(*nest_col2).get_element(0),
+                    res->get_data(), input_rows_count);
+        } else if (left_const) {
+            execute_constant_vector(
+                    assert_cast<const typename 
Transform::ColumnType1&>(*nest_col1).get_element(0),
+                    assert_cast<const typename 
Transform::ColumnType2&>(*nest_col2).get_data(),
+                    res->get_data(), input_rows_count);
+        } else if (right_const) {
+            execute_vector_constant(
+                    assert_cast<const typename 
Transform::ColumnType1&>(*nest_col1).get_data(),
+                    assert_cast<const typename 
Transform::ColumnType2&>(*nest_col2).get_element(0),
+                    res->get_data(), input_rows_count);
+        } else {
+            execute_vector_vector(
+                    assert_cast<const typename 
Transform::ColumnType1&>(*nest_col1).get_data(),
+                    assert_cast<const typename 
Transform::ColumnType2&>(*nest_col2).get_data(),
+                    res->get_data(), input_rows_count);
+        }
+
+        block.replace_by_position(result, std::move(res));
+        return Status::OK();
+    }
+    void execute_vector_vector(const PaddedPODArray<NativeType1>& left_col,
+                               const PaddedPODArray<NativeType2>& right_col,
+                               PaddedPODArray<ReturnNativeType>& res_data,
+                               size_t input_rows_count) const {
+        Transform transform;
+        for (size_t i = 0; i < input_rows_count; ++i) {
+            res_data[i] = transform.execute(left_col[i], right_col[i]);
+        }
+    }
+
+    void execute_vector_constant(const PaddedPODArray<NativeType1>& left_col,
+                                 const NativeType2 right_value,
+                                 PaddedPODArray<ReturnNativeType>& res_data,
+                                 size_t input_rows_count) const {
+        Transform transform;
+        for (size_t i = 0; i < input_rows_count; ++i) {
+            res_data[i] = transform.execute(left_col[i], right_value);
+        }
+    }
+
+    void execute_constant_vector(const NativeType1 left_value,
+                                 const PaddedPODArray<NativeType2>& right_col,
+                                 PaddedPODArray<ReturnNativeType>& res_data,
+                                 size_t input_rows_count) const {
+        Transform transform;
+        for (size_t i = 0; i < input_rows_count; ++i) {
+            res_data[i] = transform.execute(left_value, right_col[i]);
+        }
+    }
+    void execute_constant_constant(const NativeType1 left_value, const 
NativeType2 right_value,

Review Comment:
   这个情况不存在



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to