diff --git a/be/src/exprs/function/function_string_misc.cpp b/be/src/exprs/function/function_string_misc.cpp index 663fa0fe018591..56d2add78014f3 100644 --- a/be/src/exprs/function/function_string_misc.cpp +++ b/be/src/exprs/function/function_string_misc.cpp @@ -100,6 +100,7 @@ class FunctionAutoPartitionName : public IFunction { 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; } + bool use_default_implementation_for_constants() const override { return false; } DataTypePtr get_return_type_impl(const DataTypes& arguments) const override { return std::make_shared(); } @@ -107,13 +108,15 @@ class FunctionAutoPartitionName : public IFunction { Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments, uint32_t result, size_t input_rows_count) const override { size_t argument_size = arguments.size(); + if (argument_size < 2) { + return Status::InvalidArgument( + "function auto_partition_name must contains at least two arguments"); + } + auto const_null_map = ColumnUInt8::create(input_rows_count, 0); - auto null_map = ColumnUInt8::create(input_rows_count, 0); - std::vector chars_list(argument_size); - std::vector offsets_list(argument_size); + std::vector string_columns(argument_size); std::vector is_const_args(argument_size); std::vector null_list(argument_size); - std::vector argument_null_columns(argument_size); std::vector argument_columns(argument_size); for (int i = 0; i < argument_size; ++i) { @@ -122,19 +125,14 @@ class FunctionAutoPartitionName : public IFunction { if (const auto* nullable = check_and_get_column(*argument_columns[i])) { null_list[i] = &nullable->get_null_map_data(); - argument_null_columns[i] = nullable->get_null_map_column_ptr(); argument_columns[i] = nullable->get_nested_column_ptr(); } else { null_list[i] = &const_null_map->get_data(); } - const auto& [col, is_const] = - unpack_if_const(block.get_by_position(arguments[i]).column); - const auto* col_str = assert_cast(argument_columns[i].get()); - chars_list[i] = &col_str->get_chars(); - offsets_list[i] = &col_str->get_offsets(); - is_const_args[i] = is_const; + string_columns[i] = col_str; + is_const_args[i] = is_column_const(*block.get_by_position(arguments[i]).column); } auto res = ColumnString::create(); @@ -142,20 +140,34 @@ class FunctionAutoPartitionName : public IFunction { auto& res_offset = res->get_offsets(); res_offset.resize(input_rows_count); - std::string partition_type(chars_list[0]->raw_data(), (*offsets_list[0])[0]); + if (input_rows_count == 0) { + block.get_by_position(result).column = std::move(res); + return Status::OK(); + } + if (!is_const_args[0]) { + return Status::InvalidArgument( + "auto_partition_name must accept literal for 1st argument"); + } + if ((*null_list[0])[0]) { + return Status::InvalidArgument( + "function auto_partition_name must accept range|list for 1st argument"); + } + + std::string partition_type = string_columns[0]->get_data_at(0).to_string(); std::transform(partition_type.begin(), partition_type.end(), partition_type.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); // partition type is list|range if (partition_type == "list") { - return _auto_partition_type_of_list(chars_list, offsets_list, is_const_args, null_list, - res_data, res_offset, input_rows_count, - argument_size, block, result, res); - } else { - return _auto_partition_type_of_range(chars_list, offsets_list, is_const_args, res_data, + return _auto_partition_type_of_list(string_columns, is_const_args, null_list, res_data, + res_offset, input_rows_count, argument_size, block, + result, res); + } else if (partition_type == "range") { + return _auto_partition_type_of_range(string_columns, is_const_args, null_list, res_data, res_offset, input_rows_count, argument_size, block, result, res); } - return Status::OK(); + return Status::InvalidArgument( + "function auto_partition_name must accept range|list for 1st argument"); } private: @@ -194,8 +206,7 @@ class FunctionAutoPartitionName : public IFunction { return first; } - Status _auto_partition_type_of_list(std::vector& chars_list, - std::vector& offsets_list, + Status _auto_partition_type_of_list(std::vector& string_columns, std::vector& is_const_args, const std::vector& null_list, auto& res_data, auto& res_offset, size_t input_rows_count, @@ -207,8 +218,6 @@ class FunctionAutoPartitionName : public IFunction { res_p.reserve(argument_size * 5); res_p += 'p'; for (int col = 1; col < argument_size; col++) { - const auto& current_offsets = *offsets_list[col]; - const auto& current_chars = *chars_list[col]; const auto& current_nullmap = *null_list[col]; if (current_nullmap[row]) { @@ -216,11 +225,8 @@ class FunctionAutoPartitionName : public IFunction { } else { auto idx = index_check_const(row, is_const_args[col]); - int size = current_offsets[idx] - current_offsets[idx - 1]; - const char* raw_chars = - reinterpret_cast(¤t_chars[current_offsets[idx - 1]]); // convert string to u16string in order to convert to unicode strings - const std::string raw_str(raw_chars, size); + const std::string raw_str = string_columns[col]->get_data_at(idx).to_string(); auto u16string = _string_to_u16string(raw_str); res_p += _string_to_unicode(u16string) + std::to_string(u16string.size()); } @@ -253,26 +259,38 @@ class FunctionAutoPartitionName : public IFunction { return curr_len; } - Status _auto_partition_type_of_range(std::vector& chars_list, - std::vector& offsets_list, - std::vector& is_const_args, auto& res_data, - auto& res_offset, size_t input_rows_count, - size_t argument_size, Block& block, uint32_t result, - auto& res) const { - std::string range_type(chars_list[1]->raw_data(), (*offsets_list[1])[0]); + Status _auto_partition_type_of_range( + std::vector& string_columns, std::vector& is_const_args, + const std::vector& null_list, auto& res_data, + auto& res_offset, size_t input_rows_count, size_t argument_size, Block& block, + uint32_t result, auto& res) const { + if (argument_size != 3) { + return Status::InvalidArgument( + "range auto_partition_name must contains three arguments"); + } + if (!is_const_args[1]) { + return Status::InvalidArgument( + "auto_partition_name must accept literal for 2nd argument"); + } + if ((*null_list[1])[0]) { + return Status::InvalidArgument( + "range auto_partition_name must accept year|month|day|hour|minute|second for " + "2nd argument"); + } + std::string range_type = string_columns[1]->get_data_at(0).to_string(); std::transform(range_type.begin(), range_type.end(), range_type.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); + if (range_type != "year" && range_type != "month" && range_type != "day" && + range_type != "hour" && range_type != "minute" && range_type != "second") { + return Status::InvalidArgument( + "range auto_partition_name must accept year|month|day|hour|minute|second for " + "2nd argument"); + } res_data.resize(15 * input_rows_count); for (int i = 0; i < input_rows_count; i++) { - const auto& current_offsets = *offsets_list[2]; - const auto& current_chars = *chars_list[2]; - auto idx = index_check_const(i, is_const_args[2]); - int size = current_offsets[idx] - current_offsets[idx - 1]; - const char* tmp = - reinterpret_cast(¤t_chars[current_offsets[idx - 1]]); - std::string to_split_s(tmp, size); + std::string to_split_s = string_columns[2]->get_data_at(idx).to_string(); // check the str if it is date|datetime RE2 date_regex(R"(^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}:\d{2})?$)"); @@ -283,7 +301,7 @@ class FunctionAutoPartitionName : public IFunction { // split date_str from (yyyy-mm-dd hh:mm:ss) to ([yyyy, mm, dd, hh, mm, ss]) std::vector date_str(6); date_str[0] = to_split_s.substr(0, 4); - for (int ni = 5, j = 1; ni <= size; ni += 3, j++) { + for (size_t ni = 5, j = 1; ni <= to_split_s.size(); ni += 3, j++) { date_str[j] = to_split_s.substr(ni, 2); } int curr_len = 0; diff --git a/be/test/exprs/function/function_string_test.cpp b/be/test/exprs/function/function_string_test.cpp index c9c818d2d59bd4..e7e1640df860e7 100644 --- a/be/test/exprs/function/function_string_test.cpp +++ b/be/test/exprs/function/function_string_test.cpp @@ -87,6 +87,7 @@ TEST(function_string_test, function_auto_partition_name_case_insensitive_test) { const DataSet list_data_set = { {{std::string("LIST"), std::string("edc_server2")}, std::string("pedc5fserver211")}, {{std::string("LiSt"), std::string("edc_server2")}, std::string("pedc5fserver211")}, + {{std::string("LIST"), std::string("10")}, std::string("p102")}, }; for (const auto& data : list_data_set) { ASSERT_TRUE(check_function("auto_partition_name", list_input_types, {data}) @@ -106,6 +107,13 @@ TEST(function_string_test, function_auto_partition_name_case_insensitive_test) { ASSERT_TRUE(check_function("auto_partition_name", range_input_types, {data}) .ok()); } + + const DataSet invalid_range_data_set = { + {{std::string("RANGE"), std::string("DAY")}, std::string("")}, + }; + ASSERT_FALSE(check_function("auto_partition_name", list_input_types, + invalid_range_data_set, -1, -1, true) + .ok()); } TEST(function_string_test, function_string_substr_test) {