From eb4c389b0b0a5400cba876dbc23fd7d34220a2ce Mon Sep 17 00:00:00 2001 From: yangshijie Date: Sun, 7 Jan 2024 13:03:11 +0800 Subject: [PATCH] [feature](function) support ip functions isipv4string and isipv6string (#28556) --- be/src/olap/utils.cpp | 14 +- be/src/vec/data_types/data_type_ipv4.cpp | 1 - be/src/vec/functions/function_ip.cpp | 2 + be/src/vec/functions/function_ip.h | 140 ++++++++++++++++++ be/src/vec/io/io_helper.h | 4 +- be/src/vec/runtime/ipv4_value.h | 40 ++++- be/src/vec/runtime/ipv6_value.h | 40 ++++- .../doris/catalog/BuiltinScalarFunctions.java | 4 + .../functions/scalar/IsIpv4String.java | 67 +++++++++ .../functions/scalar/IsIpv6String.java | 67 +++++++++ .../visitor/ScalarFunctionVisitor.java | 10 ++ gensrc/script/doris_builtins_functions.py | 5 + .../data/nereids_function_p0/ip_functions.out | 14 +- .../test_is_ip_string_functions.out | 14 ++ .../nereids_function_p0/ip_functions.groovy | 5 + .../test_is_ip_string_functions.groovy | 44 ++++++ 16 files changed, 441 insertions(+), 30 deletions(-) create mode 100644 fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/IsIpv4String.java create mode 100644 fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/IsIpv6String.java create mode 100644 regression-test/data/query_p0/sql_functions/ip_functions/test_is_ip_string_functions.out create mode 100644 regression-test/suites/query_p0/sql_functions/ip_functions/test_is_ip_string_functions.groovy diff --git a/be/src/olap/utils.cpp b/be/src/olap/utils.cpp index bcdf015da8..e6958343c1 100644 --- a/be/src/olap/utils.cpp +++ b/be/src/olap/utils.cpp @@ -652,21 +652,11 @@ bool valid_bool(const std::string& value_str) { } bool valid_ipv4(const std::string& value_str) { - if (value_str.size() == 0) { - return false; - } - - vectorized::IPv4 value = 0; - return IPv4Value::from_string(value, value_str); + return IPv4Value::is_valid_string(value_str.c_str(), value_str.size()); } bool valid_ipv6(const std::string& value_str) { - if (value_str.size() == 0) { - return false; - } - - vectorized::IPv6 value; - return IPv6Value::from_string(value, value_str); + return IPv6Value::is_valid_string(value_str.c_str(), value_str.size()); } void write_log_info(char* buf, size_t buf_len, const char* fmt, ...) { diff --git a/be/src/vec/data_types/data_type_ipv4.cpp b/be/src/vec/data_types/data_type_ipv4.cpp index 963a1adf82..f7aaca5c73 100644 --- a/be/src/vec/data_types/data_type_ipv4.cpp +++ b/be/src/vec/data_types/data_type_ipv4.cpp @@ -18,7 +18,6 @@ #include "vec/data_types/data_type_ipv4.h" #include "util/binary_cast.hpp" -#include "util/string_parser.hpp" #include "vec/columns/column.h" #include "vec/columns/column_const.h" #include "vec/columns/column_vector.h" diff --git a/be/src/vec/functions/function_ip.cpp b/be/src/vec/functions/function_ip.cpp index ba96331cf7..9a58e97f62 100644 --- a/be/src/vec/functions/function_ip.cpp +++ b/be/src/vec/functions/function_ip.cpp @@ -37,5 +37,7 @@ void register_function_ip(SimpleFunctionFactory& factory) { factory.register_function>(); factory.register_alias(FunctionIPv6StringToNum::name, "inet6_aton"); + factory.register_function(); + factory.register_function(); } } // namespace doris::vectorized \ No newline at end of file diff --git a/be/src/vec/functions/function_ip.h b/be/src/vec/functions/function_ip.h index b5bbe6e5d9..eb76e3f31e 100644 --- a/be/src/vec/functions/function_ip.h +++ b/be/src/vec/functions/function_ip.h @@ -605,4 +605,144 @@ public: } }; +class FunctionIsIPv4String : public IFunction { +private: + Status execute_type(Block& block, const ColumnWithTypeAndName& argument, size_t result) const { + const ColumnPtr& column = argument.column; + + if (const auto* nullable_src = typeid_cast(column.get())) { + size_t col_size = nullable_src->size(); + auto col_res = ColumnUInt8::create(col_size, 0); + auto null_map = ColumnUInt8::create(col_size, 0); + auto& col_res_data = col_res->get_data(); + auto& null_map_data = null_map->get_data(); + + for (size_t i = 0; i < col_size; ++i) { + if (nullable_src->is_null_at(i)) { + null_map_data[i] = 1; + } else { + StringRef ipv4_str = nullable_src->get_data_at(i); + if (IPv4Value::is_valid_string(ipv4_str.data, ipv4_str.size)) { + col_res_data[i] = 1; + } + } + } + + block.replace_by_position( + result, ColumnNullable::create(std::move(col_res), std::move(null_map))); + return Status::OK(); + } else if (const auto* col_src = typeid_cast(column.get())) { + size_t col_size = col_src->size(); + auto col_res = ColumnUInt8::create(col_size, 0); + auto null_map = ColumnUInt8::create(col_size, 0); + auto& col_res_data = col_res->get_data(); + + for (size_t i = 0; i < col_size; ++i) { + StringRef ipv4_str = col_src->get_data_at(i); + if (IPv4Value::is_valid_string(ipv4_str.data, ipv4_str.size)) { + col_res_data[i] = 1; + } + } + + block.replace_by_position( + result, ColumnNullable::create(std::move(col_res), std::move(null_map))); + return Status::OK(); + } else { + return Status::RuntimeError("Illegal column {} of argument of function {}", + argument.column->get_name(), get_name()); + } + } + +public: + static constexpr auto name = "isipv4string"; + static FunctionPtr create() { return std::make_shared(); } + + String get_name() const override { return name; } + + size_t get_number_of_arguments() const override { return 1; } + + DataTypePtr get_return_type_impl(const DataTypes& arguments) const override { + return make_nullable(std::make_shared()); + } + + bool use_default_implementation_for_nulls() const override { return true; } + + Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments, + size_t result, size_t input_rows_count) const override { + ColumnWithTypeAndName& argument = block.get_by_position(arguments[0]); + DCHECK(argument.type->get_type_id() == TypeIndex::String); + return execute_type(block, argument, result); + } +}; + +class FunctionIsIPv6String : public IFunction { +private: + Status execute_type(Block& block, const ColumnWithTypeAndName& argument, size_t result) const { + const ColumnPtr& column = argument.column; + + if (const auto* nullable_src = typeid_cast(column.get())) { + size_t col_size = nullable_src->size(); + auto col_res = ColumnUInt8::create(col_size, 0); + auto null_map = ColumnUInt8::create(col_size, 0); + auto& col_res_data = col_res->get_data(); + auto& null_map_data = null_map->get_data(); + + for (size_t i = 0; i < col_size; ++i) { + if (nullable_src->is_null_at(i)) { + null_map_data[i] = 1; + } else { + StringRef ipv6_str = nullable_src->get_data_at(i); + if (IPv6Value::is_valid_string(ipv6_str.data, ipv6_str.size)) { + col_res_data[i] = 1; + } + } + } + + block.replace_by_position( + result, ColumnNullable::create(std::move(col_res), std::move(null_map))); + return Status::OK(); + } else if (const auto* col_src = typeid_cast(column.get())) { + size_t col_size = col_src->size(); + auto col_res = ColumnUInt8::create(col_size, 0); + auto null_map = ColumnUInt8::create(col_size, 0); + auto& col_res_data = col_res->get_data(); + + for (size_t i = 0; i < col_size; ++i) { + StringRef ipv6_str = col_src->get_data_at(i); + if (IPv6Value::is_valid_string(ipv6_str.data, ipv6_str.size)) { + col_res_data[i] = 1; + } + } + + block.replace_by_position( + result, ColumnNullable::create(std::move(col_res), std::move(null_map))); + return Status::OK(); + } else { + return Status::RuntimeError("Illegal column {} of argument of function {}", + argument.column->get_name(), get_name()); + } + } + +public: + static constexpr auto name = "isipv6string"; + static FunctionPtr create() { return std::make_shared(); } + + String get_name() const override { return name; } + + size_t get_number_of_arguments() const override { return 1; } + + DataTypePtr get_return_type_impl(const DataTypes& arguments) const override { + return make_nullable(std::make_shared()); + } + + bool use_default_implementation_for_nulls() const override { return true; } + + Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments, + size_t result, size_t input_rows_count) const override { + ColumnWithTypeAndName& argument = block.get_by_position(arguments[0]); + DCHECK(argument.type->get_type_id() == TypeIndex::String); + return execute_type(block, argument, result); + } +}; + } // namespace doris::vectorized \ No newline at end of file diff --git a/be/src/vec/io/io_helper.h b/be/src/vec/io/io_helper.h index b3c475c947..9bc255a8b6 100644 --- a/be/src/vec/io/io_helper.h +++ b/be/src/vec/io/io_helper.h @@ -297,7 +297,7 @@ bool read_date_text_impl(T& x, ReadBuffer& buf, const cctz::time_zone& local_tim template bool read_ipv4_text_impl(T& x, ReadBuffer& buf) { static_assert(std::is_same_v); - bool res = IPv4Value::from_string(x, buf.to_string()); + bool res = IPv4Value::from_string(x, buf.position(), buf.count()); buf.position() = buf.end(); return res; } @@ -305,7 +305,7 @@ bool read_ipv4_text_impl(T& x, ReadBuffer& buf) { template bool read_ipv6_text_impl(T& x, ReadBuffer& buf) { static_assert(std::is_same_v); - bool res = IPv6Value::from_string(x, buf.to_string()); + bool res = IPv6Value::from_string(x, buf.position(), buf.count()); buf.position() = buf.end(); return res; } diff --git a/be/src/vec/runtime/ipv4_value.h b/be/src/vec/runtime/ipv4_value.h index 9304aa2c18..b82bc3489b 100644 --- a/be/src/vec/runtime/ipv4_value.h +++ b/be/src/vec/runtime/ipv4_value.h @@ -24,6 +24,7 @@ #include "util/string_parser.hpp" #include "vec/common/format_ip.h" +#include "vec/common/string_ref.h" namespace doris { @@ -43,16 +44,20 @@ public: std::string to_string() const { return to_string(_value); } - static bool from_string(vectorized::IPv4& value, const std::string& ipv4_str) { - if (ipv4_str.empty()) { + static bool from_string(vectorized::IPv4& value, const char* ipv4_str, size_t len) { + if (len == 0) { return false; } int64_t parse_value; - const char* src = ipv4_str.c_str(); - const char* end = ipv4_str.c_str() + ipv4_str.size() - 1; - while (std::isspace(*src)) ++src; - while (std::isspace(*end)) --end; - if (!vectorized::parseIPv4whole(src, ++end, + size_t begin = 0; + size_t end = len - 1; + while (begin < len && std::isspace(ipv4_str[begin])) { + ++begin; + } + while (end > begin && std::isspace(ipv4_str[end])) { + --end; + } + if (!vectorized::parseIPv4whole(ipv4_str + begin, ipv4_str + end + 1, reinterpret_cast(&parse_value))) { return false; } @@ -60,6 +65,10 @@ public: return true; } + static bool from_string(vectorized::IPv4& value, const std::string& ipv4_str) { + return from_string(value, ipv4_str.c_str(), ipv4_str.size()); + } + static std::string to_string(vectorized::IPv4 value) { char buf[IPV4_MAX_TEXT_LENGTH + 1]; char* start = buf; @@ -70,6 +79,23 @@ public: return {buf, len}; } + static bool is_valid_string(const char* ipv4_str, size_t len) { + if (len == 0) { + return false; + } + int64_t parse_value; + size_t begin = 0; + size_t end = len - 1; + while (begin < len && std::isspace(ipv4_str[begin])) { + ++begin; + } + while (end > begin && std::isspace(ipv4_str[end])) { + --end; + } + return vectorized::parseIPv4whole(ipv4_str + begin, ipv4_str + end + 1, + reinterpret_cast(&parse_value)); + } + private: vectorized::IPv4 _value; }; diff --git a/be/src/vec/runtime/ipv6_value.h b/be/src/vec/runtime/ipv6_value.h index 8aaa8a26b6..58e6be3a8a 100644 --- a/be/src/vec/runtime/ipv6_value.h +++ b/be/src/vec/runtime/ipv6_value.h @@ -42,15 +42,24 @@ public: bool from_string(const std::string& ipv6_str) { return from_string(_value, ipv6_str); } - static bool from_string(vectorized::IPv6& value, const std::string& ipv6_str) { - if (ipv6_str.empty()) { + static bool from_string(vectorized::IPv6& value, const char* ipv6_str, size_t len) { + if (len == 0) { return false; } - const char* src = ipv6_str.c_str(); - const char* end = ipv6_str.c_str() + ipv6_str.size() - 1; - while (std::isspace(*src)) ++src; - while (std::isspace(*end)) --end; - return vectorized::parseIPv6whole(src, ++end, reinterpret_cast(&value)); + size_t begin = 0; + size_t end = len - 1; + while (begin < len && std::isspace(ipv6_str[begin])) { + ++begin; + } + while (end > begin && std::isspace(ipv6_str[end])) { + --end; + } + return vectorized::parseIPv6whole(ipv6_str + begin, ipv6_str + end + 1, + reinterpret_cast(&value)); + } + + static bool from_string(vectorized::IPv6& value, const std::string& ipv6_str) { + return from_string(value, ipv6_str.c_str(), ipv6_str.size()); } std::string to_string() const { return to_string(_value); } @@ -65,6 +74,23 @@ public: return {buf, len}; } + static bool is_valid_string(const char* ipv6_str, size_t len) { + if (len == 0 || len > IPV6_MAX_TEXT_LENGTH) { + return false; + } + vectorized::IPv6 value; + size_t begin = 0; + size_t end = len - 1; + while (begin < len && std::isspace(ipv6_str[begin])) { + ++begin; + } + while (end > begin && std::isspace(ipv6_str[end])) { + --end; + } + return vectorized::parseIPv6whole(ipv6_str + begin, ipv6_str + end + 1, + reinterpret_cast(&value)); + } + private: vectorized::IPv6 _value; }; 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 2193f3631e..185e3bdada 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 @@ -198,6 +198,8 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.Ipv6NumToStri import org.apache.doris.nereids.trees.expressions.functions.scalar.Ipv6StringToNum; import org.apache.doris.nereids.trees.expressions.functions.scalar.Ipv6StringToNumOrDefault; import org.apache.doris.nereids.trees.expressions.functions.scalar.Ipv6StringToNumOrNull; +import org.apache.doris.nereids.trees.expressions.functions.scalar.IsIpv4String; +import org.apache.doris.nereids.trees.expressions.functions.scalar.IsIpv6String; import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonArray; import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonContains; import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonExtract; @@ -599,6 +601,8 @@ public class BuiltinScalarFunctions implements FunctionHelper { scalar(Ipv6StringToNum.class, "ipv6_string_to_num", "inet6_aton"), scalar(Ipv6StringToNumOrDefault.class, "ipv6_string_to_num_or_default"), scalar(Ipv6StringToNumOrNull.class, "ipv6_string_to_num_or_null"), + scalar(IsIpv4String.class, "isipv4string"), + scalar(IsIpv6String.class, "isipv6string"), scalar(JsonArray.class, "json_array"), scalar(JsonObject.class, "json_object"), scalar(JsonQuote.class, "json_quote"), diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/IsIpv4String.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/IsIpv4String.java new file mode 100644 index 0000000000..2216d749f2 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/IsIpv4String.java @@ -0,0 +1,67 @@ +// 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.BooleanType; +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; + +/** + * scalar function IsIpv4String + */ +public class IsIpv4String extends ScalarFunction + implements BinaryExpression, ExplicitlyCastableSignature, AlwaysNullable { + + public static final List SIGNATURES = ImmutableList.of( + FunctionSignature.ret(BooleanType.INSTANCE).args(VarcharType.SYSTEM_DEFAULT), + FunctionSignature.ret(BooleanType.INSTANCE).args(StringType.INSTANCE)); + + public IsIpv4String(Expression arg0) { + super("isipv4string", arg0); + } + + @Override + public IsIpv4String withChildren(List children) { + Preconditions.checkArgument(children.size() == 1, + "isipv4string accept 1 args, but got %s (%s)", + children.size(), + children); + return new IsIpv4String(children.get(0)); + } + + @Override + public List getSignatures() { + return SIGNATURES; + } + + @Override + public R accept(ExpressionVisitor visitor, C context) { + return visitor.visitIsIpv4String(this, context); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/IsIpv6String.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/IsIpv6String.java new file mode 100644 index 0000000000..9963501840 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/IsIpv6String.java @@ -0,0 +1,67 @@ +// 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.BooleanType; +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; + +/** + * scalar function IsIpv6String + */ +public class IsIpv6String extends ScalarFunction + implements BinaryExpression, ExplicitlyCastableSignature, AlwaysNullable { + + public static final List SIGNATURES = ImmutableList.of( + FunctionSignature.ret(BooleanType.INSTANCE).args(VarcharType.SYSTEM_DEFAULT), + FunctionSignature.ret(BooleanType.INSTANCE).args(StringType.INSTANCE)); + + public IsIpv6String(Expression arg0) { + super("isipv6string", arg0); + } + + @Override + public IsIpv6String withChildren(List children) { + Preconditions.checkArgument(children.size() == 1, + "isipv6string accept 1 args, but got %s (%s)", + children.size(), + children); + return new IsIpv6String(children.get(0)); + } + + @Override + public List getSignatures() { + return SIGNATURES; + } + + @Override + public R accept(ExpressionVisitor visitor, C context) { + return visitor.visitIsIpv6String(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 944bb4fdb8..73756dd2c6 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 @@ -194,6 +194,8 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.Ipv6NumToStri import org.apache.doris.nereids.trees.expressions.functions.scalar.Ipv6StringToNum; import org.apache.doris.nereids.trees.expressions.functions.scalar.Ipv6StringToNumOrDefault; import org.apache.doris.nereids.trees.expressions.functions.scalar.Ipv6StringToNumOrNull; +import org.apache.doris.nereids.trees.expressions.functions.scalar.IsIpv4String; +import org.apache.doris.nereids.trees.expressions.functions.scalar.IsIpv6String; import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonArray; import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonContains; import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonExtract; @@ -1136,6 +1138,14 @@ public interface ScalarFunctionVisitor { return visitScalarFunction(ipv6StringToNumOrNull, context); } + default R visitIsIpv4String(IsIpv4String isIpv4String, C context) { + return visitScalarFunction(isIpv4String, context); + } + + default R visitIsIpv6String(IsIpv6String isIpv6String, C context) { + return visitScalarFunction(isIpv6String, context); + } + default R visitJsonArray(JsonArray jsonArray, C context) { return visitScalarFunction(jsonArray, context); } diff --git a/gensrc/script/doris_builtins_functions.py b/gensrc/script/doris_builtins_functions.py index 1ec2973f87..b3f5a7b58b 100644 --- a/gensrc/script/doris_builtins_functions.py +++ b/gensrc/script/doris_builtins_functions.py @@ -2012,6 +2012,11 @@ visible_functions = { [['ipv6_string_to_num_or_default'], 'STRING', ['STRING'], 'ALWAYS_NOT_NULLABLE'], [['ipv6_string_to_num_or_null'], 'VARCHAR', ['VARCHAR'], 'ALWAYS_NULLABLE'], [['ipv6_string_to_num_or_null'], 'STRING', ['STRING'], 'ALWAYS_NULLABLE'], + [['ipv6numtostring','inet6_ntoa'], 'STRING', ['STRING'], 'ALWAYS_NULLABLE'], + [['isipv4string'], 'BOOLEAN', ['VARCHAR'], 'ALWAYS_NULLABLE'], + [['isipv4string'], 'BOOLEAN', ['STRING'], 'ALWAYS_NULLABLE'], + [['isipv6string'], 'BOOLEAN', ['VARCHAR'], 'ALWAYS_NULLABLE'], + [['isipv6string'], 'BOOLEAN', ['STRING'], 'ALWAYS_NULLABLE'], ], "NonNullalbe": [ diff --git a/regression-test/data/nereids_function_p0/ip_functions.out b/regression-test/data/nereids_function_p0/ip_functions.out index 56ae095999..2e3b749a15 100644 --- a/regression-test/data/nereids_function_p0/ip_functions.out +++ b/regression-test/data/nereids_function_p0/ip_functions.out @@ -150,4 +150,16 @@ AAAAAAAAFFFFFFFFFFFFFFFFAAAAAAAA 00000000000000000000FFFFC0A80001 -- !ip51 -- -2A0206B8000000000000000000000011 \ No newline at end of file +2A0206B8000000000000000000000011 + +-- !ip52 -- +true + +-- !ip53 -- +false + +-- !ip54 -- +true + +-- !ip55 -- +false \ No newline at end of file diff --git a/regression-test/data/query_p0/sql_functions/ip_functions/test_is_ip_string_functions.out b/regression-test/data/query_p0/sql_functions/ip_functions/test_is_ip_string_functions.out new file mode 100644 index 0000000000..2db89a7eb6 --- /dev/null +++ b/regression-test/data/query_p0/sql_functions/ip_functions/test_is_ip_string_functions.out @@ -0,0 +1,14 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !sql1 -- +\N +false +false +false +true + +-- !sql2 -- +\N +true +false +true +false diff --git a/regression-test/suites/nereids_function_p0/ip_functions.groovy b/regression-test/suites/nereids_function_p0/ip_functions.groovy index 837eca9211..dc6e3de7d6 100644 --- a/regression-test/suites/nereids_function_p0/ip_functions.groovy +++ b/regression-test/suites/nereids_function_p0/ip_functions.groovy @@ -72,4 +72,9 @@ suite("ip_functions") { qt_ip49 "SELECT hex(ipv6_string_to_num_or_null('aaaa:aaaa:ffff:ffff:ffff:ffff:aaaa:aaaa'));" qt_ip50 "SELECT hex(inet6_aton('192.168.0.1'));" qt_ip51 "SELECT hex(inet6_aton('2a02:6b8::11'));" + + qt_ip52 "SELECT isipv4string('255.255.255.255');" + qt_ip53 "SELECT isipv4string('255.255.255.256');" + qt_ip54 "SELECT isipv6string('2001:5b0:23ff:fffa::113');" + qt_ip55 "SELECT isipv6string('2001:da8:e000:1691:2eaa:7eff:ffe7:7924e');" } \ No newline at end of file diff --git a/regression-test/suites/query_p0/sql_functions/ip_functions/test_is_ip_string_functions.groovy b/regression-test/suites/query_p0/sql_functions/ip_functions/test_is_ip_string_functions.groovy new file mode 100644 index 0000000000..70740dd479 --- /dev/null +++ b/regression-test/suites/query_p0/sql_functions/ip_functions/test_is_ip_string_functions.groovy @@ -0,0 +1,44 @@ +// 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. +suite("test_is_ip_string_functions") { + sql """ DROP TABLE IF EXISTS test_is_ip_string """ + + sql """ SET enable_nereids_planner=true """ + sql """ SET enable_fallback_to_original_planner=false """ + + sql """ + CREATE TABLE `test_is_ip_string` ( + `id` int, + `ip_v4` string, + `ip_v6` string + ) ENGINE=OLAP + DISTRIBUTED BY HASH(`id`) BUCKETS 4 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1" + ); + """ + sql "insert into test_is_ip_string values(0, NULL, NULL)" + sql "insert into test_is_ip_string values(1, '0.0.0.', '::')" + sql "insert into test_is_ip_string values(2, '', '')" + sql "insert into test_is_ip_string values(3, '.', '2001:1b70:a1:610::b102:2')" + sql "insert into test_is_ip_string values(4, '255.255.255.255', 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffffg')" + + qt_sql1 "select isipv4string(ip_v4) from test_is_ip_string order by id" + qt_sql2 "select isipv6string(ip_v6) from test_is_ip_string order by id" + + sql "DROP TABLE test_is_ip_string" +} \ No newline at end of file