This is an automated email from the ASF dual-hosted git repository.
yiguolei pushed a commit to branch branch-4.0
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-4.0 by this push:
new fc5bb58fe80 branch-4.0: [Feature](func) pick some functions (#57559)
fc5bb58fe80 is described below
commit fc5bb58fe80a9822775536e8dada61a260ad6060
Author: linrrarity <[email protected]>
AuthorDate: Mon Nov 3 12:16:11 2025 +0800
branch-4.0: [Feature](func) pick some functions (#57559)
### What problem does this PR solve?
pick: #56691, #56945 #57282 #57369 #57437
---
be/src/vec/functions/function.h | 1 +
.../function_date_or_datetime_computation.cpp | 5 +
.../function_date_or_datetime_computation.h | 201 ++++++++++++++++
.../vec/functions/function_needs_to_handle_null.h | 154 +++++++++++++
.../vec/functions/function_other_types_to_date.cpp | 88 +++++++
be/src/vec/functions/function_string.cpp | 4 +
be/src/vec/functions/function_string.h | 135 +++++------
.../antlr4/org/apache/doris/nereids/DorisParser.g4 | 4 +
.../doris/catalog/BuiltinScalarFunctions.java | 54 +++--
.../nereids/rules/analysis/ExpressionAnalyzer.java | 22 ++
.../rules/analysis/GetFormatFunctionBinder.java | 78 +++++++
.../executable/DateTimeExtractAndTransform.java | 150 ++++++++++++
.../expressions/functions/scalar/GetFormat.java | 75 ++++++
.../expressions/functions/scalar/MakeTime.java | 76 ++++++
.../expressions/functions/scalar/PeriodAdd.java | 69 ++++++
.../expressions/functions/scalar/PeriodDiff.java | 69 ++++++
.../expressions/visitor/ScalarFunctionVisitor.java | 20 ++
.../sql-functions/doc_date_functions_test.out | 26 +++
.../datetime_functions/test_date_function.out | 59 +++++
.../datetime_functions/test_date_function_v2.out | 81 +++++++
.../string_functions/test_string_function.out | 256 +++++++++++++++++++++
.../sql-functions/doc_date_functions_test.groovy | 131 +++++++----
.../nereids_function_p0/scalar_function/L.groovy | 12 +
.../datetime_functions/test_date_function.groovy | 34 +++
.../test_date_function_v2.groovy | 68 ++++++
.../string_functions/test_string_function.groovy | 123 +++++++++-
26 files changed, 1841 insertions(+), 154 deletions(-)
diff --git a/be/src/vec/functions/function.h b/be/src/vec/functions/function.h
index 3dab7b782ae..e944ae15a09 100644
--- a/be/src/vec/functions/function.h
+++ b/be/src/vec/functions/function.h
@@ -32,6 +32,7 @@
#include "common/logging.h"
#include "common/status.h"
#include "olap/rowset/segment_v2/inverted_index_iterator.h" // IWYU pragma:
keep
+#include "runtime/define_primitive_type.h"
#include "udf/udf.h"
#include "vec/core/block.h"
#include "vec/core/column_numbers.h"
diff --git a/be/src/vec/functions/function_date_or_datetime_computation.cpp
b/be/src/vec/functions/function_date_or_datetime_computation.cpp
index cf76fdac986..29ba8147c1d 100644
--- a/be/src/vec/functions/function_date_or_datetime_computation.cpp
+++ b/be/src/vec/functions/function_date_or_datetime_computation.cpp
@@ -67,6 +67,8 @@ using FunctionSecToTime =
FunctionCurrentDateOrDateTime<SecToTimeImpl>;
using FunctionMicroSecToDateTime = TimestampToDateTime<MicroSec>;
using FunctionMilliSecToDateTime = TimestampToDateTime<MilliSec>;
using FunctionSecToDateTime = TimestampToDateTime<Sec>;
+using FunctionPeriodAdd = FunctionNeedsToHandleNull<PeriodAddImpl,
PrimitiveType::TYPE_BIGINT>;
+using FunctionPeriodDiff = FunctionNeedsToHandleNull<PeriodDiffImpl,
PrimitiveType::TYPE_BIGINT>;
void register_function_date_time_computation(SimpleFunctionFactory& factory) {
factory.register_function<FunctionDateDiff>();
@@ -98,6 +100,9 @@ void
register_function_date_time_computation(SimpleFunctionFactory& factory) {
factory.register_function<FunctionSecToDateTime>();
factory.register_function<FunctionMonthsBetween>();
factory.register_function<FunctionTime>();
+ factory.register_function<FunctionGetFormat>();
+ factory.register_function<FunctionPeriodAdd>();
+ factory.register_function<FunctionPeriodDiff>();
// alias
factory.register_alias("days_add", "date_add");
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 d61d11932f0..447001152ae 100644
--- a/be/src/vec/functions/function_date_or_datetime_computation.h
+++ b/be/src/vec/functions/function_date_or_datetime_computation.h
@@ -59,6 +59,7 @@
#include "vec/functions/datetime_errors.h"
#include "vec/functions/function.h"
#include "vec/functions/function_helpers.h"
+#include "vec/functions/function_needs_to_handle_null.h"
#include "vec/runtime/time_value.h"
#include "vec/runtime/vdatetime_value.h"
#include "vec/utils/util.hpp"
@@ -1418,5 +1419,205 @@ public:
return Status::OK();
}
};
+
+class FunctionGetFormat : public IFunction {
+public:
+ static constexpr auto name = "get_format";
+ static FunctionPtr create() { return
std::make_shared<FunctionGetFormat>(); }
+ 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 {
+ return make_nullable(std::make_shared<DataTypeString>());
+ }
+
+ Status execute_impl(FunctionContext* context, Block& block, const
ColumnNumbers& arguments,
+ uint32_t result, size_t input_rows_count) const
override {
+ const auto& [left_col_ptr, left_is_const] =
+ unpack_if_const(block.get_by_position(arguments[0]).column);
+ const auto& [right_col_ptr, right_is_const] =
+ unpack_if_const(block.get_by_position(arguments[1]).column);
+
+ const auto* left_col = assert_cast<const
ColumnString*>(left_col_ptr.get());
+ const auto* right_col = assert_cast<const
ColumnString*>(right_col_ptr.get());
+
+ auto type_ref = left_col->get_data_at(0);
+ std::string type_str(type_ref.data, type_ref.size);
+
+ auto res_col = ColumnString::create();
+ auto res_null_map = ColumnUInt8::create(input_rows_count, 0);
+ auto& res_data = res_col->get_chars();
+ auto& res_offsets = res_col->get_offsets();
+
+ if (type_str == DATE_NAME) {
+ execute_format_type<DateFormatImpl>(res_data, res_offsets,
res_null_map->get_data(),
+ input_rows_count, right_col);
+ } else if (type_str == DATETIME_NAME) {
+ execute_format_type<DateTimeFormatImpl>(res_data, res_offsets,
res_null_map->get_data(),
+ input_rows_count,
right_col);
+ } else if (type_str == TIME_NAME) {
+ execute_format_type<TimeFormatImpl>(res_data, res_offsets,
res_null_map->get_data(),
+ input_rows_count, right_col);
+ } else {
+ return Status::InvalidArgument(
+ "Function GET_FORMAT only support DATE, DATETIME or TIME");
+ }
+
+ block.replace_by_position(
+ result, ColumnNullable::create(std::move(res_col),
std::move(res_null_map)));
+ return Status::OK();
+ }
+
+private:
+ template <typename Impl>
+ static void execute_format_type(ColumnString::Chars& res_data,
+ ColumnString::Offsets& res_offsets,
+ PaddedPODArray<UInt8>& res_null_map,
size_t input_rows_count,
+ const ColumnString* right_col) {
+ res_data.reserve(input_rows_count * Impl::ESTIMATE_SIZE);
+ res_offsets.reserve(input_rows_count);
+
+ for (int i = 0; i < input_rows_count; ++i) {
+ StringRef format_ref = right_col->get_data_at(i);
+ std::string format_str(format_ref.data, format_ref.size);
+ std::transform(format_str.begin(), format_str.end(),
format_str.begin(), ::toupper);
+
+ std::string_view format_res;
+ if (format_str == "USA") {
+ format_res = Impl::USA;
+ } else if (format_str == "JIS" || format_str == "ISO") {
+ format_res = Impl::JIS_ISO;
+ } else if (format_str == "EUR") {
+ format_res = Impl::EUR;
+ } else if (format_str == "INTERNAL") {
+ format_res = Impl::INTERNAL;
+ } else {
+ res_null_map[i] = 1;
+ res_offsets.push_back(res_data.size());
+ continue;
+ }
+
+ res_data.insert(format_res.data(), format_res.data() +
format_res.size());
+ res_offsets.push_back(res_data.size());
+ }
+ }
+
+ struct DateFormatImpl {
+ static constexpr auto USA = "%m.%d.%Y";
+ static constexpr auto JIS_ISO = "%Y-%m-%d";
+ static constexpr auto EUR = "%d.%m.%Y";
+ static constexpr auto INTERNAL = "%Y%m%d";
+ static constexpr size_t ESTIMATE_SIZE = 8;
+ };
+
+ struct DateTimeFormatImpl {
+ static constexpr auto USA = "%Y-%m-%d %H.%i.%s";
+ static constexpr auto JIS_ISO = "%Y-%m-%d %H:%i:%s";
+ static constexpr auto EUR = "%Y-%m-%d %H.%i.%s";
+ static constexpr auto INTERNAL = "%Y%m%d%H%i%s";
+ static constexpr size_t ESTIMATE_SIZE = 17;
+ };
+
+ struct TimeFormatImpl {
+ static constexpr auto USA = "%h:%i:%s %p";
+ static constexpr auto JIS_ISO = "%H:%i:%s";
+ static constexpr auto EUR = "%H.%i.%s";
+ static constexpr auto INTERNAL = "%H%i%s";
+ static constexpr size_t ESTIMATE_SIZE = 11;
+ };
+
+ static constexpr auto DATE_NAME = "DATE";
+ static constexpr auto DATETIME_NAME = "DATETIME";
+ static constexpr auto TIME_NAME = "TIME";
+};
+
+class PeriodHelper {
+public:
+ // For two digit year, 70-99 -> 1970-1999, 00-69 -> 2000-2069
+ // this rule is same as MySQL
+ static constexpr int YY_PART_YEAR = 70;
+ static Status valid_period(int64_t period) {
+ if (period <= 0 || (period % 100) == 0 || (period % 100) > 12) {
+ return Status::InvalidArgument("Period function got invalid
period: {}", period);
+ }
+ return Status::OK();
+ }
+
+ static int64_t check_and_convert_period_to_month(uint64_t period) {
+ THROW_IF_ERROR(valid_period(period));
+ uint64_t year = period / 100;
+ if (year < 100) {
+ year += (year >= YY_PART_YEAR) ? 1900 : 2000;
+ }
+ return year * 12LL + (period % 100) - 1;
+ }
+
+ static int64_t convert_month_to_period(uint64_t month) {
+ uint64_t year = month / 12;
+ if (year < 100) {
+ year += (year >= YY_PART_YEAR) ? 1900 : 2000;
+ }
+ return year * 100 + month % 12 + 1;
+ }
+};
+
+class PeriodAddImpl {
+public:
+ static constexpr auto name = "period_add";
+ static size_t get_number_of_arguments() { return 2; }
+ static DataTypePtr get_return_type_impl(const DataTypes& arguments) {
+ return std::make_shared<DataTypeInt64>();
+ }
+
+ static void execute(const std::vector<ColumnWithConstAndNullMap>&
cols_info,
+ ColumnInt64::MutablePtr& res_col,
PaddedPODArray<UInt8>& res_null_map_data,
+ size_t input_rows_count) {
+ const auto& left_data =
+ assert_cast<const
ColumnInt64*>(cols_info[0].nested_col)->get_data();
+ const auto& right_data =
+ assert_cast<const
ColumnInt64*>(cols_info[1].nested_col)->get_data();
+ for (size_t i = 0; i < input_rows_count; ++i) {
+ if (cols_info[0].is_null_at(i) || cols_info[1].is_null_at(i)) {
+ res_col->insert_default();
+ res_null_map_data[i] = 1;
+ continue;
+ }
+
+ int64_t period = left_data[index_check_const(i,
cols_info[0].is_const)];
+ int64_t months = right_data[index_check_const(i,
cols_info[1].is_const)];
+ res_col->insert_value(PeriodHelper::convert_month_to_period(
+ PeriodHelper::check_and_convert_period_to_month(period) +
months));
+ }
+ }
+};
+class PeriodDiffImpl {
+public:
+ static constexpr auto name = "period_diff";
+ static size_t get_number_of_arguments() { return 2; }
+ static DataTypePtr get_return_type_impl(const DataTypes& arguments) {
+ return std::make_shared<DataTypeInt64>();
+ }
+
+ static void execute(const std::vector<ColumnWithConstAndNullMap>&
cols_info,
+ ColumnInt64::MutablePtr& res_col,
PaddedPODArray<UInt8>& res_null_map_data,
+ size_t input_rows_count) {
+ const auto& left_data =
+ assert_cast<const
ColumnInt64*>(cols_info[0].nested_col)->get_data();
+ const auto& right_data =
+ assert_cast<const
ColumnInt64*>(cols_info[1].nested_col)->get_data();
+ for (size_t i = 0; i < input_rows_count; ++i) {
+ if (cols_info[0].is_null_at(i) || cols_info[1].is_null_at(i)) {
+ res_col->insert_default();
+ res_null_map_data[i] = 1;
+ continue;
+ }
+
+ int64_t period1 = left_data[index_check_const(i,
cols_info[0].is_const)];
+ int64_t period2 = right_data[index_check_const(i,
cols_info[1].is_const)];
+
res_col->insert_value(PeriodHelper::check_and_convert_period_to_month(period1) -
+
PeriodHelper::check_and_convert_period_to_month(period2));
+ }
+ }
+};
+
#include "common/compile_check_avoid_end.h"
} // namespace doris::vectorized
diff --git a/be/src/vec/functions/function_needs_to_handle_null.h
b/be/src/vec/functions/function_needs_to_handle_null.h
new file mode 100644
index 00000000000..0e60da92e68
--- /dev/null
+++ b/be/src/vec/functions/function_needs_to_handle_null.h
@@ -0,0 +1,154 @@
+// 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.
+#pragma once
+#include <boost/mpl/aux_/na_fwd.hpp>
+
+#include "vec/functions/function.h"
+
+namespace doris::vectorized {
+#include "common/compile_check_begin.h"
+
+// Helper struct to store information about const+nullable columns
+struct ColumnWithConstAndNullMap {
+ const IColumn* nested_col = nullptr;
+ const NullMap* null_map = nullptr;
+ bool is_const = false;
+
+ bool is_null_at(size_t row) const { return (null_map &&
(*null_map)[is_const ? 0 : row]); }
+};
+
+// For functions that need to handle const+nullable column combinations
+// means that functioin `use_default_implementation_for_nulls()` returns false
+template <typename Impl, PrimitiveType ResultPrimitiveType>
+class FunctionNeedsToHandleNull : public IFunction {
+public:
+ using ResultColumnType =
PrimitiveTypeTraits<ResultPrimitiveType>::ColumnType;
+
+ static constexpr auto name = Impl::name;
+ String get_name() const override { return name; }
+
+ static std::shared_ptr<IFunction> create() {
+ return std::make_shared<FunctionNeedsToHandleNull>();
+ }
+
+ size_t get_number_of_arguments() const override { return
Impl::get_number_of_arguments(); }
+
+ bool is_variadic() const override {
+ if constexpr (requires { Impl::is_variadic(); }) {
+ return Impl::is_variadic();
+ }
+ return false;
+ }
+
+ bool use_default_implementation_for_nulls() const override { return false;
}
+
+ DataTypePtr get_return_type_impl(const DataTypes& arguments) const
override {
+ return Impl::get_return_type_impl(arguments);
+ }
+
+ Status execute_impl(FunctionContext* context, Block& block, const
ColumnNumbers& arguments,
+ uint32_t result, size_t input_rows_count) const
override {
+ auto res_col = ResultColumnType::create();
+ auto null_map = ColumnUInt8::create();
+ auto& null_map_data = null_map->get_data();
+ res_col->reserve(input_rows_count);
+ null_map_data.resize_fill(input_rows_count, 0);
+
+ const size_t arg_size = arguments.size();
+
+ std::vector<ColumnWithConstAndNullMap> columns_info;
+ columns_info.resize(arg_size);
+ bool has_nullable = false;
+ collect_columns_info(columns_info, block, arguments, has_nullable);
+
+ // Check if there is a const null
+ for (size_t i = 0; i < arg_size; ++i) {
+ if (columns_info[i].is_const && columns_info[i].null_map &&
+ (*columns_info[i].null_map)[0] &&
+ execute_const_null(res_col, null_map_data, input_rows_count,
i)) {
+ block.replace_by_position(
+ result, ColumnNullable::create(std::move(res_col),
std::move(null_map)));
+ return Status::OK();
+ }
+ }
+
+ Impl::execute(columns_info, res_col, null_map_data, input_rows_count);
+
+ if (is_return_nullable(has_nullable, columns_info)) {
+ block.replace_by_position(
+ result, ColumnNullable::create(std::move(res_col),
std::move(null_map)));
+ } else {
+ block.replace_by_position(result, std::move(res_col));
+ }
+
+ return Status::OK();
+ }
+
+private:
+ // Handle a NULL literal
+ // Default behavior is fill result with all NULLs
+ // return true when the res_col is ready to be written back to the block
without further processing
+ bool execute_const_null(typename ResultColumnType::MutablePtr& res_col,
+ PaddedPODArray<UInt8>& res_null_map_data, size_t
input_rows_count,
+ size_t null_index) const {
+ if constexpr (requires {
+ Impl::execute_const_null(res_col, res_null_map_data,
input_rows_count,
+ null_index);
+ }) {
+ return Impl::execute_const_null(res_col, res_null_map_data,
input_rows_count,
+ null_index);
+ }
+
+ res_col->insert_many_defaults(input_rows_count);
+ res_null_map_data.assign(input_rows_count, (UInt8)1);
+
+ return true;
+ }
+
+ // Collect the required information for each column into columns_info
+ // Including whether it is a constant column, nested column and null
map(if exists).
+ void collect_columns_info(std::vector<ColumnWithConstAndNullMap>&
columns_info,
+ const Block& block, const ColumnNumbers&
arguments,
+ bool& has_nullable) const {
+ for (size_t i = 0; i < arguments.size(); ++i) {
+ ColumnPtr col_ptr;
+ const auto& col_with_type = block.get_by_position(arguments[i]);
+ std::tie(col_ptr, columns_info[i].is_const) =
unpack_if_const(col_with_type.column);
+
+ if (is_column_nullable(*col_ptr)) {
+ has_nullable = true;
+ const auto* nullable =
check_and_get_column<ColumnNullable>(col_ptr.get());
+ columns_info[i].nested_col = &nullable->get_nested_column();
+ columns_info[i].null_map = &nullable->get_null_map_data();
+ } else {
+ columns_info[i].nested_col = col_ptr.get();
+ }
+ }
+ }
+
+ // Determine if the return type should be wrapped in nullable
+ // Default behavior is return nullable if any argument is nullable
+ bool is_return_nullable(bool has_nullable,
+ const std::vector<ColumnWithConstAndNullMap>&
cols_info) const {
+ if constexpr (requires { Impl::is_return_nullable(has_nullable,
cols_info); }) {
+ return Impl::is_return_nullable(has_nullable, cols_info);
+ }
+ return has_nullable;
+ }
+};
+#include "common/compile_check_end.h"
+} // namespace doris::vectorized
\ No newline at end of file
diff --git a/be/src/vec/functions/function_other_types_to_date.cpp
b/be/src/vec/functions/function_other_types_to_date.cpp
index 2c35d4138bc..0d0ba8ffa2b 100644
--- a/be/src/vec/functions/function_other_types_to_date.cpp
+++ b/be/src/vec/functions/function_other_types_to_date.cpp
@@ -44,6 +44,7 @@
#include "vec/columns/column_string.h"
#include "vec/columns/column_vector.h"
#include "vec/common/assert_cast.h"
+#include "vec/common/pod_array.h"
#include "vec/common/pod_array_fwd.h"
#include "vec/common/string_ref.h"
#include "vec/core/block.h"
@@ -62,6 +63,7 @@
#include "vec/functions/datetime_errors.h"
#include "vec/functions/function.h"
#include "vec/functions/simple_function_factory.h"
+#include "vec/runtime/time_value.h"
#include "vec/runtime/vdatetime_value.h"
#include "vec/utils/util.hpp"
@@ -379,6 +381,91 @@ private:
}
};
+struct MakeTimeImpl {
+ static constexpr auto name = "maketime";
+ using DateValueType =
PrimitiveTypeTraits<PrimitiveType::TYPE_TIMEV2>::CppType;
+ using NativeType =
PrimitiveTypeTraits<PrimitiveType::TYPE_TIMEV2>::CppNativeType;
+ static bool is_variadic() { return false; }
+ static size_t get_number_of_arguments() { return 3; }
+ static DataTypes get_variadic_argument_types() { return {}; }
+ static DataTypePtr get_return_type_impl(const DataTypes& arguments) {
+ return make_nullable(std::make_shared<DataTypeTimeV2>());
+ }
+
+ static Status execute(FunctionContext* context, Block& block, const
ColumnNumbers& arguments,
+ uint32_t result, size_t input_rows_count) {
+ DCHECK_EQ(arguments.size(), 3);
+ auto res_col = ColumnTimeV2::create(input_rows_count);
+ auto res_null_map = ColumnUInt8::create(input_rows_count, 0);
+ auto& res_data = res_col->get_data();
+
+ ColumnPtr arg_col[3];
+ bool is_const[3];
+ for (int i = 0; i < arguments.size(); ++i) {
+ std::tie(arg_col[i], is_const[i]) =
+
unpack_if_const(block.get_by_position(arguments[i]).column);
+ }
+
+ const auto& hour_data = assert_cast<const
ColumnInt64*>(arg_col[0].get())->get_data();
+ const auto& min_data = assert_cast<const
ColumnInt64*>(arg_col[1].get())->get_data();
+ if (const auto* sec_col =
check_and_get_column<ColumnFloat64>(arg_col[2].get())) {
+ for (int i = 0; i < input_rows_count; ++i) {
+ int64_t hour = hour_data[index_check_const(i, is_const[0])];
+ int64_t minute = min_data[index_check_const(i, is_const[1])];
+ double sec = sec_col->get_element(index_check_const(i,
is_const[2]));
+ if (!check_and_set_time_value(hour, minute, sec)) {
+ res_data[i] = 0;
+ res_null_map->get_data()[i] = 1;
+ continue;
+ }
+ execute_single(hour, minute, sec, res_data, i);
+ }
+ } else {
+ const auto& sec_data = assert_cast<const
ColumnInt64*>(arg_col[2].get())->get_data();
+ for (int i = 0; i < input_rows_count; ++i) {
+ int64_t hour = hour_data[index_check_const(i, is_const[0])];
+ int64_t minute = min_data[index_check_const(i, is_const[1])];
+ double sec = static_cast<double>(sec_data[index_check_const(i,
is_const[2])]);
+ if (!check_and_set_time_value(hour, minute, sec)) {
+ res_data[i] = 0;
+ res_null_map->get_data()[i] = 1;
+ continue;
+ }
+ execute_single(hour, minute, sec, res_data, i);
+ }
+ }
+
+ block.replace_by_position(
+ result, ColumnNullable::create(std::move(res_col),
std::move(res_null_map)));
+ return Status::OK();
+ }
+
+private:
+ static bool check_and_set_time_value(int64_t& hour, int64_t& minute,
double& sec) {
+ static constexpr int MAX_HOUR_FOR_MAKETIME = 838;
+ if (minute < 0 || minute >= 60 || sec < 0 || sec >= 60) {
+ return false;
+ }
+
+ // Avoid overflow in `execute_single`
+ // the case {838, 59, 59.999999} will be slove in
`TimeValue::from_double_with_limit`
+ if (std::abs(hour) > MAX_HOUR_FOR_MAKETIME) {
+ hour = hour > 0 ? MAX_HOUR_FOR_MAKETIME : -MAX_HOUR_FOR_MAKETIME;
+ minute = sec = 59;
+ }
+ return true;
+ }
+
+ static void execute_single(int64_t hour, int64_t minute, double sec,
+ PaddedPODArray<double>& res_data, size_t row) {
+ // Round sec to 6 decimal places (microsecond precision)
+ double total_sec =
+ std::abs(hour) * 3600 + minute * 60 + std::round(sec *
1000000.0) / 1000000.0;
+
+ res_data[row] = TimeValue::from_double_with_limit(total_sec * (hour <
0 ? -1 : 1));
+ }
+};
+
struct DateTruncState {
using Callback_function = std::function<void(const ColumnPtr&, ColumnPtr&
res, size_t)>;
Callback_function callback_function;
@@ -1360,6 +1447,7 @@ void register_function_timestamp(SimpleFunctionFactory&
factory) {
factory.register_function<FunctionStrToDate>();
factory.register_function<FunctionStrToDatetime>();
factory.register_function<FunctionMakeDate>();
+ factory.register_function<FunctionOtherTypesToDateType<MakeTimeImpl>>();
factory.register_function<FromDays>();
factory.register_function<FunctionDateTruncDateV2>();
factory.register_function<FunctionDateTruncDatetimeV2>();
diff --git a/be/src/vec/functions/function_string.cpp
b/be/src/vec/functions/function_string.cpp
index 7a6c71eadbe..c92a1a268f3 100644
--- a/be/src/vec/functions/function_string.cpp
+++ b/be/src/vec/functions/function_string.cpp
@@ -1334,6 +1334,8 @@ using FunctionStringAppendTrailingCharIfAbsent =
using FunctionStringLPad = FunctionStringPad<StringLPad>;
using FunctionStringRPad = FunctionStringPad<StringRPad>;
+using FunctionMakeSet = FunctionNeedsToHandleNull<MakeSetImpl,
PrimitiveType::TYPE_STRING>;
+
void register_function_string(SimpleFunctionFactory& factory) {
factory.register_function<FunctionStringParseDataSize>();
factory.register_function<FunctionStringASCII>();
@@ -1443,6 +1445,8 @@ void register_function_string(SimpleFunctionFactory&
factory) {
factory.register_alias(FunctionStringDigestMulti<SM3Sum>::name, "sm3");
factory.register_alias(FunctionStringDigestSHA1::name, "sha");
factory.register_alias(FunctionStringLocatePos::name, "position");
+ factory.register_alias(FunctionStringLength::name, "octet_length");
+ factory.register_alias(FunctionOverlay::name, "insert");
}
} // namespace doris::vectorized
diff --git a/be/src/vec/functions/function_string.h
b/be/src/vec/functions/function_string.h
index f131baeceda..0218526ef68 100644
--- a/be/src/vec/functions/function_string.h
+++ b/be/src/vec/functions/function_string.h
@@ -68,6 +68,7 @@
#include "vec/core/column_with_type_and_name.h"
#include "vec/core/types.h"
#include "vec/data_types/data_type.h"
+#include "vec/functions/function_needs_to_handle_null.h"
#include "vec/utils/template_helpers.hpp"
#ifndef USE_LIBCPP
@@ -4995,106 +4996,76 @@ private:
}
};
-class FunctionMakeSet : public IFunction {
+class MakeSetImpl {
public:
static constexpr auto name = "make_set";
- static FunctionPtr create() { return std::make_shared<FunctionMakeSet>(); }
- String get_name() const override { return name; }
- size_t get_number_of_arguments() const override { return 0; }
- bool is_variadic() const override { return true; }
- bool use_default_implementation_for_nulls() const override { return false;
}
- DataTypePtr get_return_type_impl(const DataTypes& arguments) const
override {
+
+ static size_t get_number_of_arguments() { return 0; }
+ static bool is_variadic() { return true; }
+ static DataTypePtr get_return_type_impl(const DataTypes& arguments) {
if (arguments[0].get()->is_nullable()) {
return make_nullable(std::make_shared<DataTypeString>());
}
return std::make_shared<DataTypeString>();
}
- Status execute_impl(FunctionContext* context, Block& block, const
ColumnNumbers& arguments,
- uint32_t result, size_t input_rows_count) const
override {
- auto res_col = ColumnString::create();
- auto null_map = ColumnUInt8::create();
-
- const auto& [bit_col, bit_const] =
- unpack_if_const(block.get_by_position(arguments[0]).column);
-
- if (bit_const) {
- if (bit_col->is_null_at(0)) {
- res_col->insert_many_defaults(input_rows_count);
- null_map->insert_many_vals(1, input_rows_count);
- } else {
- const uint64_t bit_data =
- assert_cast<const
ColumnInt64*>(bit_col.get())->get_element(0);
- vector_execute<true>(block, arguments, input_rows_count,
*res_col, bit_data,
- null_map->get_data());
- }
- } else if (const auto* bit_data =
check_and_get_column<ColumnNullable>(bit_col.get())) {
- null_map->insert_range_from(bit_data->get_null_map_column(), 0,
input_rows_count);
- vector_execute<false>(block, arguments, input_rows_count, *res_col,
- assert_cast<const
ColumnInt64&>(bit_data->get_nested_column()),
- null_map->get_data());
+ static bool is_return_nullable(bool has_nullable,
+ const
std::vector<ColumnWithConstAndNullMap>& cols_info) {
+ return cols_info[0].null_map != nullptr;
+ }
- } else {
- null_map->get_data().resize_fill(input_rows_count, 0);
- vector_execute<false>(block, arguments, input_rows_count, *res_col,
- assert_cast<const
ColumnInt64&>(*bit_col.get()),
- null_map->get_data());
+ static bool execute_const_null(ColumnString::MutablePtr& res_col,
+ PaddedPODArray<UInt8>& res_null_map_data,
+ size_t input_rows_count, size_t null_index)
{
+ if (null_index == 1) {
+ res_col->insert_many_defaults(input_rows_count);
+ res_null_map_data.assign(input_rows_count, (UInt8)1);
+ return true;
}
+ return false;
+ }
- if (block.get_by_position(arguments[0]).type.get()->is_nullable()) {
- block.replace_by_position(
- result, ColumnNullable::create(std::move(res_col),
std::move(null_map)));
- } else {
- block.replace_by_position(result, std::move(res_col));
+ static void execute(const std::vector<ColumnWithConstAndNullMap>&
column_infos,
+ ColumnString::MutablePtr& res_col,
PaddedPODArray<UInt8>& res_null_map_data,
+ size_t input_rows_count) {
+ static constexpr char SEPARATOR = ',';
+ const auto& bit_data =
+ assert_cast<const
ColumnInt64&>(*column_infos[0].nested_col).get_data();
+ std::vector<const ColumnString*> str_cols(column_infos.size());
+ for (size_t i = 1; i < column_infos.size(); ++i) {
+ str_cols[i] = assert_cast<const
ColumnString*>(column_infos[i].nested_col);
}
- return Status::OK();
- }
-private:
- template <bool bit_const>
- void vector_execute(const Block& block, const ColumnNumbers& arguments,
size_t input_rows_count,
- ColumnString& res_col, const ColumnInt64& bit_col,
- PaddedPODArray<uint8_t>& null_map) const {
- if constexpr (bit_const) {
- uint64_t bit = bit_col.get_element(0);
- for (size_t i = 0; i < input_rows_count; ++i) {
- execute_one_row(block, arguments, res_col, bit, i);
+ for (size_t row = 0; row < input_rows_count; ++row) {
+ if (column_infos[0].is_null_at(row)) {
+ res_col->insert_default();
+ res_null_map_data[row] = 1;
+ continue;
}
- } else {
- for (size_t i = 0; i < input_rows_count; ++i) {
- if (null_map[i]) {
- res_col.insert_default();
- continue;
+
+ uint64_t bit = bit_data[column_infos[0].is_const ? 0 : row];
+ uint64_t col_pos = __builtin_ffsll(bit);
+ ColumnString::Chars data;
+ while (col_pos != 0 && col_pos < column_infos.size() && bit != 0) {
+ if (!column_infos[col_pos].is_null_at(row)) {
+ /* Here insert `str,` directly to support the case below:
+ * SELECT MAKE_SET(3, '', 'a');
+ * the exception result should be ',a'.
+ */
+ auto s_ref = str_cols[col_pos]->get_data_at(
+ column_infos[col_pos].is_const ? 0 : row);
+ data.insert(s_ref.data, s_ref.data + s_ref.size);
+ data.push_back(SEPARATOR);
}
- execute_one_row(block, arguments, res_col,
bit_col.get_element(i), i);
+ bit &= ~(1ULL << (col_pos - 1));
+ col_pos = __builtin_ffsll(bit);
}
- }
- }
-
- void execute_one_row(const Block& block, const ColumnNumbers& arguments,
ColumnString& res_col,
- uint64_t bit, int row_num) const {
- static constexpr char SEPARATOR = ',';
- uint64_t pos = __builtin_ffsll(bit);
- ColumnString::Chars data;
- while (pos != 0 && pos < arguments.size() && bit != 0) {
- auto col = block.get_by_position(arguments[pos]).column;
- if (!col->is_null_at(row_num)) {
- /* Here insert `str,` directly to support the case below:
- * SELECT MAKE_SET(3, '', 'a');
- * the exception result should be ',a'
- */
- auto s_ref = col->get_data_at(row_num);
- data.insert(s_ref.data, s_ref.data + s_ref.size);
- data.push_back(SEPARATOR);
+ // remove the last ','
+ if (!data.empty()) {
+ data.pop_back();
}
- bit &= ~(1ULL << (pos - 1));
- pos = __builtin_ffsll(bit);
+ res_col->insert_data(reinterpret_cast<const char*>(data.data()),
data.size());
}
- // remove the last ','
- if (!data.empty()) {
- data.pop_back();
- }
- res_col.insert_data(reinterpret_cast<const char*>(data.data()),
data.size());
}
};
diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
index c4649068c24..14b02187173 100644
--- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
+++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
@@ -1605,6 +1605,8 @@ primaryExpression
(ORDER BY sortItem (COMMA sortItem)*)?
(SEPARATOR sep=expression)? RIGHT_PAREN
(OVER windowSpec)?
#groupConcat
+ | GET_FORMAT LEFT_PAREN
+ expression COMMA expression RIGHT_PAREN
#getFormatFunction
| TRIM LEFT_PAREN
((BOTH | LEADING | TRAILING) expression? | expression) FROM expression
RIGHT_PAREN #trim
| (SUBSTR | SUBSTRING | MID) LEFT_PAREN
@@ -1998,6 +2000,7 @@ nonReserved
| FRONTENDS
| FUNCTION
| GENERATED
+ | GET_FORMAT
| GENERIC
| GLOBAL
| GRAPH
@@ -2022,6 +2025,7 @@ nonReserved
| IMMEDIATE
| INCREMENTAL
| INDEXES
+ | INSERT
| INVERTED
| IP_TRIE
| IPV4
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
b/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
index 064dc3c24d2..cefc5dc6eb5 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
@@ -220,6 +220,7 @@ import
org.apache.doris.nereids.trees.expressions.functions.scalar.FromSecond;
import
org.apache.doris.nereids.trees.expressions.functions.scalar.FromUnixtime;
import org.apache.doris.nereids.trees.expressions.functions.scalar.G;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Gcd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.GetFormat;
import
org.apache.doris.nereids.trees.expressions.functions.scalar.GetVariantType;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Greatest;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Grouping;
@@ -311,6 +312,7 @@ import
org.apache.doris.nereids.trees.expressions.functions.scalar.Ltrim;
import org.apache.doris.nereids.trees.expressions.functions.scalar.LtrimIn;
import org.apache.doris.nereids.trees.expressions.functions.scalar.MakeDate;
import org.apache.doris.nereids.trees.expressions.functions.scalar.MakeSet;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MakeTime;
import
org.apache.doris.nereids.trees.expressions.functions.scalar.MapContainsEntry;
import
org.apache.doris.nereids.trees.expressions.functions.scalar.MapContainsKey;
import
org.apache.doris.nereids.trees.expressions.functions.scalar.MapContainsValue;
@@ -369,6 +371,8 @@ import
org.apache.doris.nereids.trees.expressions.functions.scalar.Overlay;
import
org.apache.doris.nereids.trees.expressions.functions.scalar.ParseDataSize;
import org.apache.doris.nereids.trees.expressions.functions.scalar.ParseUrl;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Password;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.PeriodAdd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.PeriodDiff;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Pi;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Pmod;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Positive;
@@ -551,6 +555,16 @@ public class BuiltinScalarFunctions implements
FunctionHelper {
scalar(Abs.class, "abs"),
scalar(Acos.class, "acos"),
scalar(Acosh.class, "acosh"),
+ scalar(AITranslate.class, "ai_translate"),
+ scalar(AISentiment.class, "ai_sentiment"),
+ scalar(AIFilter.class, "ai_filter"),
+ scalar(AIFixGrammar.class, "ai_fixgrammar"),
+ scalar(AIExtract.class, "ai_extract"),
+ scalar(AIGenerate.class, "ai_generate"),
+ scalar(AIClassify.class, "ai_classify"),
+ scalar(AIMask.class, "ai_mask"),
+ scalar(AISummarize.class, "ai_summarize"),
+ scalar(AISimilarity.class, "ai_similarity"),
scalar(AesDecrypt.class, "aes_decrypt"),
scalar(AesEncrypt.class, "aes_encrypt"),
scalar(AppendTrailingCharIfAbsent.class,
"append_trailing_char_if_absent"),
@@ -651,6 +665,7 @@ public class BuiltinScalarFunctions implements
FunctionHelper {
scalar(Char.class, "char"),
scalar(CharacterLength.class, "char_length", "character_length"),
scalar(Coalesce.class, "coalesce"),
+ scalar(Compress.class, "compress"),
scalar(Concat.class, "concat"),
scalar(ConcatWs.class, "concat_ws"),
scalar(ConnectionId.class, "connection_id"),
@@ -705,6 +720,7 @@ public class BuiltinScalarFunctions implements
FunctionHelper {
scalar(E.class, "e"),
scalar(ElementAt.class, "element_at"),
scalar(Elt.class, "elt"),
+ scalar(Embed.class, "embed"),
scalar(EncodeAsSmallInt.class, "encode_as_smallint"),
scalar(EncodeAsInt.class, "encode_as_int"),
scalar(EncodeAsBigInt.class, "encode_as_bigint"),
@@ -713,6 +729,7 @@ public class BuiltinScalarFunctions implements
FunctionHelper {
scalar(EsQuery.class, "esquery"),
scalar(Even.class, "even"),
scalar(Exp.class, "exp"),
+ scalar(ExportSet.class, "export_set"),
scalar(ExtractUrlParameter.class, "extract_url_parameter"),
scalar(Field.class, "field"),
scalar(FindInSet.class, "find_in_set"),
@@ -730,6 +747,7 @@ public class BuiltinScalarFunctions implements
FunctionHelper {
scalar(FromUnixtime.class, "from_unixtime"),
scalar(G.class, "g"),
scalar(Gcd.class, "gcd"),
+ scalar(GetFormat.class, "get_format"),
scalar(GetVariantType.class, "variant_type"),
scalar(Greatest.class, "greatest"),
scalar(Grouping.class, "grouping"),
@@ -810,10 +828,11 @@ public class BuiltinScalarFunctions implements
FunctionHelper {
scalar(L2DistanceApproximate.class, "l2_distance_approximate"),
scalar(L2Distance.class, "l2_distance"),
scalar(LastDay.class, "last_day"),
+ scalar(LastQueryId.class, "last_query_id"),
scalar(Lcm.class, "lcm"),
scalar(Least.class, "least"),
scalar(Left.class, "left", "strleft"),
- scalar(Length.class, "length"),
+ scalar(Length.class, "length", "octet_length"),
scalar(Crc32.class, "crc32"),
scalar(Crc32Internal.class, "crc32_internal"),
scalar(Like.class, "like"),
@@ -827,6 +846,8 @@ public class BuiltinScalarFunctions implements
FunctionHelper {
scalar(Ltrim.class, "ltrim"),
scalar(LtrimIn.class, "ltrim_in"),
scalar(MakeDate.class, "makedate"),
+ scalar(MakeSet.class, "make_set"),
+ scalar(MakeTime.class, "maketime"),
scalar(MapContainsEntry.class, "map_contains_entry"),
scalar(MapContainsKey.class, "map_contains_key"),
scalar(MapContainsValue.class, "map_contains_value"),
@@ -861,6 +882,7 @@ public class BuiltinScalarFunctions implements
FunctionHelper {
scalar(MonthsBetween.class, "months_between"),
scalar(MonthsDiff.class, "months_diff"),
scalar(MonthsSub.class, "months_sub"),
+ scalar(MultiMatch.class, "multi_match"),
scalar(MultiMatchAny.class, "multi_match_any"),
scalar(MultiSearchAllPositions.class,
"multi_search_all_positions"),
scalar(MurmurHash332.class, "murmur_hash3_32"),
@@ -879,10 +901,12 @@ public class BuiltinScalarFunctions implements
FunctionHelper {
scalar(NullIf.class, "nullif"),
scalar(NullOrEmpty.class, "null_or_empty"),
scalar(Nvl.class, "ifnull", "nvl"),
- scalar(Overlay.class, "overlay"),
+ scalar(Overlay.class, "overlay", "insert"),
scalar(ParseUrl.class, "parse_url"),
scalar(Password.class, "password"),
scalar(ParseDataSize.class, "parse_data_size"),
+ scalar(PeriodAdd.class, "period_add"),
+ scalar(PeriodDiff.class, "period_diff"),
scalar(Pi.class, "pi"),
scalar(Pmod.class, "pmod"),
scalar(Positive.class, "positive"),
@@ -897,6 +921,7 @@ public class BuiltinScalarFunctions implements
FunctionHelper {
scalar(QuartersDiff.class, "quarters_diff"),
scalar(QuarterFloor.class, "quarter_floor"),
scalar(QuartersSub.class, "quarters_sub"),
+ scalar(Quote.class, "quote"),
scalar(Search.class, "search"),
scalar(Radians.class, "radians"),
scalar(Random.class, "rand", "random"),
@@ -934,6 +959,7 @@ public class BuiltinScalarFunctions implements
FunctionHelper {
scalar(MilliSecondTimestamp.class, "millisecond_timestamp"),
scalar(MicroSecondTimestamp.class, "microsecond_timestamp"),
scalar(RandomBytes.class, "random_bytes"),
+ scalar(SessionUser.class, "session_user"),
scalar(Sha1.class, "sha1", "sha"),
scalar(Sha2.class, "sha2"),
scalar(Sign.class, "sign"),
@@ -1024,7 +1050,8 @@ public class BuiltinScalarFunctions implements
FunctionHelper {
scalar(UnhexNull.class, "unhex_null"),
scalar(UnixTimestamp.class, "unix_timestamp"),
scalar(Upper.class, "ucase", "upper"),
- scalar(Quote.class, "quote"),
+ scalar(Uncompress.class, "uncompress"),
+ scalar(Uniform.class, "uniform"),
scalar(UrlDecode.class, "url_decode"),
scalar(UrlEncode.class, "url_encode"),
scalar(User.class, "user"),
@@ -1053,26 +1080,7 @@ public class BuiltinScalarFunctions implements
FunctionHelper {
scalar(YearWeek.class, "yearweek"),
scalar(YearsAdd.class, "years_add"),
scalar(YearsDiff.class, "years_diff"),
- scalar(YearsSub.class, "years_sub"),
- scalar(MultiMatch.class, "multi_match"),
- scalar(SessionUser.class, "session_user"),
- scalar(LastQueryId.class, "last_query_id"),
- scalar(Compress.class, "compress"),
- scalar(Uncompress.class, "uncompress"),
- scalar(AITranslate.class, "ai_translate"),
- scalar(AISentiment.class, "ai_sentiment"),
- scalar(AIFilter.class, "ai_filter"),
- scalar(AIFixGrammar.class, "ai_fixgrammar"),
- scalar(AIExtract.class, "ai_extract"),
- scalar(AIGenerate.class, "ai_generate"),
- scalar(AIClassify.class, "ai_classify"),
- scalar(AIMask.class, "ai_mask"),
- scalar(AISummarize.class, "ai_summarize"),
- scalar(AISimilarity.class, "ai_similarity"),
- scalar(Embed.class, "embed"),
- scalar(Uniform.class, "uniform"),
- scalar(MakeSet.class, "make_set"),
- scalar(ExportSet.class, "export_set"));
+ scalar(YearsSub.class, "years_sub"));
public static final BuiltinScalarFunctions INSTANCE = new
BuiltinScalarFunctions();
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java
index b61e7923387..bb1b844520e 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java
@@ -92,6 +92,7 @@ import org.apache.doris.nereids.types.ArrayType;
import org.apache.doris.nereids.types.BigIntType;
import org.apache.doris.nereids.types.BooleanType;
import org.apache.doris.nereids.types.DataType;
+import org.apache.doris.nereids.types.StringType;
import org.apache.doris.nereids.types.TinyIntType;
import org.apache.doris.nereids.util.ExpressionUtils;
import org.apache.doris.nereids.util.TypeCoercionUtils;
@@ -397,6 +398,19 @@ public class ExpressionAnalyzer extends
SubExprAnalyzer<ExpressionRewriteContext
newChildrenBuilder.add(unboundFunction.child(i));
}
unboundFunction =
unboundFunction.withChildren(newChildrenBuilder.build());
+ } else if (StringUtils.isEmpty(unboundFunction.getDbName())
+ && "get_format".equalsIgnoreCase(unboundFunction.getName())
+ && unboundFunction.arity() == 2
+ && unboundFunction.child(0) instanceof UnboundSlot) {
+ SlotReference slotReference = new SlotReference(new ExprId(-1),
+ ((UnboundSlot) unboundFunction.child(0)).getName(),
+ StringType.INSTANCE, false, ImmutableList.of());
+ ImmutableList.Builder<Expression> newChildrenBuilder =
ImmutableList.builder();
+ newChildrenBuilder.add(slotReference);
+ for (int i = 1; i < unboundFunction.arity(); i++) {
+ newChildrenBuilder.add(unboundFunction.child(i));
+ }
+ unboundFunction =
unboundFunction.withChildren(newChildrenBuilder.build());
}
unboundFunction = (UnboundFunction) super.visit(unboundFunction,
context);
}
@@ -449,6 +463,14 @@ public class ExpressionAnalyzer extends
SubExprAnalyzer<ExpressionRewriteContext
return ret;
}
}
+ if
(GetFormatFunctionBinder.isGetFormatFunction(unboundFunction.getName())) {
+ Expression ret =
GetFormatFunctionBinder.INSTANCE.bind(unboundFunction);
+ if (ret instanceof BoundFunction) {
+ return
TypeCoercionUtils.processBoundFunction((BoundFunction) ret);
+ } else {
+ return ret;
+ }
+ }
if
(DatetimeFunctionBinder.isDatetimeFunction(unboundFunction.getName())) {
Expression ret =
DatetimeFunctionBinder.INSTANCE.bind(unboundFunction);
if (ret instanceof BoundFunction) {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/GetFormatFunctionBinder.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/GetFormatFunctionBinder.java
new file mode 100644
index 00000000000..b82e0ce28b5
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/GetFormatFunctionBinder.java
@@ -0,0 +1,78 @@
+// 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.rules.analysis;
+
+import org.apache.doris.nereids.analyzer.UnboundFunction;
+import org.apache.doris.nereids.exceptions.AnalysisException;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.SlotReference;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.GetFormat;
+import org.apache.doris.nereids.trees.expressions.literal.StringLiteral;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Binder for GET_FORMAT function.
+ */
+public class GetFormatFunctionBinder {
+
+ public static final GetFormatFunctionBinder INSTANCE = new
GetFormatFunctionBinder();
+
+ private static final ImmutableSet<String> SUPPORTED_FORMATS =
ImmutableSet.of("DATE", "DATETIME", "TIME");
+
+ public static boolean isGetFormatFunction(String functionName) {
+ return "GET_FORMAT".equalsIgnoreCase(functionName);
+ }
+
+ /**
+ * bind get_format function that have non-expression arguments.
+ *
+ * @param unboundFunction unbound get_format function
+ *
+ * @return bound function
+ */
+ public Expression bind(UnboundFunction unboundFunction) {
+ if (unboundFunction.arity() != 2) {
+ throw new AnalysisException("Can not find function 'GET_FORMAT'
with "
+ + unboundFunction.arity() + " arguments");
+ }
+ StringLiteral formatLiteral =
parseFormatType(unboundFunction.child(0));
+ Expression pattern = unboundFunction.child(1);
+ return new GetFormat(formatLiteral, pattern);
+ }
+
+ private StringLiteral parseFormatType(Expression formatTypeExpr) {
+ if (formatTypeExpr instanceof StringLiteral) {
+ String formatType = ((StringLiteral)
formatTypeExpr).getStringValue().toUpperCase();
+ validateFormatType(formatType);
+ return new StringLiteral(formatType);
+ }
+ if (formatTypeExpr instanceof SlotReference) {
+ String formatType = ((SlotReference)
formatTypeExpr).getName().toUpperCase();
+ validateFormatType(formatType);
+ return new StringLiteral(formatType);
+ }
+ throw new AnalysisException("Illegal first argument for GET_FORMAT: "
+ formatTypeExpr.toSql());
+ }
+
+ private void validateFormatType(String formatType) {
+ if (!SUPPORTED_FORMATS.contains(formatType)) {
+ throw new AnalysisException("Format type only support DATE,
DATETIME and TIME, but get: " + formatType);
+ }
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransform.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransform.java
index de65f1d914f..6b3e3d4478e 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransform.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransform.java
@@ -44,6 +44,8 @@ import
org.apache.doris.nereids.trees.expressions.literal.VarcharLiteral;
import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.DateV2Type;
import org.apache.doris.nereids.types.DecimalV3Type;
+import org.apache.doris.nereids.types.StringType;
+import org.apache.doris.nereids.types.TimeV2Type;
import org.apache.doris.nereids.util.DateUtils;
import org.apache.doris.qe.ConnectContext;
@@ -710,6 +712,34 @@ public class DateTimeExtractAndTransform {
: new NullLiteral(DateV2Type.INSTANCE);
}
+ /**
+ * time transformation function: maketime
+ */
+ @ExecFunction(name = "maketime")
+ public static Expression makeTime(BigIntLiteral hour, BigIntLiteral
minute, DoubleLiteral second) {
+ long hourValue = hour.getValue();
+ long minuteValue = minute.getValue();
+ double secondValue = second.getValue();
+
+ if (minuteValue < 0 || minuteValue >= 60 || secondValue < 0 ||
secondValue >= 60) {
+ return new NullLiteral(TimeV2Type.INSTANCE);
+ }
+ if (Math.abs(hourValue) > 838) {
+ hourValue = hourValue > 0 ? 838 : -838;
+ minuteValue = 59;
+ secondValue = 59;
+ } else if (Math.abs(hourValue) == 838 && secondValue > 59) {
+ secondValue = 59;
+ }
+
+ double totalSeconds = Math.abs(hourValue) * 3600 + minuteValue * 60
+ + Math.round(secondValue * 1000000.0) / 1000000.0;
+ if (hourValue < 0) {
+ totalSeconds = -totalSeconds;
+ }
+ return new TimeV2Literal(totalSeconds);
+ }
+
/**
* date transformation function: str_to_date
*/
@@ -1358,4 +1388,124 @@ public class DateTimeExtractAndTransform {
public static Expression secToTime(DoubleLiteral sec) {
return new TimeV2Literal(sec.getValue() * 1000000);
}
+
+ /**
+ * get_format function for constant folding
+ */
+ @ExecFunction(name = "get_format")
+ public static Expression getFormat(StringLikeLiteral type,
StringLikeLiteral format) {
+ String typeStr = type.getValue();
+ String formatStr = format.getValue().toUpperCase();
+
+ String result = null;
+
+ switch (typeStr) {
+ case "DATE":
+ switch (formatStr) {
+ case "USA":
+ result = "%m.%d.%Y";
+ break;
+ case "JIS":
+ case "ISO":
+ result = "%Y-%m-%d";
+ break;
+ case "EUR":
+ result = "%d.%m.%Y";
+ break;
+ case "INTERNAL":
+ result = "%Y%m%d";
+ break;
+ default:
+ break;
+ }
+ break;
+ case "DATETIME":
+ switch (formatStr) {
+ case "USA":
+ result = "%Y-%m-%d %H.%i.%s";
+ break;
+ case "JIS":
+ case "ISO":
+ result = "%Y-%m-%d %H:%i:%s";
+ break;
+ case "EUR":
+ result = "%Y-%m-%d %H.%i.%s";
+ break;
+ case "INTERNAL":
+ result = "%Y%m%d%H%i%s";
+ break;
+ default:
+ break;
+ }
+ break;
+ case "TIME":
+ switch (formatStr) {
+ case "USA":
+ result = "%h:%i:%s %p";
+ break;
+ case "JIS":
+ case "ISO":
+ result = "%H:%i:%s";
+ break;
+ case "EUR":
+ result = "%H.%i.%s";
+ break;
+ case "INTERNAL":
+ result = "%H%i%s";
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (result == null) {
+ return new NullLiteral(StringType.INSTANCE);
+ }
+
+ return new VarcharLiteral(result);
+ }
+
+ /**
+ * date transform function period_add
+ */
+ @ExecFunction(name = "period_add")
+ public static Expression periodAdd(BigIntLiteral period, BigIntLiteral
months) {
+ return new BigIntLiteral(convertMonthToPeriod(
+ checkAndConvertPeriodToMonth(period.getValue()) +
months.getValue()));
+ }
+
+ /**
+ * date transform function period_diff
+ */
+ @ExecFunction(name = "period_diff")
+ public static Expression periodDiff(BigIntLiteral period1, BigIntLiteral
period2) {
+ return new BigIntLiteral(checkAndConvertPeriodToMonth(
+ period1.getValue()) -
checkAndConvertPeriodToMonth(period2.getValue()));
+ }
+
+ private static void validatePeriod(long period) {
+ if (period <= 0 || (period % 100) == 0 || (period % 100) > 12) {
+ throw new AnalysisException("Period function got invalid period: "
+ period);
+ }
+ }
+
+ private static long checkAndConvertPeriodToMonth(long period) {
+ validatePeriod(period);
+ long year = period / 100;
+ if (year < 100) {
+ year += (year >= 70) ? 1900 : 2000;
+ }
+ return year * 12L + (period % 100) - 1;
+ }
+
+ private static long convertMonthToPeriod(long month) {
+ long year = month / 12;
+ if (year < 100) {
+ year += (year >= 70) ? 1900 : 2000;
+ }
+ return year * 100 + month % 12 + 1;
+ }
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/GetFormat.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/GetFormat.java
new file mode 100644
index 00000000000..e5eda62e00d
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/GetFormat.java
@@ -0,0 +1,75 @@
+// 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.AlwaysNullable;
+import
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
+import org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
+import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
+import org.apache.doris.nereids.types.StringType;
+import org.apache.doris.nereids.types.VarcharType;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/**
+ * ScalarFunction 'get_format'.
+ */
+public class GetFormat extends ScalarFunction
+ implements AlwaysNullable, BinaryExpression,
ExplicitlyCastableSignature {
+ public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+ FunctionSignature.ret(VarcharType.SYSTEM_DEFAULT)
+ .args(VarcharType.SYSTEM_DEFAULT, VarcharType.SYSTEM_DEFAULT),
+ FunctionSignature.ret(StringType.INSTANCE)
+ .args(StringType.INSTANCE, StringType.INSTANCE)
+ );
+
+ /**
+ * constructor with 2 arguments.
+ */
+ public GetFormat(Expression arg0, Expression arg1) {
+ super("get_format", arg0, arg1);
+ }
+
+ public GetFormat(ScalarFunctionParams functionParams) {
+ super(functionParams);
+ }
+
+ /**
+ * withChildren.
+ */
+ @Override
+ public GetFormat withChildren(List<Expression> children) {
+ Preconditions.checkArgument(children.size() == 2);
+ return new GetFormat(getFunctionParams(children));
+ }
+
+ @Override
+ public List<FunctionSignature> getSignatures() {
+ return SIGNATURES;
+ }
+
+ @Override
+ public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+ return visitor.visitGetFormat(this, context);
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MakeTime.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MakeTime.java
new file mode 100644
index 00000000000..2c4e8d8038e
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MakeTime.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.AlwaysNullable;
+import
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
+import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
+import org.apache.doris.nereids.types.BigIntType;
+import org.apache.doris.nereids.types.DoubleType;
+import org.apache.doris.nereids.types.TimeV2Type;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/**
+ * ScalarFunction 'maketime'.
+ */
+public class MakeTime extends ScalarFunction implements
ExplicitlyCastableSignature, AlwaysNullable {
+ public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+ FunctionSignature.ret(TimeV2Type.INSTANCE)
+ .args(BigIntType.INSTANCE, BigIntType.INSTANCE,
BigIntType.INSTANCE),
+ FunctionSignature.ret(TimeV2Type.MAX)
+ .args(BigIntType.INSTANCE, BigIntType.INSTANCE,
DoubleType.INSTANCE)
+
+ );
+
+ /**
+ * constructor with 2 arguments.
+ */
+ public MakeTime(Expression arg0, Expression arg1, Expression arg2) {
+ super("maketime", arg0, arg1, arg2);
+ }
+
+ /** constructor for withChildren and reuse signature */
+ private MakeTime(ScalarFunctionParams functionParams) {
+ super(functionParams);
+ }
+
+ /**
+ * withChildren.
+ */
+ @Override
+ public MakeTime withChildren(List<Expression> children) {
+ Preconditions.checkArgument(children.size() == 3);
+ return new MakeTime(getFunctionParams(children));
+ }
+
+ @Override
+ public List<FunctionSignature> getSignatures() {
+ return SIGNATURES;
+ }
+
+ @Override
+ public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+ return visitor.visitMakeTime(this, context);
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/PeriodAdd.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/PeriodAdd.java
new file mode 100644
index 00000000000..2f3a8475400
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/PeriodAdd.java
@@ -0,0 +1,69 @@
+// 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.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.BigIntType;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/**
+ * ScalarFunction 'period_add'.
+ */
+public class PeriodAdd extends ScalarFunction
+ implements BinaryExpression, ExplicitlyCastableSignature,
PropagateNullable {
+ public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+
FunctionSignature.ret(BigIntType.INSTANCE).args(BigIntType.INSTANCE,
BigIntType.INSTANCE)
+ );
+
+ /**
+ * constructor with 2 argument.
+ */
+ public PeriodAdd(Expression arg0, Expression arg1) {
+ super("period_add", arg0, arg1);
+ }
+
+ /** constructor for withChildren and reuse signature */
+ private PeriodAdd(ScalarFunctionParams functionParams) {
+ super(functionParams);
+ }
+
+ @Override
+ public List<FunctionSignature> getSignatures() {
+ return SIGNATURES;
+ }
+
+ @Override
+ public Expression withChildren(List<Expression> children) {
+ Preconditions.checkArgument(children.size() == 2);
+ return new PeriodAdd(getFunctionParams(children));
+ }
+
+ @Override
+ public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+ return visitor.visitPeriodAdd(this, context);
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/PeriodDiff.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/PeriodDiff.java
new file mode 100644
index 00000000000..69e1b46409f
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/PeriodDiff.java
@@ -0,0 +1,69 @@
+// 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.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.BigIntType;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/**
+ * ScalarFunction 'period_diff'.
+ */
+public class PeriodDiff extends ScalarFunction
+ implements BinaryExpression, ExplicitlyCastableSignature,
PropagateNullable {
+ public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+
FunctionSignature.ret(BigIntType.INSTANCE).args(BigIntType.INSTANCE,
BigIntType.INSTANCE)
+ );
+
+ /**
+ * constructor with 2 argument.
+ */
+ public PeriodDiff(Expression arg0, Expression arg1) {
+ super("period_diff", arg0, arg1);
+ }
+
+ /** constructor for withChildren and reuse signature */
+ private PeriodDiff(ScalarFunctionParams functionParams) {
+ super(functionParams);
+ }
+
+ @Override
+ public List<FunctionSignature> getSignatures() {
+ return SIGNATURES;
+ }
+
+ @Override
+ public Expression withChildren(List<Expression> children) {
+ Preconditions.checkArgument(children.size() == 2);
+ return new PeriodDiff(getFunctionParams(children));
+ }
+
+ @Override
+ public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+ return visitor.visitPeriodDiff(this, context);
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
index b62b490404a..5e4ce74823f 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
@@ -228,6 +228,7 @@ import
org.apache.doris.nereids.trees.expressions.functions.scalar.FromIso8601Da
import
org.apache.doris.nereids.trees.expressions.functions.scalar.FromUnixtime;
import org.apache.doris.nereids.trees.expressions.functions.scalar.G;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Gcd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.GetFormat;
import
org.apache.doris.nereids.trees.expressions.functions.scalar.GetVariantType;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Greatest;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Hex;
@@ -317,6 +318,7 @@ import
org.apache.doris.nereids.trees.expressions.functions.scalar.Ltrim;
import org.apache.doris.nereids.trees.expressions.functions.scalar.LtrimIn;
import org.apache.doris.nereids.trees.expressions.functions.scalar.MakeDate;
import org.apache.doris.nereids.trees.expressions.functions.scalar.MakeSet;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MakeTime;
import
org.apache.doris.nereids.trees.expressions.functions.scalar.MapContainsEntry;
import
org.apache.doris.nereids.trees.expressions.functions.scalar.MapContainsKey;
import
org.apache.doris.nereids.trees.expressions.functions.scalar.MapContainsValue;
@@ -372,6 +374,8 @@ import
org.apache.doris.nereids.trees.expressions.functions.scalar.Overlay;
import
org.apache.doris.nereids.trees.expressions.functions.scalar.ParseDataSize;
import org.apache.doris.nereids.trees.expressions.functions.scalar.ParseUrl;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Password;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.PeriodAdd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.PeriodDiff;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Pi;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Pmod;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Positive;
@@ -2637,7 +2641,23 @@ public interface ScalarFunctionVisitor<R, C> {
return visitScalarFunction(makeSet, context);
}
+ default R visitMakeTime(MakeTime makeTime, C context) {
+ return visitScalarFunction(makeTime, context);
+ }
+
default R visitExportSet(ExportSet exportSet, C context) {
return visitScalarFunction(exportSet, context);
}
+
+ default R visitGetFormat(GetFormat getFormat, C context) {
+ return visitScalarFunction(getFormat, context);
+ }
+
+ default R visitPeriodAdd(PeriodAdd periodAdd, C context) {
+ return visitScalarFunction(periodAdd, context);
+ }
+
+ default R visitPeriodDiff(PeriodDiff periodDiff, C context) {
+ return visitScalarFunction(periodDiff, context);
+ }
}
diff --git
a/regression-test/data/doc/sql-manual/sql-functions/doc_date_functions_test.out
b/regression-test/data/doc/sql-manual/sql-functions/doc_date_functions_test.out
index bc33c290641..b39bec687e2 100644
---
a/regression-test/data/doc/sql-manual/sql-functions/doc_date_functions_test.out
+++
b/regression-test/data/doc/sql-manual/sql-functions/doc_date_functions_test.out
@@ -1970,3 +1970,29 @@ da fanadur
-- !yearweek_5 --
202352
+-- !maketime_test_1 --
+12:15:30.000000
+111:00:23.123457
+838:59:59.000000
+-838:59:59.000000
+\N
+\N
+\N
+\N
+\N
+\N
+\N
+
+-- !maketime_test_2 --
+12:15:25
+111:00:25
+838:59:59
+-838:59:59
+\N
+14:51:25
+\N
+\N
+01:02:25
+\N
+07:23:25
+
diff --git
a/regression-test/data/nereids_p0/sql_functions/datetime_functions/test_date_function.out
b/regression-test/data/nereids_p0/sql_functions/datetime_functions/test_date_function.out
index 41bcc6c26ca..c18f2b7ec4c 100644
---
a/regression-test/data/nereids_p0/sql_functions/datetime_functions/test_date_function.out
+++
b/regression-test/data/nereids_p0/sql_functions/datetime_functions/test_date_function.out
@@ -798,3 +798,62 @@ true
-- !sql_time_value --
456:26:32 456 26 32
+-- !period_add_1 --
+200805 -1
+200902 61
+200805 -1
+207001 1197
+197002 -1195
+13374411 -14813252269
+\N \N
+\N -1
+-9223372036854775808 1106804644422549102
+1029009107 \N
+
+-- !period_add_2 --
+202601 211
+202604 267
+202601 211
+202602 670
+202512 -525
+1231311 -14814709441
+202609 \N
+\N 0
+202512 310
+1029009108 \N
+
+-- !period_add_3 --
+200901 -213
+200907 -207
+200901 -213
+207008 526
+197011 -671
+12345709 1457171
+\N \N
+202608 -2
+-9223372036854775711 1106804644422548791
+202608 -2
+
+-- !period_add_4 --
+\N \N
+\N \N
+\N \N
+\N \N
+\N \N
+\N \N
+\N \N
+\N \N
+\N \N
+\N \N
+
+-- !period_add_5 --
+\N \N
+\N \N
+\N \N
+\N \N
+\N \N
+\N \N
+\N \N
+\N \N
+\N \N
+\N \N
diff --git
a/regression-test/data/nereids_p0/sql_functions/datetime_functions/test_date_function_v2.out
b/regression-test/data/nereids_p0/sql_functions/datetime_functions/test_date_function_v2.out
index 347216879a5..11b715513a3 100644
---
a/regression-test/data/nereids_p0/sql_functions/datetime_functions/test_date_function_v2.out
+++
b/regression-test/data/nereids_p0/sql_functions/datetime_functions/test_date_function_v2.out
@@ -41,3 +41,84 @@
-- !sql_diff14 --
86400000000
+-- !get_format_date_1 --
+%m.%d.%Y
+%Y-%m-%d
+%Y-%m-%d
+%d.%m.%Y
+%Y%m%d
+\N
+
+-- !get_format_date_2 --
+%m.%d.%Y
+%Y-%m-%d
+%Y-%m-%d
+%d.%m.%Y
+%Y%m%d
+\N
+
+-- !get_format_date_3 --
+%m.%d.%Y
+%Y-%m-%d
+%Y-%m-%d
+%d.%m.%Y
+%Y%m%d
+\N
+
+-- !get_format_date_4 --
+\N
+
+-- !get_format_datetime_1 --
+%Y-%m-%d %H.%i.%s
+%Y-%m-%d %H:%i:%s
+%Y-%m-%d %H:%i:%s
+%Y-%m-%d %H.%i.%s
+%Y%m%d%H%i%s
+\N
+
+-- !get_format_datetime_2 --
+%Y-%m-%d %H.%i.%s
+%Y-%m-%d %H:%i:%s
+%Y-%m-%d %H:%i:%s
+%Y-%m-%d %H.%i.%s
+%Y%m%d%H%i%s
+\N
+
+-- !get_format_datetime_3 --
+%Y-%m-%d %H.%i.%s
+%Y-%m-%d %H:%i:%s
+%Y-%m-%d %H:%i:%s
+%Y-%m-%d %H.%i.%s
+%Y%m%d%H%i%s
+\N
+
+-- !get_format_datetime_4 --
+\N
+
+-- !get_format_time_1 --
+%h:%i:%s %p
+%H:%i:%s
+%H:%i:%s
+%H.%i.%s
+%H%i%s
+\N
+
+-- !get_format_time_2 --
+%h:%i:%s %p
+%H:%i:%s
+%H:%i:%s
+%H.%i.%s
+%H%i%s
+\N
+
+-- !get_format_time_3 --
+%h:%i:%s %p
+%H:%i:%s
+%H:%i:%s
+%H.%i.%s
+%H%i%s
+\N
+
+-- !get_format_time_4 --
+\N
+
diff --git
a/regression-test/data/query_p0/sql_functions/string_functions/test_string_function.out
b/regression-test/data/query_p0/sql_functions/string_functions/test_string_function.out
index 2f75d240a02..64cef848f05 100644
---
a/regression-test/data/query_p0/sql_functions/string_functions/test_string_function.out
+++
b/regression-test/data/query_p0/sql_functions/string_functions/test_string_function.out
@@ -817,6 +817,134 @@ x2,x4,x26,x51,x62,x63,x64
-- !mask_set_4 --
,y6
+-- !mask_set_5 --
+1 const1
+2 blue
+3 const1,cat
+4 const3
+5 const1,const3
+6 tuesday,const3
+7 const1,two,const3
+8
+9 test2,const3
+10 const1,const3
+11 \N
+12 const1,const3
+13 const1,should after ,
+14 const1,const3
+
+-- !mask_set_6 --
+1 apple,middle
+2 red,middle
+3 dog,middle
+4 small,middle
+5 hot,middle
+6 monday,middle
+7 one,middle
+8 hello,middle
+9 test1,middle
+10 汽车,middle
+11 a,middle
+12 middle
+13 ,middle
+14 first,middle
+
+-- !mask_set_7 --
+1 Doris
+2 Apache
+3 Doris,Apache
+4 large
+5 Doris
+6 Apache,wednesday
+7 Doris,Apache,three
+8
+9 Apache,test3
+10 Doris,火车
+11 \N
+12 Doris,Apache
+13 Doris,Apache
+14 Doris,third
+
+-- !mask_set_8 --
+1 apple
+2
+3 dog
+4 constant
+5 hot,constant
+6 constant
+7 one,constant
+8
+9 test1
+10
+11 a
+12 constant
+13 ,constant
+14 constant
+
+-- !mask_set_9 --
+1 apple,orange,third
+2 red,blue,third
+3 dog,cat,third
+4 small,medium,third
+5 hot,warm,third
+6 monday,tuesday,third
+7 one,two,third
+8 hello,world,third
+9 test1,test2,third
+10 汽车,自行车,third
+11 a,b,third
+12 third
+13 ,should after ,,third
+14 first,second,third
+
+-- !mask_set_10 --
+1 第一
+2 第二
+3 第一,第二
+4 large
+5 第一
+6 第二,wednesday
+7 第一,第二,three
+8
+9 第二,test3
+10 第一,火车
+11 \N
+12 第一,第二
+13 第一,第二
+14 第一,third
+
+-- !mask_set_11 --
+1 alpha,gamma
+2 alpha,gamma
+3 alpha,gamma
+4 alpha,gamma
+5 alpha,gamma
+6 alpha,gamma
+7 alpha,gamma
+8 alpha,gamma
+9 alpha,gamma
+10 alpha,gamma
+11 alpha,gamma
+12 alpha,gamma
+13 alpha,gamma
+14 alpha,gamma
+
+-- !mask_set_12 --
+1 apple
+2 fixed
+3 dog,fixed
+4
+5 hot
+6 fixed
+7 one,fixed
+8
+9 fixed
+10 汽车
+11 \N
+12 fixed
+13 ,fixed
+14 first
+
-- !export_set_1 --
1
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
2 0111111111111111111111111111111111111111111111111111111111111111
@@ -1033,3 +1161,131 @@ x2,x4,x26,x51,x62,x63,x64
12
1世界!?你好0世界!?你好1世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0
13
1世界!?你好0世界!?你好1世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0世界!?你好0
+-- !insert_1 --
+1 QuWhattic
+2 Quadratic
+3 QuWhat
+4 Quadratic
+5 Quadratic
+6 QuWhatadratic
+7 QuWhat
+8 Hello Doris
+9 Hi World
+10 Hello World
+11
+12 test
+13
+14 你好Apache
+15 He你好o
+16 你Doris世界
+17 xyz
+18 abcxyzdefg
+19 abcdefg
+20 tt
+21 新字符串
+22 测试内容
+23 Special***
+24 b
+25 a
+26 \N
+27 \N
+28 \N
+29 \N
+30 🎉🎁🎈
+
+-- !insert_2 --
+1 QuWhattic
+2 Quadratic
+3 QuWhattic
+4 Quadratic
+5 Quadratic
+6 QuWhattic
+7 QuWhattic
+8 QuadraWhat
+9 Whatratic
+10 Quadratic
+11 Whatratic
+12 Whatratic
+13 Whatratic
+14 QuWhattic
+15 QuWhattic
+16 QWhatatic
+17 Whatratic
+18 QuaWhatic
+19 QuadratWhat
+20 QWhatatic
+21 Whatratic
+22 QuWhattic
+23 QuadratWhat
+24 Whatratic
+25 QWhatatic
+26 Whatratic
+27 \N
+28 Whatratic
+29 Whatratic
+30 QWhatatic
+
+-- !insert_3 --
+1 QuWhattic
+2 QuWhattic
+3 QuWhat
+4 QuWhattic
+5 QuWhattic
+6 QuWhatadratic
+7 QuWhat
+8 HeWhatorld
+9 HeWhatorld
+10 HeWhatlo World
+11
+12 teWhatst
+13 teWhat
+14 你好What
+15 HeWhato
+16 你好What界
+17 abWhat
+18 abWhatcdefg
+19 abWhatdefg
+20 teWhat
+21 测试What串
+22 测试What
+23 SpWhatal!@#
+24 a
+25 a
+26 \N
+27 teWhatt
+28 \N
+29 teWhatt
+30 🎉🎊What
+
+-- !insert_4 --
+1 QuWhatratic
+2 Quadratic
+3 QuWhatratic
+4 Quadratic
+5 Quadratic
+6 QuWhatratic
+7 QuWhatratic
+8 Hello Dorisrld
+9 Hillo World
+10 Hello World
+11
+12 st
+13 st
+14 你好Apache
+15 He你好o
+16 你Doris界
+17 xyzcdefg
+18 abcxyzfg
+19 abcdefg
+20 tt
+21 新字符串
+22 测试内容串
+23 Special***#
+24 b
+25 a
+26 \N
+27 \N
+28 newst
+29 \N
+30 🎉🎁
+
diff --git
a/regression-test/suites/doc/sql-manual/sql-functions/doc_date_functions_test.groovy
b/regression-test/suites/doc/sql-manual/sql-functions/doc_date_functions_test.groovy
index ac0656a15db..05a8576b178 100644
---
a/regression-test/suites/doc/sql-manual/sql-functions/doc_date_functions_test.groovy
+++
b/regression-test/suites/doc/sql-manual/sql-functions/doc_date_functions_test.groovy
@@ -35,22 +35,22 @@
suite("doc_date_functions_test") {
//FIXME: make FE and BE have same range of timezone
// sql "set debug_skip_fold_constant=true;"
- // Test Group 1: Basic Date Functions (序号 1-12)
+ // Test Group 1: Basic Date Functions(1 - 12)
// 1. CONVERT_TZ function tests
- // 中国上海时间转换到美国洛杉矶
+ // Convert China Shanghai time to America Los Angeles
qt_convert_tz_1 """select CONVERT_TZ(CAST('2019-08-01 13:21:03' AS
DATETIME), 'Asia/Shanghai', 'America/Los_Angeles')"""
- // 将东八区(+08:00)的时间转换为美国洛杉矶
+ // Convert East 8 zone (+08:00) time to America Los Angeles
qt_convert_tz_2 """select CONVERT_TZ(CAST('2019-08-01 13:21:03' AS
DATETIME), '+08:00', 'America/Los_Angeles')"""
- // 输入为date类型,时间部分自动转换为 00:00:00
+ // Input is date type, time part is automatically converted to 00:00:00
qt_convert_tz_3 """select CONVERT_TZ(CAST('2019-08-01 13:21:03' AS DATE),
'Asia/Shanghai', 'America/Los_Angeles')"""
- // 转换时间为NULL,输出NULL
+ // Convert time is NULL, output NULL
qt_convert_tz_4 """select CONVERT_TZ(NULL, 'Asia/Shanghai',
'America/New_York')"""
- // 任一时区为NULL,返回NULL
+ // Any timezone is NULL, return NULL
qt_convert_tz_5 """select CONVERT_TZ('2019-08-01 13:21:03', NULL,
'America/Los_Angeles')"""
qt_convert_tz_6 """select CONVERT_TZ('2019-08-01 13:21:03', '+08:00',
NULL)"""
@@ -59,7 +59,7 @@ suite("doc_date_functions_test") {
exception "Operation convert_tz invalid timezone"
}
- // 带有 scale 的时间
+ // Time with scale
qt_convert_tz_8 """select CONVERT_TZ('2019-08-01 13:21:03.636', '+08:00',
'America/Los_Angeles')"""
// test {
@@ -68,88 +68,88 @@ suite("doc_date_functions_test") {
// }
// 5. DATE_ADD function tests
- // 添加天数
+ // Add days
qt_date_add_1 """select date_add(cast('2010-11-30 23:59:59' as datetime),
INTERVAL 2 DAY)"""
- // 添加季度
+ // Add quarter
qt_date_add_2 """select DATE_ADD(cast('2023-01-01' as date), INTERVAL 1
QUARTER)"""
- // 添加周数
+ // Add weeks
qt_date_add_3 """select DATE_ADD('2023-01-01', INTERVAL 1 WEEK)"""
- // 添加月数,因为2023年2月只有28天,所以1月31加一个月返回2月28
+ // Add month, because February 2023 only has 28 days, so January 31 plus
one month returns February 28
qt_date_add_4 """select DATE_ADD('2023-01-31', INTERVAL 1 MONTH)"""
- // 负数测试
+ // Negative number test
qt_date_add_5 """select DATE_ADD('2019-01-01', INTERVAL -3 DAY)"""
- // 跨年的小时增加
+ // Cross-year hour increment
qt_date_add_6 """select DATE_ADD('2023-12-31 23:00:00', INTERVAL 2 HOUR)"""
- // 参数为NULL,返回NULL
+ // Parameter is NULL, return NULL
qt_date_add_7 """select DATE_ADD(NULL, INTERVAL 1 MONTH)"""
// 6. DATE_CEIL function tests
- // 秒数按五秒向上取整
+ // Round up seconds to five-second intervals
qt_date_ceil_1 """select date_ceil(cast('2023-07-13 22:28:18' as
datetime),interval 5 second)"""
- // 带有 scale 的日期时间参数
+ // Datetime parameter with scale
qt_date_ceil_2 """select date_ceil(cast('2023-07-13 22:28:18.123' as
datetime(3)),interval 5 second)"""
- // 按五分钟向上取整
+ // Round up to five-minute intervals
qt_date_ceil_3 """select date_ceil('2023-07-13 22:28:18',interval 5
minute)"""
- // 按五周向上取整
+ // Round up to five-week intervals
qt_date_ceil_4 """select date_ceil('2023-07-13 22:28:18',interval 5
WEEK)"""
- // 按五小时向上取整
+ // Round up to five-hour intervals
qt_date_ceil_5 """select date_ceil('2023-07-13 22:28:18',interval 5
hour)"""
- // 按五天向上取整
+ // Round up to five-day intervals
qt_date_ceil_6 """select date_ceil('2023-07-13 22:28:18',interval 5 day)"""
- // 按五个月向上取整
+ // Round up to five-month intervals
qt_date_ceil_7 """select date_ceil('2023-07-13 22:28:18',interval 5
month)"""
- // 按五年向上取整
+ // Round up to five-year intervals
qt_date_ceil_8 """select date_ceil('2023-07-13 22:28:18',interval 5
year)"""
- // 任一参数为 NULL
+ // Any parameter is NULL
qt_date_ceil_9 """select date_ceil('9900-07-13',interval NULL year)"""
qt_date_ceil_10 """select date_ceil(NULL,interval 5 year)"""
// 7. DATEDIFF function tests
- // 两个日期相差1天(忽略时间部分)
+ // Two dates differ by 1 day (ignore time part)
qt_datediff_1 """select datediff(CAST('2007-12-31 23:59:59' AS DATETIME),
CAST('2007-12-30' AS DATETIME))"""
- // 前一个日期早于后一个日期,返回负数
+ // First date is earlier than second date, return negative number
qt_datediff_2 """select datediff(CAST('2010-11-30 23:59:59' AS DATETIME),
CAST('2010-12-31' AS DATETIME))"""
- // 任一参数为 NULL
+ // Any parameter is NULL
qt_datediff_3 """select datediff('2023-01-01', NULL)"""
- // 若输入 datetime 类型,会忽略时间部分
+ // If input is datetime type, time part will be ignored
qt_datediff_4 """select datediff('2023-01-02 13:00:00', '2023-01-01
12:00:00')"""
qt_datediff_5 """select datediff('2023-01-02 12:00:00', '2023-01-01
13:00:00')"""
// 8. DATE_FLOOR function tests
- // 按 5 秒向下取整
+ // Round down to 5-second intervals
qt_date_floor_1 """select date_floor(cast('0001-01-01 00:00:18' as
datetime), INTERVAL 5 SECOND)"""
- // 带有 scale 的日期时间,返回值也会带有 scale
+ // Datetime with scale, return value also has scale
qt_date_floor_2 """select date_floor(cast('0001-01-01 00:00:18.123' as
datetime), INTERVAL 5 SECOND)"""
- // 输入时间恰好是 5 天周期的起点
+ // Input time is exactly at the start of a 5-day cycle
qt_date_floor_3 """select date_floor('2023-07-10 00:00:00', INTERVAL 5
DAY)"""
- // date 类型的向下取整
+ // Round down date type
qt_date_floor_4 """select date_floor('2023-07-13', INTERVAL 5 YEAR)"""
- // 任一参数为 NULL
+ // Any parameter is NULL
qt_date_floor_5 """select date_floor(NULL, INTERVAL 5 HOUR)"""
// 9. DATE_FORMAT function tests
- // 基本格式化测试
+ // Basic formatting tests
qt_date_format_1 """SELECT DATE_FORMAT('2009-10-04 22:23:00', '%W %M
%Y')"""
qt_date_format_2 """SELECT DATE_FORMAT('2007-10-04 22:23:00',
'%H:%i:%s')"""
qt_date_format_3 """SELECT DATE_FORMAT('1999-01-01', '%Y-%m-%d')"""
@@ -187,52 +187,52 @@ suite("doc_date_functions_test") {
exception "Operation date_format of 142335765945253888,
%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p
is invalid"
}
- // 特殊格式符测试
+ // Special format specifier tests
qt_date_format_5 """SELECT DATE_FORMAT('2009-10-04', '%a %b %c')"""
qt_date_format_6 """SELECT DATE_FORMAT('2009-10-04', '%D %e %f')"""
- // 任一参数为 NULL
+ // Any parameter is NULL
qt_date_format_7 """SELECT DATE_FORMAT(NULL, '%Y-%m-%d')"""
qt_date_format_8 """SELECT DATE_FORMAT('2009-10-04', NULL)"""
// 10. DATE function tests
- // 从datetime中提取日期部分
+ // Extract date part from datetime
qt_date_1 """SELECT DATE('2003-12-31 01:02:03')"""
qt_date_2 """SELECT DATE('2003-12-31')"""
- // 参数为 NULL
+ // Parameter is NULL
qt_date_3 """SELECT DATE(NULL)"""
// 11. DATE_SUB function tests
- // 减去天数
+ // Subtract days
qt_date_sub_1 """SELECT DATE_SUB('2018-05-01', INTERVAL 1 DAY)"""
- // 减去月数
+ // Subtract months
qt_date_sub_2 """SELECT DATE_SUB('2018-05-01', INTERVAL 1 MONTH)"""
- // 减去年数
+ // Subtract years
qt_date_sub_3 """SELECT DATE_SUB('2018-05-01', INTERVAL 1 YEAR)"""
- // 减去小时
+ // Subtract hours
qt_date_sub_4 """SELECT DATE_SUB('2018-05-01 12:00:00', INTERVAL 2 HOUR)"""
- // 参数为 NULL
+ // Parameter is NULL
qt_date_sub_5 """SELECT DATE_SUB(NULL, INTERVAL 1 DAY)"""
// 12. DATE_TRUNC function tests
- // 截断到年
+ // Truncate to year
qt_date_trunc_1 """SELECT DATE_TRUNC('2019-05-09', 'year')"""
- // 截断到月
+ // Truncate to month
qt_date_trunc_2 """SELECT DATE_TRUNC('2019-05-09', 'month')"""
- // 截断到日
+ // Truncate to day
qt_date_trunc_3 """SELECT DATE_TRUNC('2019-05-09 12:30:45', 'day')"""
- // 截断到小时
+ // Truncate to hour
qt_date_trunc_4 """SELECT DATE_TRUNC('2019-05-09 12:30:45', 'hour')"""
- // 参数为 NULL
+ // Parameter is NULL
qt_date_trunc_5 """SELECT DATE_TRUNC(NULL, 'year')"""
// Group 2: Day functions and related date extraction functions
@@ -1368,6 +1368,30 @@ suite("doc_date_functions_test") {
qt_yearweek_4 """SELECT YEARWEEK('2023-01-02', 5) AS yearweek_mode5"""
qt_yearweek_5 """SELECT YEARWEEK('2023-12-25', 1) AS date_type_mode1"""
+ // 100. MAKETIME function test;
+ sql """DROP TABLE IF EXISTS maketime_test"""
+ sql """CREATE TABLE maketime_test (
+ `id` INT,
+ `hour` INT,
+ `minute` INT,
+ `sec` FLOAT
+ ) DUPLICATE KEY(id)
+ PROPERTIES ( 'replication_num' = '1' );"""
+ sql """ INSERT INTO maketime_test VALUES
+ (1, 12, 15, 30),
+ (2, 111, 0, 23.1234567),
+ (3, 1234, 11, 4),
+ (4, -1234, 6, 52),
+ (5, 20, 60, 12),
+ (6, 14, 51, 66),
+ (7, NULL, 15, 16),
+ (8, 7, NULL, 8),
+ (9, 1, 2, NULL),
+ (10, 123, -4, 52),
+ (11, 7, 23, -6);"""
+ qt_maketime_test_1 """SELECT MAKETIME(hour,minute,sec) FROM maketime_test
ORDER BY id;"""
+ qt_maketime_test_2 """SELECT MAKETIME(hour, minute, 25) FROM maketime_test
ORDER BY id;"""
+
// Test constant folding for YEARWEEK function
testFoldConst("SELECT YEARWEEK('2021-01-01') AS yearweek_mode0")
testFoldConst("SELECT YEARWEEK('2020-07-01', 1) AS yearweek_mode1")
@@ -1985,6 +2009,19 @@ suite("doc_date_functions_test") {
testFoldConst("SELECT YEARS_SUB('2022-12-25', 3) AS sub_3_year_date")
testFoldConst("SELECT YEARS_SUB('2020-02-29', 1) AS leap_day_adjust_1")
+ // 99. MAKETIME function constant folding tests
+ testFoldConst("SELECT MAKETIME(12, 15, 30)")
+ testFoldConst("SELECT MAKETIME(111, 0, 23.1234567)")
+ testFoldConst("SELECT MAKETIME(1234, 11, 4)")
+ testFoldConst("SELECT MAKETIME(-1234, 6, 52)")
+ testFoldConst("SELECT MAKETIME(20, 60, 12)")
+ testFoldConst("SELECT MAKETIME(14, 51, 66)")
+ testFoldConst("SELECT MAKETIME(NULL, 15, 16)")
+ testFoldConst("SELECT MAKETIME(7, NULL, 8)")
+ testFoldConst("SELECT MAKETIME(1, 2, NULL)")
+ testFoldConst("SELECT MAKETIME(123, -4, 40)")
+ testFoldConst("SELECT MAKETIME(7, 8, -23)")
+
// Additional NULL parameter tests for comprehensive coverage
// MINUTE functions NULL tests
diff --git
a/regression-test/suites/nereids_function_p0/scalar_function/L.groovy
b/regression-test/suites/nereids_function_p0/scalar_function/L.groovy
index 5f6e44341bd..daf28b3a8a9 100644
--- a/regression-test/suites/nereids_function_p0/scalar_function/L.groovy
+++ b/regression-test/suites/nereids_function_p0/scalar_function/L.groovy
@@ -73,6 +73,18 @@ suite("nereids_scalar_fn_L") {
qt_sql_length_Varchar_notnull "select length(kvchrs1) from
fn_test_not_nullable order by kvchrs1"
qt_sql_length_String "select length(kstr) from fn_test order by kstr"
qt_sql_length_String_notnull "select length(kstr) from
fn_test_not_nullable order by kstr"
+ def length_str = sql """select length(kvchrs1) from fn_test order by
kvchrs1"""
+ def octet_length_str = sql """select octet_length(kvchrs1) from fn_test
order by kvchrs1"""
+ assertEquals(length_str, octet_length_str)
+ length_str = sql """select length(kvchrs1) from fn_test_not_nullable
order by kvchrs1"""
+ octet_length_str = sql """select length(kvchrs1) from
fn_test_not_nullable order by kvchrs1"""
+ assertEquals(length_str, octet_length_str)
+ length_str = sql """select length(kstr) from fn_test order by kstr"""
+ octet_length_str = sql """select octet_length(kstr) from fn_test order
by kstr"""
+ assertEquals(length_str, octet_length_str)
+ length_str = sql """select length(kstr) from fn_test_not_nullable order
by kstr"""
+ octet_length_str = sql """select octet_length(kstr) from
fn_test_not_nullable order by kstr"""
+ assertEquals(length_str, octet_length_str)
qt_sql_like_Varchar_Varchar "select like(kvchrs1, kvchrs2) from fn_test
order by kvchrs1"
qt_sql_like_Varchar_Varchar_not_null "select like(kvchrs1, kvchrs2)
from fn_test_not_nullable order by kvchrs1"
qt_sql_ln_Double "select ln(kdbl) from fn_test order by kdbl"
diff --git
a/regression-test/suites/nereids_p0/sql_functions/datetime_functions/test_date_function.groovy
b/regression-test/suites/nereids_p0/sql_functions/datetime_functions/test_date_function.groovy
index d58fb3a58ee..a9a7ec6b114 100644
---
a/regression-test/suites/nereids_p0/sql_functions/datetime_functions/test_date_function.groovy
+++
b/regression-test/suites/nereids_p0/sql_functions/datetime_functions/test_date_function.groovy
@@ -838,4 +838,38 @@ suite("test_date_function") {
result([[true]])
}
}()
+
+ sql """ DROP TABLE IF EXISTS test_period_union; """
+ sql """ CREATE TABLE test_period_union (
+ id INT,
+ period_1 BIGINT,
+ month BIGINT,
+ period_2 BIGINT
+ ) DUPLICATE KEY(id)
+ DISTRIBUTED BY HASH(id) BUCKETS 1
+ PROPERTIES ( 'replication_num' = '1' ); """
+ sql """ INSERT INTO test_period_union VALUES
+ (1, 200803, 2, 200804),
+ (2, 200809, 5, 0308),
+ (3, 0803, 2, 0804),
+ (4, 6910, 3, 7001),
+ (5, 7001, 1, 6908),
+ (6, 12345611, 123456, 123456114512),
+ (7, NULL, 10, NULL),
+ (8, 202510, NULL, 202511),
+ (9, 9223372036854775807, 1, 1),
+ (10, 2510, 123456789, NULL); """
+ qt_period_add_1 """ SELECT PERIOD_ADD(period_1, month),
PERIOD_DIFF(period_1, period_2) FROM test_period_union ORDER BY id; """
+ qt_period_add_2 """ SELECT PERIOD_ADD(2511, month), PERIOD_DIFF(2511,
period_2) FROM test_period_union ORDER BY id; """
+ qt_period_add_3 """ SELECT PERIOD_ADD(period_1, 10), PERIOD_DIFF(period_1,
202512) FROM test_period_union ORDER BY id; """
+ qt_period_add_4 """ SELECT PERIOD_ADD(NULL, month), PERIOD_DIFF(NULL,
period_2) FROM test_period_union ORDER BY id; """
+ qt_period_add_5 """ SELECT PERIOD_ADD(period_1, NULL),
PERIOD_DIFF(period_1, NULL) FROM test_period_union ORDER BY id; """
+ testFoldConst("SELECT PERIOD_ADD(200803, 2)")
+ testFoldConst("SELECT PERIOD_ADD(200809, 5)")
+ testFoldConst("SELECT PERIOD_ADD(9223372036854775807, 1);")
+ testFoldConst("SELECT PERIOD_DIFF(200803, 200804)")
+ testFoldConst("SELECT PERIOD_DIFF(200804, 0803)")
+ testFoldConst("SELECT PERIOD_DIFF(9223372036854775807, 101);")
+
+ sql """ DROP TABLE IF EXISTS test_period_union; """
}
diff --git
a/regression-test/suites/nereids_p0/sql_functions/datetime_functions/test_date_function_v2.groovy
b/regression-test/suites/nereids_p0/sql_functions/datetime_functions/test_date_function_v2.groovy
index 58a04714139..8d5158ea87a 100644
---
a/regression-test/suites/nereids_p0/sql_functions/datetime_functions/test_date_function_v2.groovy
+++
b/regression-test/suites/nereids_p0/sql_functions/datetime_functions/test_date_function_v2.groovy
@@ -86,4 +86,72 @@ suite("test_date_function_v2") {
testFoldConst("select microseconds_diff('2023-10-15 00:00:00', '2023-10-14
00:00:00.1');")
qt_sql_diff14 "select microseconds_diff('2023-10-15 00:00:00', '2023-10-14
00:00:00');"
testFoldConst("select microseconds_diff('2023-10-15 00:00:00', '2023-10-14
00:00:00');")
+
+ def getFormatTable = "get_format_table_test"
+ sql """ DROP TABLE IF EXISTS ${getFormatTable} """
+ sql """ CREATE TABLE ${getFormatTable} (
+ id INT,
+ lc VARCHAR(10)
+ ) DUPLICATE KEY(id)
+ DISTRIBUTED BY HASH(id) BUCKETS 1
+ PROPERTIES ( "replication_num" = "1" ); """
+ sql """ INSERT INTO ${getFormatTable} VALUES
+ (1, 'USA'), (2, 'JIS'), (3, 'ISO'), (4, 'EUR'),
+ (5, 'INTERNAL'), (6, 'Doris'); """
+
+ qt_get_format_date_1 """ SELECT GET_FORMAT(DATE, lc) FROM
${getFormatTable} ORDER BY id; """
+ qt_get_format_date_2 """SELECT GET_FORMAT(DaTe, lc) FROM ${getFormatTable}
ORDER BY id; """
+ qt_get_format_date_3 """SELECT GET_FORMAT(dATe, lc) FROM ${getFormatTable}
ORDER BY id; """
+ qt_get_format_date_4 """SELECT GET_FORMAT(date, '你好');"""
+ qt_get_format_datetime_1 """ SELECT GET_FORMAT(DATETIME, lc) FROM
${getFormatTable} ORDER BY id; """
+ qt_get_format_datetime_2 """SELECT GET_FORMAT(DaTETimE, lc) FROM
${getFormatTable} ORDER BY id; """
+ qt_get_format_datetime_3 """SELECT GET_FORMAT(dATetIMe, lc) FROM
${getFormatTable} ORDER BY id; """
+ qt_get_format_datetime_4 """SELECT GET_FORMAT(datetime, '你好');"""
+ qt_get_format_time_1 """ SELECT GET_FORMAT(TIME, lc) FROM
${getFormatTable} ORDER BY id; """
+ qt_get_format_time_2 """ SELECT GET_FORMAT(TiMe, lc) FROM
${getFormatTable} ORDER BY id; """
+ qt_get_format_time_3 """ SELECT GET_FORMAT(tIME, lc) FROM
${getFormatTable} ORDER BY id; """
+ qt_get_format_time_4 """ SELECT GET_FORMAT(time, '你好'); """
+ test {
+ sql """ SELECT GET_FORMAT(DATA, 'USA'); """
+ exception "Format type only support DATE, DATETIME and TIME"
+ }
+
+ sql """ DROP TABLE IF EXISTS ${getFormatTable} """
+
+ testFoldConst("SELECT GET_FORMAT(DATE, 'USA');")
+ testFoldConst("SELECT GET_FORMAT(date, 'usa');")
+ testFoldConst("SELECT GET_FORMAT(DATE, 'JIS');")
+ testFoldConst("SELECT GET_FORMAT(Date, 'JiS');")
+ testFoldConst("SELECT GET_FORMAT(DATE, 'ISO');")
+ testFoldConst("SELECT GET_FORMAT(DaTe, 'iSo');")
+ testFoldConst("SELECT GET_FORMAT(DATE, 'EUR');")
+ testFoldConst("SELECT GET_FORMAT(daTE, 'EuR');")
+ testFoldConst("SELECT GET_FORMAT(DATE, 'INTERNAL');")
+ testFoldConst("SELECT GET_FORMAT(DaTE, 'InTERnAL');")
+ testFoldConst("SELECT GET_FORMAT(DATE, 'Doris');")
+ testFoldConst("SELECT GET_FORMAT(DATE, '你好');")
+ testFoldConst("SELECT GET_FORMAT(DATETIME, 'USA');")
+ testFoldConst("SELECT GET_FORMAT(datetime, 'Usa');")
+ testFoldConst("SELECT GET_FORMAT(DATETIME, 'JIS');")
+ testFoldConst("SELECT GET_FORMAT(DateTime, 'jis');")
+ testFoldConst("SELECT GET_FORMAT(DATETIME, 'ISO');")
+ testFoldConst("SELECT GET_FORMAT(DaTeTiMe, 'IsO');")
+ testFoldConst("SELECT GET_FORMAT(DATETIME, 'EUR');")
+ testFoldConst("SELECT GET_FORMAT(dateTIME, 'EuR');")
+ testFoldConst("SELECT GET_FORMAT(DATETIME, 'INTERNAL');")
+ testFoldConst("SELECT GET_FORMAT(DaTeTimE, 'internal');")
+ testFoldConst("SELECT GET_FORMAT(DATETIME, 'Doris');")
+ testFoldConst("SELECT GET_FORMAT(DATETIME, '你好');")
+ testFoldConst("SELECT GET_FORMAT(TIME, 'USA');")
+ testFoldConst("SELECT GET_FORMAT(time, 'USa');")
+ testFoldConst("SELECT GET_FORMAT(TIME, 'JIS');")
+ testFoldConst("SELECT GET_FORMAT(TiMe, 'jiS');")
+ testFoldConst("SELECT GET_FORMAT(TIME, 'ISO');")
+ testFoldConst("SELECT GET_FORMAT(TiME, 'iso');")
+ testFoldConst("SELECT GET_FORMAT(TIME, 'EUR');")
+ testFoldConst("SELECT GET_FORMAT(TimE, 'eur');")
+ testFoldConst("SELECT GET_FORMAT(TIME, 'INTERNAL');")
+ testFoldConst("SELECT GET_FORMAT(TImE, 'INTERNAL');")
+ testFoldConst("SELECT GET_FORMAT(TIME, 'Doris');")
+ testFoldConst("SELECT GET_FORMAT(TIME, '你好');")
}
diff --git
a/regression-test/suites/query_p0/sql_functions/string_functions/test_string_function.groovy
b/regression-test/suites/query_p0/sql_functions/string_functions/test_string_function.groovy
index c5b36c56ec5..f7b4d27e0ac 100644
---
a/regression-test/suites/query_p0/sql_functions/string_functions/test_string_function.groovy
+++
b/regression-test/suites/query_p0/sql_functions/string_functions/test_string_function.groovy
@@ -497,6 +497,14 @@ suite("test_string_function", "arrow_flight_sql") {
qt_mask_set_2"""SELECT MAKE_SET(id, vc1, vc2, vc3) FROM test_make_set;"""
qt_mask_set_3"""SELECT MAKE_SET(BIT_SHIFT_LEFT(1, 63) + BIT_SHIFT_LEFT(1,
62) + BIT_SHIFT_LEFT(1, 61) + BIT_SHIFT_LEFT(1, 50) + BIT_SHIFT_LEFT(1, 25) +
BIT_SHIFT_LEFT(1, 3) + BIT_SHIFT_LEFT(1, 1),
'x1','x2','x3','x4','x5','x6','x7','x8','x9','x10','x11','x12','x13','x14','x15','x16','x17','x18','x19','x20','x21','x22','x23','x24','x25','x26','x27','x28','x29','x30','x31','x32','x33','x34','x35','x36','x37','x38','x39','x40','x41','x42','x43','x44','x45','x46','x47','x48','x49','x50',
[...]
qt_mask_set_4"""SELECT MAKE_SET(BIT_SHIFT_LEFT(1, 62) + BIT_SHIFT_LEFT(1,
60) + BIT_SHIFT_LEFT(1, 58) + BIT_SHIFT_LEFT(1, 45) + BIT_SHIFT_LEFT(1, 5) +
BIT_SHIFT_LEFT(1, 2), 'y1', NULL, '', 'y4','y5','y6','y7','y8','y9','y10',
'y11','y12','y13','y14','y15','y16','y17','y18','y19','y20',
'y21','y22','y23','y24','y25','y26','y27','y28','y29','y30',
'y31','y32','y33','y34','y35','y36','y37','y38','y39','y40',
'y41','y42','y43','y44','y45',NULL,'y47','y48');"""
+ qt_mask_set_5"""SELECT id, MAKE_SET(bit_num, 'const1', vc2, 'const3') FROM
test_make_set ORDER BY id;"""
+ qt_mask_set_6"""SELECT id, MAKE_SET(3, vc1, 'middle', vc3) FROM
test_make_set ORDER BY id;"""
+ qt_mask_set_7"""SELECT id, MAKE_SET(bit_num, 'Doris', 'Apache', vc3) FROM
test_make_set ORDER BY id;"""
+ qt_mask_set_8"""SELECT id, MAKE_SET(id, vc1, NULL, 'constant') FROM
test_make_set ORDER BY id;"""
+ qt_mask_set_9"""SELECT id, MAKE_SET(7, vc1, vc2, 'third') FROM
test_make_set ORDER BY id;"""
+ qt_mask_set_10"""SELECT id, MAKE_SET(bit_num, '第一', '第二', vc3) FROM
test_make_set ORDER BY id;"""
+ qt_mask_set_11"""SELECT id, MAKE_SET(5, 'alpha', vc2, 'gamma') FROM
test_make_set ORDER BY id;"""
+ qt_mask_set_12"""SELECT id, MAKE_SET(bit_num, vc1, 'fixed', NULL) FROM
test_make_set ORDER BY id;"""
testFoldConst("SELECT MAKE_SET(1, 'Doris', 'Apache', 'Database');")
testFoldConst("SELECT MAKE_SET(2, 'hello', 'goodbye', 'world');")
@@ -513,8 +521,6 @@ suite("test_string_function", "arrow_flight_sql") {
exception "Can not find the compatibility function signature"
}
- sql """DROP TABLE IF EXISTS test_make_set;"""
-
// EXPORT_SET
sql """DROP TABLE IF EXISTS test_export_set;"""
sql """CREATE TABLE `test_export_set` (
@@ -614,4 +620,117 @@ suite("test_string_function", "arrow_flight_sql") {
testFoldConst("SELECT EXPORT_SET(-9223372036854775808, '1', '0');")
testFoldConst("SELECT EXPORT_SET(-9223372036854775809, '1', '0');")
testFoldConst("SELECT EXPORT_SET(-9223372036854775807, '1', '0');")
+
+ // INSERT function tests
+ sql """DROP TABLE IF EXISTS test_insert_function;"""
+ sql """CREATE TABLE `test_insert_function` (
+ `id` INT,
+ `str` VARCHAR(255),
+ `pos` BIGINT,
+ `len` BIGINT,
+ `newstr` VARCHAR(255)
+ ) DUPLICATE KEY(id)
+ DISTRIBUTED BY HASH(id) BUCKETS 1
+ PROPERTIES ( 'replication_num' = '1' );"""
+
+ sql """INSERT INTO `test_insert_function` VALUES
+ (1, 'Quadratic', 3, 4, 'What'),
+ (2, 'Quadratic', -1, 4, 'What'),
+ (3, 'Quadratic', 3, 100, 'What'),
+ (4, 'Quadratic', 0, 4, 'What'),
+ (5, 'Quadratic', 100, 4, 'What'),
+ (6, 'Quadratic', 3, 0, 'What'),
+ (7, 'Quadratic', 3, -1, 'What'),
+ (8, 'Hello World', 7, 5, 'Doris'),
+ (9, 'Hello World', 1, 5, 'Hi'),
+ (10, 'Hello World', 12, 1, '!'),
+ (11, '', 1, 0, 'test'),
+ (12, 'test', 1, 0, ''),
+ (13, 'test', 1, 10, ''),
+ (14, '你好世界', 3, 2, 'Apache'),
+ (15, 'Hello', 3, 2, '你好'),
+ (16, '你好世界', 2, 1, 'Doris'),
+ (17, 'abcdefg', 1, 7, 'xyz'),
+ (18, 'abcdefg', 4, 0, 'xyz'),
+ (19, 'abcdefg', 8, 1, 'xyz'),
+ (20, 'test', 2, 2, ''),
+ (21, '测试字符串', 1, 2, '新'),
+ (22, '测试字符串', 3, 10, '内容'),
+ (23, 'Special!@#', 8, 3, '***'),
+ (24, 'a', 1, 1, 'b'),
+ (25, 'a', 2, 0, 'b'),
+ (26, NULL, 1, 1, 'test'),
+ (27, 'test', NULL, 1, 'new'),
+ (28, 'test', 1, NULL, 'new'),
+ (29, 'test', 1, 1, NULL),
+ (30, '🎉🎊🎈', 2, 1, '🎁');"""
+
+ qt_insert_1 """SELECT id, INSERT(`str`, `pos`, `len`, `newstr`) FROM
`test_insert_function` ORDER BY `id`;"""
+ qt_insert_2 """SELECT id, INSERT('Quadratic', `pos`, 4, 'What') FROM
`test_insert_function` ORDER BY `id`;"""
+ qt_insert_3 """SELECT id, INSERT(`str`, 3, `len`, 'What') FROM
`test_insert_function` ORDER BY `id`;"""
+ qt_insert_4 """SELECT id, INSERT(`str`, `pos`, 2, `newstr`) FROM
`test_insert_function` ORDER BY `id`;"""
+ testFoldConst("SELECT INSERT('Quadratic', 3, 4, 'What');")
+ testFoldConst("SELECT INSERT('Quadratic', -1, 4, 'What');")
+ testFoldConst("SELECT INSERT('Quadratic', 3, 100, 'What');")
+ testFoldConst("SELECT INSERT('Quadratic', 0, 4, 'What');")
+ testFoldConst("SELECT INSERT('Quadratic', 100, 4, 'What');")
+ testFoldConst("SELECT INSERT('Quadratic', 3, 0, 'What');")
+ testFoldConst("SELECT INSERT('Quadratic', 3, -1, 'What');")
+ testFoldConst("SELECT INSERT('Quadratic', 3, -100, 'What');")
+ testFoldConst("SELECT INSERT('Hello World', 7, 5, 'Doris');")
+ testFoldConst("SELECT INSERT('Hello World', 1, 5, 'Hi');")
+ testFoldConst("SELECT INSERT('Hello World', 12, 1, '!');")
+ testFoldConst("SELECT INSERT('', 1, 0, 'test');")
+ testFoldConst("SELECT INSERT('test', 1, 0, '');")
+ testFoldConst("SELECT INSERT('test', 1, 10, '');")
+ testFoldConst("SELECT INSERT('test', 1, 100, '');")
+ testFoldConst("SELECT INSERT('你好世界', 3, 2, 'Apache');")
+ testFoldConst("SELECT INSERT('Hello', 3, 2, '你好');")
+ testFoldConst("SELECT INSERT('你好世界', 2, 1, 'Doris');")
+ testFoldConst("SELECT INSERT('你好世界', 1, 4, 'Test');")
+ testFoldConst("SELECT INSERT('你好世界', 5, 1, '!');")
+ testFoldConst("SELECT INSERT('abcdefg', 1, 7, 'xyz');")
+ testFoldConst("SELECT INSERT('abcdefg', 4, 0, 'xyz');")
+ testFoldConst("SELECT INSERT('abcdefg', 8, 1, 'xyz');")
+ testFoldConst("SELECT INSERT('abcdefg', 1, 3, '123');")
+ testFoldConst("SELECT INSERT('abcdefg', 4, 3, '456');")
+ testFoldConst("SELECT INSERT('abcdefg', 7, 1, '!');")
+ testFoldConst("SELECT INSERT('test', 2, 2, '');")
+ testFoldConst("SELECT INSERT('test', 1, 0, 'prefix');")
+ testFoldConst("SELECT INSERT('test', 5, 0, 'suffix');")
+ testFoldConst("SELECT INSERT('测试字符串', 1, 2, '新');")
+ testFoldConst("SELECT INSERT('测试字符串', 3, 10, '内容');")
+ testFoldConst("SELECT INSERT('测试字符串', 1, 5, 'Apache Doris');")
+ testFoldConst("SELECT INSERT('Special!@#', 8, 3, '***');")
+ testFoldConst("SELECT INSERT('Special!@#', 1, 7, 'Normal');")
+ testFoldConst("SELECT INSERT('a', 1, 1, 'b');")
+ testFoldConst("SELECT INSERT('a', 2, 0, 'b');")
+ testFoldConst("SELECT INSERT('a', 1, 0, 'b');")
+ testFoldConst("SELECT INSERT('a', 1, 2, 'b');")
+ testFoldConst("SELECT INSERT('🎉🎊🎈', 2, 1, '🎁');")
+ testFoldConst("SELECT INSERT('🎉🎊🎈', 1, 3, '🎁');")
+ testFoldConst("SELECT INSERT('abc', 2, 1, 'XYZ');")
+ testFoldConst("SELECT INSERT('abc', 2, 2, 'XYZ');")
+ testFoldConst("SELECT INSERT('abc', 1, 1, 'XYZ');")
+ testFoldConst("SELECT INSERT('abc', 3, 1, 'XYZ');")
+ testFoldConst("SELECT INSERT('abcdefghijklmnopqrstuvwxyz', 10, 8,
'12345');")
+ testFoldConst("SELECT INSERT('abcdefghijklmnopqrstuvwxyz', 1, 26,
'ALPHABET');")
+ testFoldConst("SELECT INSERT('abcdefghijklmnopqrstuvwxyz', 14, 13,
'END');")
+ testFoldConst("SELECT INSERT('test', 2, 2, 'EST');")
+ testFoldConst("SELECT INSERT('test', 1, 4, 'TEST');")
+ testFoldConst("SELECT INSERT('test', 3, 2, 'ST');")
+ testFoldConst("SELECT INSERT('0123456789', 1, 10, 'X');")
+ testFoldConst("SELECT INSERT('0123456789', 5, 1, 'X');")
+ testFoldConst("SELECT INSERT('0123456789', 11, 0, 'X');")
+ testFoldConst("SELECT INSERT('0123456789', 0, 5, 'X');")
+ testFoldConst("SELECT INSERT('0123456789', -5, 5, 'X');")
+ testFoldConst("SELECT INSERT('0123456789', 5, 0, 'X');")
+ testFoldConst("SELECT INSERT('0123456789', 5, -1, 'X');")
+ testFoldConst("SELECT INSERT('0123456789', 5, 100, 'X');")
+ testFoldConst("SELECT INSERT('Hello World!', 7, 6, 'Doris!');")
+ testFoldConst("SELECT INSERT('Apache Doris', 8, 5, 'Database');")
+ testFoldConst("SELECT INSERT(NULL, 1, 1, 'test');")
+ testFoldConst("SELECT INSERT('test', NULL, 1, 'new');")
+ testFoldConst("SELECT INSERT('test', 1, NULL, 'new');")
+ testFoldConst("SELECT INSERT('test', 1, 1, NULL);")
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]