superdiaodiao commented on code in PR #40293:
URL: https://github.com/apache/doris/pull/40293#discussion_r1741371565


##########
regression-test/suites/nereids_function_p0/scalar_function/T.groovy:
##########
@@ -45,6 +45,10 @@ suite("nereids_scalar_fn_T") {
        qt_sql_timestamp_DateTime_notnull "select timestamp(kdtm) from 
fn_test_not_nullable order by kdtm"
        qt_sql_timestamp_DateTimeV2 "select timestamp(kdtmv2s1) from fn_test 
order by kdtmv2s1"
        qt_sql_timestamp_DateTimeV2_notnull "select timestamp(kdtmv2s1) from 
fn_test_not_nullable order by kdtmv2s1"
+       qt_sql_timestamp_DateTime "select timestamp(kdtm,'Asia/Bangkok') from 
fn_test order by kdtm"
+       qt_sql_timestamp_DateTime_notnull "select 
timestamp(kdtm,'Asia/Bangkok') from fn_test_not_nullable order by kdtm"
+       qt_sql_timestamp_DateTimeV2 "select timestamp(kdtmv2s1,'Asia/Bangkok') 
from fn_test order by kdtmv2s1"
+       qt_sql_timestamp_DateTimeV2_notnull "select 
timestamp(kdtmv2s1,'Asia/Bangkok') from fn_test_not_nullable order by kdtmv2s1"

Review Comment:
   If the function supports two column arguments, we'd better test this case, 
that is, `timestamp(column1, coulumn2)`.
   
   Also, the tag for sentence(like `qt_sql_timestamp_DateTimeV2`) should be 
different from the any other's.



##########
be/src/vec/functions/function_convert_tz.h:
##########
@@ -217,4 +219,323 @@ class FunctionConvertTZ : public IFunction {
     }
 };
 
+template <typename ArgDateType>
+class FunctionDateTZ : public IFunction {
+    using DateValueType = date_cast::TypeToValueTypeV<ArgDateType>;
+    using ArgColumnType = date_cast::TypeToColumnV<ArgDateType>;
+    using NativeType = date_cast::ValueTypeOfColumnV<ArgColumnType>;
+    constexpr static bool is_v1 = date_cast::IsV1<ArgDateType>();
+    using TempDateType = std::conditional_t<is_v1, DataTypeDateTime, 
ArgDateType>;
+    using TempDateValueType = date_cast::TypeToValueTypeV<TempDateType>;
+    using ReturnDateType = std::conditional_t<is_v1, DataTypeDate, 
DataTypeDateV2>; //todo
+    using ReturnDateValueType = date_cast::TypeToValueTypeV<ReturnDateType>;
+    using ReturnColumnType = date_cast::TypeToColumnV<ReturnDateType>;
+    using ReturnNativeType = date_cast::ValueTypeOfColumnV<ReturnColumnType>;
+
+public:
+    static constexpr auto name = "date";
+
+    static FunctionPtr create() { return std::make_shared<FunctionDateTZ>(); }
+
+    String get_name() const override { return name; }
+
+    size_t get_number_of_arguments() const override { return 2; }
+
+    DataTypePtr get_return_type_impl(const DataTypes& arguments) const 
override {
+        if constexpr (is_v1) {
+            return make_nullable(std::make_shared<DataTypeDate>());
+        } else {
+            return make_nullable(std::make_shared<DataTypeDateV2>());
+        }
+    }
+
+    bool is_variadic() const override { return true; }
+
+    DataTypes get_variadic_argument_types_impl() const override {
+        return {std::make_shared<ArgDateType>(), 
std::make_shared<DataTypeString>()};
+    }
+
+    bool use_default_implementation_for_nulls() const override { return false; 
}
+
+    Status close(FunctionContext* context, FunctionContext::FunctionStateScope 
scope) override {
+        return Status::OK();
+    }
+
+    Status execute_impl(FunctionContext* context, Block& block, const 
ColumnNumbers& arguments,
+                        size_t result, size_t input_rows_count) const override 
{
+        auto result_null_map_column = ColumnUInt8::create(input_rows_count, 0);
+
+        bool col_const[3];
+        ColumnPtr argument_columns[2];
+        for (int i = 0; i < 2; ++i) {
+            col_const[i] = 
is_column_const(*block.get_by_position(arguments[i]).column);
+        }
+        argument_columns[0] = col_const[0] ? static_cast<const ColumnConst&>(
+                                                     
*block.get_by_position(arguments[0]).column)
+                                                     .convert_to_full_column()
+                                           : 
block.get_by_position(arguments[0]).column;
+
+        default_preprocess_parameter_columns(argument_columns, col_const, {1}, 
block, arguments);
+
+        for (int i = 0; i < 2; i++) {
+            check_set_nullable(argument_columns[i], result_null_map_column, 
col_const[i]);
+        }
+
+        if (col_const[1]) {
+            auto result_column = ReturnColumnType::create();
+            execute_tz_const(context, assert_cast<const 
ArgColumnType*>(argument_columns[0].get()),
+                             assert_cast<const 
ColumnString*>(argument_columns[1].get()),
+                             
assert_cast<ReturnColumnType*>(result_column.get()),
+                             
assert_cast<ColumnUInt8*>(result_null_map_column.get())->get_data(),
+                             input_rows_count);
+            block.get_by_position(result).column = ColumnNullable::create(
+                    std::move(result_column), 
std::move(result_null_map_column));
+        } else {
+            auto result_column = ReturnColumnType::create();
+            execute(context, assert_cast<const 
ArgColumnType*>(argument_columns[0].get()),
+                    assert_cast<const 
ColumnString*>(argument_columns[1].get()),
+                    assert_cast<ReturnColumnType*>(result_column.get()),
+                    
assert_cast<ColumnUInt8*>(result_null_map_column.get())->get_data(),
+                    input_rows_count);
+            block.get_by_position(result).column = ColumnNullable::create(
+                    std::move(result_column), 
std::move(result_null_map_column));
+        } //if const
+        return Status::OK();
+    }
+
+private:
+    static void execute(FunctionContext* context, const ArgColumnType* 
date_column,
+                        const ColumnString* to_tz_column, ReturnColumnType* 
result_column,
+                        NullMap& result_null_map, size_t input_rows_count) {

Review Comment:
   I found that `execute()` as well as `execute_tz_const()` in `class 
FunctionDateTZ()` and `class FunctionTimestampTZ()` are almost the same, is 
there any chance to simplify them?



##########
be/src/vec/functions/function_convert_tz.h:
##########
@@ -217,4 +219,323 @@ class FunctionConvertTZ : public IFunction {
     }
 };
 
+template <typename ArgDateType>
+class FunctionDateTZ : public IFunction {
+    using DateValueType = date_cast::TypeToValueTypeV<ArgDateType>;
+    using ArgColumnType = date_cast::TypeToColumnV<ArgDateType>;
+    using NativeType = date_cast::ValueTypeOfColumnV<ArgColumnType>;
+    constexpr static bool is_v1 = date_cast::IsV1<ArgDateType>();
+    using TempDateType = std::conditional_t<is_v1, DataTypeDateTime, 
ArgDateType>;
+    using TempDateValueType = date_cast::TypeToValueTypeV<TempDateType>;
+    using ReturnDateType = std::conditional_t<is_v1, DataTypeDate, 
DataTypeDateV2>; //todo
+    using ReturnDateValueType = date_cast::TypeToValueTypeV<ReturnDateType>;
+    using ReturnColumnType = date_cast::TypeToColumnV<ReturnDateType>;
+    using ReturnNativeType = date_cast::ValueTypeOfColumnV<ReturnColumnType>;
+
+public:
+    static constexpr auto name = "date";
+
+    static FunctionPtr create() { return std::make_shared<FunctionDateTZ>(); }
+
+    String get_name() const override { return name; }
+
+    size_t get_number_of_arguments() const override { return 2; }
+
+    DataTypePtr get_return_type_impl(const DataTypes& arguments) const 
override {
+        if constexpr (is_v1) {
+            return make_nullable(std::make_shared<DataTypeDate>());
+        } else {
+            return make_nullable(std::make_shared<DataTypeDateV2>());
+        }
+    }
+
+    bool is_variadic() const override { return true; }
+
+    DataTypes get_variadic_argument_types_impl() const override {
+        return {std::make_shared<ArgDateType>(), 
std::make_shared<DataTypeString>()};
+    }
+
+    bool use_default_implementation_for_nulls() const override { return false; 
}
+
+    Status close(FunctionContext* context, FunctionContext::FunctionStateScope 
scope) override {
+        return Status::OK();
+    }

Review Comment:
   This function could be deleted.



##########
be/src/vec/functions/function_convert_tz.h:
##########
@@ -217,4 +219,323 @@ class FunctionConvertTZ : public IFunction {
     }
 };
 
+template <typename ArgDateType>
+class FunctionDateTZ : public IFunction {
+    using DateValueType = date_cast::TypeToValueTypeV<ArgDateType>;
+    using ArgColumnType = date_cast::TypeToColumnV<ArgDateType>;
+    using NativeType = date_cast::ValueTypeOfColumnV<ArgColumnType>;
+    constexpr static bool is_v1 = date_cast::IsV1<ArgDateType>();
+    using TempDateType = std::conditional_t<is_v1, DataTypeDateTime, 
ArgDateType>;
+    using TempDateValueType = date_cast::TypeToValueTypeV<TempDateType>;
+    using ReturnDateType = std::conditional_t<is_v1, DataTypeDate, 
DataTypeDateV2>; //todo
+    using ReturnDateValueType = date_cast::TypeToValueTypeV<ReturnDateType>;
+    using ReturnColumnType = date_cast::TypeToColumnV<ReturnDateType>;
+    using ReturnNativeType = date_cast::ValueTypeOfColumnV<ReturnColumnType>;
+
+public:
+    static constexpr auto name = "date";
+
+    static FunctionPtr create() { return std::make_shared<FunctionDateTZ>(); }
+
+    String get_name() const override { return name; }
+
+    size_t get_number_of_arguments() const override { return 2; }
+
+    DataTypePtr get_return_type_impl(const DataTypes& arguments) const 
override {
+        if constexpr (is_v1) {
+            return make_nullable(std::make_shared<DataTypeDate>());
+        } else {
+            return make_nullable(std::make_shared<DataTypeDateV2>());
+        }
+    }
+
+    bool is_variadic() const override { return true; }
+
+    DataTypes get_variadic_argument_types_impl() const override {
+        return {std::make_shared<ArgDateType>(), 
std::make_shared<DataTypeString>()};
+    }
+
+    bool use_default_implementation_for_nulls() const override { return false; 
}
+
+    Status close(FunctionContext* context, FunctionContext::FunctionStateScope 
scope) override {
+        return Status::OK();
+    }
+
+    Status execute_impl(FunctionContext* context, Block& block, const 
ColumnNumbers& arguments,
+                        size_t result, size_t input_rows_count) const override 
{
+        auto result_null_map_column = ColumnUInt8::create(input_rows_count, 0);
+
+        bool col_const[3];
+        ColumnPtr argument_columns[2];
+        for (int i = 0; i < 2; ++i) {
+            col_const[i] = 
is_column_const(*block.get_by_position(arguments[i]).column);
+        }
+        argument_columns[0] = col_const[0] ? static_cast<const ColumnConst&>(
+                                                     
*block.get_by_position(arguments[0]).column)
+                                                     .convert_to_full_column()
+                                           : 
block.get_by_position(arguments[0]).column;
+
+        default_preprocess_parameter_columns(argument_columns, col_const, {1}, 
block, arguments);
+
+        for (int i = 0; i < 2; i++) {
+            check_set_nullable(argument_columns[i], result_null_map_column, 
col_const[i]);
+        }
+
+        if (col_const[1]) {
+            auto result_column = ReturnColumnType::create();
+            execute_tz_const(context, assert_cast<const 
ArgColumnType*>(argument_columns[0].get()),
+                             assert_cast<const 
ColumnString*>(argument_columns[1].get()),
+                             
assert_cast<ReturnColumnType*>(result_column.get()),
+                             
assert_cast<ColumnUInt8*>(result_null_map_column.get())->get_data(),
+                             input_rows_count);
+            block.get_by_position(result).column = ColumnNullable::create(
+                    std::move(result_column), 
std::move(result_null_map_column));
+        } else {
+            auto result_column = ReturnColumnType::create();
+            execute(context, assert_cast<const 
ArgColumnType*>(argument_columns[0].get()),
+                    assert_cast<const 
ColumnString*>(argument_columns[1].get()),
+                    assert_cast<ReturnColumnType*>(result_column.get()),
+                    
assert_cast<ColumnUInt8*>(result_null_map_column.get())->get_data(),
+                    input_rows_count);
+            block.get_by_position(result).column = ColumnNullable::create(
+                    std::move(result_column), 
std::move(result_null_map_column));
+        } //if const

Review Comment:
   The `result_column` and `block.get_by_position(result).column` could be 
moved out of `if-else` part.



##########
be/src/vec/functions/function_convert_tz.h:
##########
@@ -217,4 +219,323 @@ class FunctionConvertTZ : public IFunction {
     }
 };
 
+template <typename ArgDateType>
+class FunctionDateTZ : public IFunction {
+    using DateValueType = date_cast::TypeToValueTypeV<ArgDateType>;
+    using ArgColumnType = date_cast::TypeToColumnV<ArgDateType>;
+    using NativeType = date_cast::ValueTypeOfColumnV<ArgColumnType>;
+    constexpr static bool is_v1 = date_cast::IsV1<ArgDateType>();
+    using TempDateType = std::conditional_t<is_v1, DataTypeDateTime, 
ArgDateType>;
+    using TempDateValueType = date_cast::TypeToValueTypeV<TempDateType>;
+    using ReturnDateType = std::conditional_t<is_v1, DataTypeDate, 
DataTypeDateV2>; //todo
+    using ReturnDateValueType = date_cast::TypeToValueTypeV<ReturnDateType>;
+    using ReturnColumnType = date_cast::TypeToColumnV<ReturnDateType>;
+    using ReturnNativeType = date_cast::ValueTypeOfColumnV<ReturnColumnType>;
+
+public:
+    static constexpr auto name = "date";
+
+    static FunctionPtr create() { return std::make_shared<FunctionDateTZ>(); }
+
+    String get_name() const override { return name; }
+
+    size_t get_number_of_arguments() const override { return 2; }
+
+    DataTypePtr get_return_type_impl(const DataTypes& arguments) const 
override {
+        if constexpr (is_v1) {
+            return make_nullable(std::make_shared<DataTypeDate>());
+        } else {
+            return make_nullable(std::make_shared<DataTypeDateV2>());
+        }
+    }
+
+    bool is_variadic() const override { return true; }
+
+    DataTypes get_variadic_argument_types_impl() const override {
+        return {std::make_shared<ArgDateType>(), 
std::make_shared<DataTypeString>()};
+    }
+
+    bool use_default_implementation_for_nulls() const override { return false; 
}
+
+    Status close(FunctionContext* context, FunctionContext::FunctionStateScope 
scope) override {
+        return Status::OK();
+    }
+
+    Status execute_impl(FunctionContext* context, Block& block, const 
ColumnNumbers& arguments,
+                        size_t result, size_t input_rows_count) const override 
{
+        auto result_null_map_column = ColumnUInt8::create(input_rows_count, 0);
+
+        bool col_const[3];
+        ColumnPtr argument_columns[2];
+        for (int i = 0; i < 2; ++i) {
+            col_const[i] = 
is_column_const(*block.get_by_position(arguments[i]).column);
+        }
+        argument_columns[0] = col_const[0] ? static_cast<const ColumnConst&>(
+                                                     
*block.get_by_position(arguments[0]).column)
+                                                     .convert_to_full_column()
+                                           : 
block.get_by_position(arguments[0]).column;
+
+        default_preprocess_parameter_columns(argument_columns, col_const, {1}, 
block, arguments);
+
+        for (int i = 0; i < 2; i++) {
+            check_set_nullable(argument_columns[i], result_null_map_column, 
col_const[i]);
+        }
+
+        if (col_const[1]) {
+            auto result_column = ReturnColumnType::create();
+            execute_tz_const(context, assert_cast<const 
ArgColumnType*>(argument_columns[0].get()),
+                             assert_cast<const 
ColumnString*>(argument_columns[1].get()),
+                             
assert_cast<ReturnColumnType*>(result_column.get()),
+                             
assert_cast<ColumnUInt8*>(result_null_map_column.get())->get_data(),
+                             input_rows_count);
+            block.get_by_position(result).column = ColumnNullable::create(
+                    std::move(result_column), 
std::move(result_null_map_column));
+        } else {
+            auto result_column = ReturnColumnType::create();
+            execute(context, assert_cast<const 
ArgColumnType*>(argument_columns[0].get()),
+                    assert_cast<const 
ColumnString*>(argument_columns[1].get()),
+                    assert_cast<ReturnColumnType*>(result_column.get()),
+                    
assert_cast<ColumnUInt8*>(result_null_map_column.get())->get_data(),
+                    input_rows_count);
+            block.get_by_position(result).column = ColumnNullable::create(
+                    std::move(result_column), 
std::move(result_null_map_column));
+        } //if const
+        return Status::OK();
+    }
+
+private:
+    static void execute(FunctionContext* context, const ArgColumnType* 
date_column,
+                        const ColumnString* to_tz_column, ReturnColumnType* 
result_column,
+                        NullMap& result_null_map, size_t input_rows_count) {
+        for (size_t i = 0; i < input_rows_count; i++) {
+            if (result_null_map[i]) {
+                result_column->insert_default();
+                continue;
+            }
+            auto to_tz = to_tz_column->get_data_at(i).to_string();
+            execute_inner_loop(context, date_column, to_tz, result_column, 
result_null_map, i);
+        }
+    }
+
+    static void execute_tz_const(FunctionContext* context, const 
ArgColumnType* date_column,
+                                 const ColumnString* to_tz_column, 
ReturnColumnType* result_column,
+                                 NullMap& result_null_map, size_t 
input_rows_count) {
+        auto to_tz = to_tz_column->get_data_at(0).to_string();
+        for (size_t i = 0; i < input_rows_count; i++) {
+            if (result_null_map[i]) {
+                result_column->insert_default();
+                continue;
+            }
+            execute_inner_loop(context, date_column, to_tz, result_column, 
result_null_map, i);
+        }
+    }
+
+    static void execute_inner_loop(FunctionContext* context, const 
ArgColumnType* date_column,
+                                   const std::string& to_tz_name, 
ReturnColumnType* result_column,
+                                   NullMap& result_null_map, const size_t 
index_now) {
+        DateValueType ts_value =
+                binary_cast<NativeType, 
DateValueType>(date_column->get_element(index_now));
+        cctz::time_zone from_tz {}, to_tz {};
+        TempDateValueType ts_value2;
+        ReturnDateValueType ts_res;
+
+        from_tz = context->state()->timezone_obj();
+
+        if (!TimezoneUtils::find_cctz_time_zone(to_tz_name, to_tz)) {
+            result_null_map[index_now] = true;
+            result_column->insert_default();
+            return;
+        }
+
+        if constexpr (std::is_same_v<ArgDateType, DataTypeDateTimeV2>) {
+            std::pair<int64_t, int64_t> timestamp;
+            if (!ts_value.unix_timestamp(&timestamp, from_tz)) {
+                result_null_map[index_now] = true;
+                result_column->insert_default();
+                return;
+            }
+            ts_value2.from_unixtime(timestamp, to_tz);
+        } else {
+            int64_t timestamp;
+            if (!ts_value.unix_timestamp(&timestamp, from_tz)) {
+                result_null_map[index_now] = true;
+                result_column->insert_default();
+                return;
+            }
+            ts_value2.from_unixtime(timestamp, to_tz);
+        }
+
+        if (!ts_value2.is_valid_date()) [[unlikely]] {
+            result_null_map[index_now] = true;
+            result_column->insert_default();
+            return;
+        }
+
+        ts_res = ts_res.create_from_olap_date(ts_value2.to_olap_date());
+
+        result_column->insert(binary_cast<ReturnDateValueType, 
ReturnNativeType>(ts_res));
+    }
+};
+
+template <typename ArgDateType>
+class FunctionTimestampTZ : public IFunction {
+    using DateValueType = date_cast::TypeToValueTypeV<ArgDateType>;
+    using ColumnType = date_cast::TypeToColumnV<ArgDateType>;
+    using NativeType = date_cast::ValueTypeOfColumnV<ColumnType>;
+    constexpr static bool is_v1 = date_cast::IsV1<ArgDateType>();
+    using ReturnDateType = std::conditional_t<is_v1, DataTypeDateTime, 
ArgDateType>;
+    using ReturnDateValueType = date_cast::TypeToValueTypeV<ReturnDateType>;
+    using ReturnColumnType = date_cast::TypeToColumnV<ReturnDateType>;
+    using ReturnNativeType = date_cast::ValueTypeOfColumnV<ReturnColumnType>;
+
+public:
+    static constexpr auto name = "timestamp";
+
+    static FunctionPtr create() { return 
std::make_shared<FunctionTimestampTZ>(); }
+
+    String get_name() const override { return name; }
+
+    size_t get_number_of_arguments() const override { return 2; }
+
+    DataTypePtr get_return_type_impl(const DataTypes& arguments) const 
override {
+        if constexpr (is_v1) {
+            return make_nullable(std::make_shared<DataTypeDateTime>());
+        } else {
+            return make_nullable(std::make_shared<DataTypeDateTimeV2>());
+        }
+    }
+
+    bool is_variadic() const override { return true; }
+
+    DataTypes get_variadic_argument_types_impl() const override {
+        return {std::make_shared<ArgDateType>(), 
std::make_shared<DataTypeString>()};
+    }
+
+    bool use_default_implementation_for_nulls() const override { return false; 
}
+
+    Status close(FunctionContext* context, FunctionContext::FunctionStateScope 
scope) override {
+        return Status::OK();
+    }

Review Comment:
   ditto



-- 
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