github-actions[bot] commented on code in PR #68407:
URL: https://github.com/apache/doris/pull/68407#discussion_r4079772906


##########
be/src/exprs/function/function_ip.h:
##########
@@ -792,72 +793,52 @@ class FunctionIPv4CIDRToRange : public IFunction {
 
     DataTypePtr get_return_type_impl(const DataTypes& arguments) const 
override {
         DataTypePtr element = std::make_shared<DataTypeIPv4>();
-        return std::make_shared<DataTypeStruct>(DataTypes {element, element},
-                                                Strings {"min", "max"});
+        DataTypePtr result = std::make_shared<DataTypeStruct>(DataTypes 
{element, element},
+                                                              Strings {"min", 
"max"});
+        if (arguments[0]->is_nullable() || arguments[1]->is_nullable()) {
+            return make_nullable(result);
+        }
+        return result;
     }
 
+    bool use_default_implementation_for_nulls() const override { return false; 
}
+
     Status execute_impl(FunctionContext* context, Block& block, const 
ColumnNumbers& arguments,
                         uint32_t result, size_t input_rows_count) const 
override {
-        ColumnWithTypeAndName& ip_column = block.get_by_position(arguments[0]);
-        ColumnWithTypeAndName& cidr_column = 
block.get_by_position(arguments[1]);
-
-        const auto& [ip_column_ptr, ip_col_const] = 
unpack_if_const(ip_column.column);
-        const auto& [cidr_column_ptr, cidr_col_const] = 
unpack_if_const(cidr_column.column);
-
-        const auto* col_ip_column = assert_cast<const 
ColumnIPv4*>(ip_column_ptr.get());
-        const auto* col_cidr_column = assert_cast<const 
ColumnInt16*>(cidr_column_ptr.get());
+        const auto& ip_argument = block.get_by_position(arguments[0]);
+        const auto& cidr_argument = block.get_by_position(arguments[1]);
+        const auto ip = ColumnView<TYPE_IPV4>::create(ip_argument.column);
+        const auto cidr = 
ColumnView<TYPE_SMALLINT>::create(cidr_argument.column);
 
-        const typename ColumnIPv4::Container& vec_ip_input = 
col_ip_column->get_data();
-        const ColumnInt16::Container& vec_cidr_input = 
col_cidr_column->get_data();
         auto col_lower_range_output = ColumnIPv4::create(input_rows_count, 0);
         auto col_upper_range_output = ColumnIPv4::create(input_rows_count, 0);
-
-        ColumnIPv4::Container& vec_lower_range_output = 
col_lower_range_output->get_data();
-        ColumnIPv4::Container& vec_upper_range_output = 
col_upper_range_output->get_data();
-
+        auto null_map = ColumnUInt8::create(input_rows_count, 0);

Review Comment:
   **[P2] Keep the non-nullable path allocation-free**
   
   When both arguments are declared non-nullable, `get_return_type_impl` 
returns a non-nullable struct and neither `ColumnView` can report NULL, but 
this still allocates and zero-fills `input_rows_count` bytes and the branch 
below discards the map. The same dead O(rows) allocation was added at lines 883 
and 1254 for the other two functions, so ordinary non-nullable queries now pay 
it on every block. Please allocate/populate a null map only when the declared 
result is nullable (and preserve a direct non-nullable fast path).



##########
be/src/exprs/function/function_ip.h:
##########
@@ -878,91 +859,113 @@ class FunctionIPv6CIDRToRange : public IFunction {
 
     DataTypePtr get_return_type_impl(const DataTypes& arguments) const 
override {
         DataTypePtr element = std::make_shared<DataTypeIPv6>();
-        return std::make_shared<DataTypeStruct>(DataTypes {element, element},
-                                                Strings {"min", "max"});
+        DataTypePtr result = std::make_shared<DataTypeStruct>(DataTypes 
{element, element},
+                                                              Strings {"min", 
"max"});
+        if (arguments[0]->is_nullable() || arguments[1]->is_nullable()) {
+            return make_nullable(result);
+        }
+        return result;
     }
 
+    bool use_default_implementation_for_nulls() const override { return false; 
}
+
     Status execute_impl(FunctionContext* context, Block& block, const 
ColumnNumbers& arguments,
                         uint32_t result, size_t input_rows_count) const 
override {
         const auto& addr_column_with_type_and_name = 
block.get_by_position(arguments[0]);
         const auto& cidr_column_with_type_and_name = 
block.get_by_position(arguments[1]);
-        const auto& [addr_column, add_col_const] =
-                unpack_if_const(addr_column_with_type_and_name.column);
-        const auto& [cidr_column, col_const] =
-                unpack_if_const(cidr_column_with_type_and_name.column);
+        const auto cidr = 
ColumnView<TYPE_SMALLINT>::create(cidr_column_with_type_and_name.column);
+        const auto addr_type = 
addr_column_with_type_and_name.type->get_primitive_type();
 
-        const auto* cidr_col = assert_cast<const 
ColumnInt16*>(cidr_column.get());
-        ColumnPtr col_res = nullptr;
-
-        if (addr_column_with_type_and_name.type->get_primitive_type() == 
TYPE_IPV6) {
-            const auto* ipv6_addr_column = assert_cast<const 
ColumnIPv6*>(addr_column.get());
-            col_res = execute_impl(*ipv6_addr_column, *cidr_col, 
input_rows_count, add_col_const,
-                                   col_const);
-        } else if 
(is_string_type(addr_column_with_type_and_name.type->get_primitive_type())) {
-            ColumnPtr col_ipv6 =
-                    
convert_to_ipv6<IPConvertExceptionMode::Throw>(addr_column, nullptr);
-            const auto* ipv6_addr_column = assert_cast<const 
ColumnIPv6*>(col_ipv6.get());
-            col_res = execute_impl(*ipv6_addr_column, *cidr_col, 
input_rows_count, add_col_const,
-                                   col_const);
+        auto col_res_lower_range = ColumnIPv6::create(input_rows_count, 0);
+        auto col_res_upper_range = ColumnIPv6::create(input_rows_count, 0);
+        auto& vec_res_lower_range = col_res_lower_range->get_data();
+        auto& vec_res_upper_range = col_res_upper_range->get_data();
+        auto null_map = ColumnUInt8::create(input_rows_count, 0);
+        auto& nulls = null_map->get_data();
+        if (addr_type == TYPE_IPV6) {
+            const auto addr = 
ColumnView<TYPE_IPV6>::create(addr_column_with_type_and_name.column);
+            execute_impl(addr, cidr, input_rows_count, vec_res_lower_range, 
vec_res_upper_range,
+                         nulls);
+        } else if (is_string_type(addr_type)) {
+            const auto addr =
+                    
ColumnView<TYPE_STRING>::create(addr_column_with_type_and_name.column);
+            execute_impl(addr, cidr, input_rows_count, vec_res_lower_range, 
vec_res_upper_range,
+                         nulls);
         } else {
             return Status::RuntimeError(
                     "Illegal column {} of argument of function {}, Expected 
IPv6 or String",
-                    addr_column->get_name(), get_name());
+                    addr_column_with_type_and_name.column->get_name(), 
get_name());
         }
 
-        block.replace_by_position(result, std::move(col_res));
+        ColumnPtr result_column = ColumnStruct::create(
+                Columns {std::move(col_res_lower_range), 
std::move(col_res_upper_range)});
+        if (block.get_by_position(result).type->is_nullable()) {
+            result_column = ColumnNullable::create(std::move(result_column), 
std::move(null_map));
+        }
+        block.replace_by_position(result, std::move(result_column));
         return Status::OK();
     }
 
-    static ColumnPtr execute_impl(const ColumnIPv6& from_column, const 
ColumnInt16& cidr_column,
-                                  size_t input_rows_count, bool is_addr_const 
= false,
-                                  bool is_cidr_const = false) {
-        auto col_res_lower_range = ColumnIPv6::create(input_rows_count, 0);
-        auto col_res_upper_range = ColumnIPv6::create(input_rows_count, 0);
-        auto& vec_res_lower_range = col_res_lower_range->get_data();
-        auto& vec_res_upper_range = col_res_upper_range->get_data();
-
+private:
+    static void execute_impl(const ColumnView<TYPE_IPV6>& addr,
+                             const ColumnView<TYPE_SMALLINT>& cidr, size_t 
input_rows_count,
+                             ColumnIPv6::Container& lower, 
ColumnIPv6::Container& upper,
+                             ColumnUInt8::Container& nulls) {
         static constexpr UInt8 max_cidr_mask = IPV6_BINARY_LENGTH * 8;
+        for (size_t i = 0; i < input_rows_count; ++i) {
+            if (addr.is_null_at(i) || cidr.is_null_at(i)) {
+                nulls[i] = 1;
+                continue;
+            }
+            const auto prefix = cidr.value_at(i);
+            if (prefix < 0 || prefix > max_cidr_mask) {
+                throw Exception(ErrorCode::INVALID_ARGUMENT, "Illegal cidr 
value '{}'",
+                                std::to_string(prefix));
+            }
+            const auto address = addr.value_at(i);
+            apply_cidr_mask(reinterpret_cast<const char*>(&address),
+                            reinterpret_cast<char*>(&lower[i]), 
reinterpret_cast<char*>(&upper[i]),
+                            cast_set<UInt8>(prefix));
+        }
+    }
 
-        if (is_addr_const) {
-            for (size_t i = 0; i < input_rows_count; ++i) {
-                auto cidr = cidr_column.get_int(i);
-                if (cidr < 0 || cidr > max_cidr_mask) {
-                    throw Exception(ErrorCode::INVALID_ARGUMENT, "Illegal cidr 
value '{}'",
-                                    std::to_string(cidr));
-                }
-                apply_cidr_mask(from_column.get_data_at(0).data,
-                                
reinterpret_cast<char*>(&vec_res_lower_range[i]),
-                                
reinterpret_cast<char*>(&vec_res_upper_range[i]),
-                                cast_set<UInt8>(cidr));
+    static void execute_impl(const ColumnView<TYPE_STRING>& addr,
+                             const ColumnView<TYPE_SMALLINT>& cidr, size_t 
input_rows_count,
+                             ColumnIPv6::Container& lower, 
ColumnIPv6::Container& upper,
+                             ColumnUInt8::Container& nulls) {
+        static constexpr UInt8 max_cidr_mask = IPV6_BINARY_LENGTH * 8;
+        for (size_t i = 0; i < input_rows_count; ++i) {
+            if (addr.is_null_at(i) || cidr.is_null_at(i)) {
+                nulls[i] = 1;
+                continue;
             }
-        } else if (is_cidr_const) {
-            auto cidr = cidr_column.get_int(0);
-            if (cidr < 0 || cidr > max_cidr_mask) {
+            const auto prefix = cidr.value_at(i);
+            if (prefix < 0 || prefix > max_cidr_mask) {
                 throw Exception(ErrorCode::INVALID_ARGUMENT, "Illegal cidr 
value '{}'",
-                                std::to_string(cidr));
+                                std::to_string(prefix));
             }
-            for (size_t i = 0; i < input_rows_count; ++i) {
-                apply_cidr_mask(from_column.get_data_at(i).data,
-                                
reinterpret_cast<char*>(&vec_res_lower_range[i]),
-                                
reinterpret_cast<char*>(&vec_res_upper_range[i]),
-                                cast_set<UInt8>(cidr));
+            const auto value = addr.value_at(i);
+            if (value.size == 0) {
+                throw Exception(ErrorCode::INVALID_ARGUMENT, "Invalid IPv6 
value");
             }
-        } else {
-            for (size_t i = 0; i < input_rows_count; ++i) {
-                auto cidr = cidr_column.get_int(i);
-                if (cidr < 0 || cidr > max_cidr_mask) {
-                    throw Exception(ErrorCode::INVALID_ARGUMENT, "Illegal cidr 
value '{}'",
-                                    std::to_string(cidr));
-                }
-                apply_cidr_mask(from_column.get_data_at(i).data,
-                                
reinterpret_cast<char*>(&vec_res_lower_range[i]),
-                                
reinterpret_cast<char*>(&vec_res_upper_range[i]),
-                                cast_set<UInt8>(cidr));
+            IPv6 address = 0;
+            Int64 parsed_ipv4 = 0;
+            bool parsed = false;
+            if (try_parse_ipv4(value.begin(), value.end(), parsed_ipv4)) {

Review Comment:
   **[P2] Preserve the constant-string fast path**
   
   When the address is a constant string but the CIDR varies (for example, 
`ipv6_cidr_to_range('2001:db8::1', cidr_column)`), `addr.value_at(i)` correctly 
reuses element 0, but this loop still runs `try_parse_ipv4`/`parse_ipv6_whole` 
for every row. Before this change, `unpack_if_const` left a one-row nested 
string, `convert_to_ipv6` parsed it once, and the mask loop reused the parsed 
address. This turns one parse per block into O(rows) identical parses. Please 
cache the first needed non-NULL constant parse after the row's NULL and 
CIDR-range checks (or otherwise preserve the converted constant fast path).



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

To unsubscribe, e-mail: [email protected]

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


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

Reply via email to