This is an automated email from the ASF dual-hosted git repository. yiguolei pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push: new 7a0a33c820a [feature](function) support ip function named is_ip_address_in_range(addr, cidr) (#29681) 7a0a33c820a is described below commit 7a0a33c820aa3c38a1bca123a29a65973284990b Author: yangshijie <sjyang2...@zju.edu.cn> AuthorDate: Tue Jan 9 15:19:51 2024 +0800 [feature](function) support ip function named is_ip_address_in_range(addr, cidr) (#29681) --- be/src/vec/functions/function_ip.cpp | 8 +- be/src/vec/functions/function_ip.h | 107 ++++++++++++++-- be/src/vec/runtime/ip_address_cidr.h | 141 +++++++++++++++++++++ .../doris/catalog/BuiltinScalarFunctions.java | 6 +- .../{IsIpv6String.java => IsIpAddressInRange.java} | 26 ++-- .../expressions/functions/scalar/IsIpv4String.java | 6 +- .../expressions/functions/scalar/IsIpv6String.java | 6 +- .../expressions/visitor/ScalarFunctionVisitor.java | 5 + gensrc/script/doris_builtins_functions.py | 11 +- .../test_is_ip_address_in_range_function.out | 27 ++++ .../suites/nereids_function_p0/ip_functions.groovy | 8 +- .../test_is_ip_address_in_range_function.groovy | 67 ++++++++++ .../test_is_ip_string_functions.groovy | 4 +- 13 files changed, 375 insertions(+), 47 deletions(-) diff --git a/be/src/vec/functions/function_ip.cpp b/be/src/vec/functions/function_ip.cpp index 9a58e97f629..fb0c346e6a6 100644 --- a/be/src/vec/functions/function_ip.cpp +++ b/be/src/vec/functions/function_ip.cpp @@ -18,13 +18,10 @@ #include "vec/functions/function_ip.h" namespace doris::vectorized { -struct NameFunctionIPv4NumToString { - static constexpr auto name = "ipv4_num_to_string"; -}; void register_function_ip(SimpleFunctionFactory& factory) { - factory.register_function<FunctionIPv4NumToString<0, NameFunctionIPv4NumToString>>(); - factory.register_alias(NameFunctionIPv4NumToString::name, "inet_ntoa"); + factory.register_function<FunctionIPv4NumToString>(); + factory.register_alias(FunctionIPv4NumToString::name, "inet_ntoa"); factory.register_function<FunctionIPv4StringToNum<IPStringToNumExceptionMode::Throw>>(); factory.register_function<FunctionIPv4StringToNum<IPStringToNumExceptionMode::Default>>(); factory.register_function<FunctionIPv4StringToNum<IPStringToNumExceptionMode::Null>>(); @@ -39,5 +36,6 @@ void register_function_ip(SimpleFunctionFactory& factory) { "inet6_aton"); factory.register_function<FunctionIsIPv4String>(); factory.register_function<FunctionIsIPv6String>(); + factory.register_function<FunctionIsIPAddressInRange>(); } } // 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 eb76e3f31e6..18c2033ff8d 100644 --- a/be/src/vec/functions/function_ip.h +++ b/be/src/vec/functions/function_ip.h @@ -32,12 +32,10 @@ #include "vec/functions/function.h" #include "vec/functions/function_helpers.h" #include "vec/functions/simple_function_factory.h" +#include "vec/runtime/ip_address_cidr.h" namespace doris::vectorized { -/** If mask_tail_octets > 0, the last specified number of octets will be filled with "xxx". - */ -template <size_t mask_tail_octets, typename Name> class FunctionIPv4NumToString : public IFunction { private: template <typename ArgType> @@ -66,8 +64,7 @@ private: offsets_res[i] = pos - begin; null_map->get_data()[i] = 1; } else { - formatIPv4(reinterpret_cast<const unsigned char*>(&vec_in[i]), src_size, pos, - mask_tail_octets, "xxx"); + formatIPv4(reinterpret_cast<const unsigned char*>(&vec_in[i]), src_size, pos); offsets_res[i] = pos - begin; } } @@ -83,9 +80,7 @@ private: public: static constexpr auto name = "ipv4_num_to_string"; - static FunctionPtr create() { - return std::make_shared<FunctionIPv4NumToString<mask_tail_octets, Name>>(); - } + static FunctionPtr create() { return std::make_shared<FunctionIPv4NumToString>(); } String get_name() const override { return name; } @@ -654,7 +649,7 @@ private: } public: - static constexpr auto name = "isipv4string"; + static constexpr auto name = "is_ipv4_string"; static FunctionPtr create() { return std::make_shared<FunctionIsIPv4String>(); } String get_name() const override { return name; } @@ -724,7 +719,7 @@ private: } public: - static constexpr auto name = "isipv6string"; + static constexpr auto name = "is_ipv6_string"; static FunctionPtr create() { return std::make_shared<FunctionIsIPv6String>(); } String get_name() const override { return name; } @@ -745,4 +740,96 @@ public: } }; +class FunctionIsIPAddressInRange : public IFunction { +public: + static constexpr auto name = "is_ip_address_in_range"; + static FunctionPtr create() { return std::make_shared<FunctionIsIPAddressInRange>(); } + + String get_name() const override { return name; } + + size_t get_number_of_arguments() const override { return 2; } + + DataTypePtr get_return_type_impl(const DataTypes& arguments) const override { + if (arguments.size() != 2) { + throw Exception( + ErrorCode::INVALID_ARGUMENT, + "Number of arguments for function {} doesn't match: passed {}, should be 2", + get_name(), arguments.size()); + } + const auto& addr_type = arguments[0]; + const auto& cidr_type = arguments[1]; + if (!is_string(remove_nullable(addr_type)) || !is_string(remove_nullable(cidr_type))) { + throw Exception(ErrorCode::INVALID_ARGUMENT, + "The arguments of function {} must be String", get_name()); + } + return std::make_shared<DataTypeUInt8>(); + } + + bool use_default_implementation_for_nulls() const override { return false; } + + Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments, + size_t result, size_t input_rows_count) const override { + ColumnPtr& addr_column = block.get_by_position(arguments[0]).column; + ColumnPtr& cidr_column = block.get_by_position(arguments[1]).column; + const ColumnString* str_addr_column = nullptr; + const ColumnString* str_cidr_column = nullptr; + const NullMap* nullmap_addr = nullptr; + const NullMap* nullmap_cidr = nullptr; + + if (addr_column->is_nullable()) { + const auto* addr_column_nullable = + assert_cast<const ColumnNullable*>(addr_column.get()); + str_addr_column = + check_and_get_column<ColumnString>(addr_column_nullable->get_nested_column()); + nullmap_addr = &addr_column_nullable->get_null_map_data(); + } else { + str_addr_column = check_and_get_column<ColumnString>(addr_column.get()); + } + + if (cidr_column->is_nullable()) { + const auto* cidr_column_nullable = + assert_cast<const ColumnNullable*>(cidr_column.get()); + str_cidr_column = + check_and_get_column<ColumnString>(cidr_column_nullable->get_nested_column()); + nullmap_cidr = &cidr_column_nullable->get_null_map_data(); + } else { + str_cidr_column = check_and_get_column<ColumnString>(cidr_column.get()); + } + + if (!str_addr_column) { + throw Exception(ErrorCode::INVALID_ARGUMENT, + "Illegal column {} of argument of function {}, expected String", + addr_column->get_name(), get_name()); + } + + if (!str_cidr_column) { + throw Exception(ErrorCode::INVALID_ARGUMENT, + "Illegal column {} of argument of function {}, expected String", + cidr_column->get_name(), get_name()); + } + + auto col_res = ColumnUInt8::create(input_rows_count, 0); + auto& col_res_data = col_res->get_data(); + + for (size_t i = 0; i < input_rows_count; ++i) { + if (nullmap_addr && (*nullmap_addr)[i]) { + throw Exception(ErrorCode::INVALID_ARGUMENT, + "The arguments of function {} must be String, not NULL", + get_name()); + } + if (nullmap_cidr && (*nullmap_cidr)[i]) { + throw Exception(ErrorCode::INVALID_ARGUMENT, + "The arguments of function {} must be String, not NULL", + get_name()); + } + const auto addr = IPAddressVariant(str_addr_column->get_data_at(i).to_string_view()); + const auto cidr = parse_ip_with_cidr(str_cidr_column->get_data_at(i).to_string_view()); + col_res_data[i] = is_address_in_range(addr, cidr) ? 1 : 0; + } + + block.replace_by_position(result, std::move(col_res)); + return Status::OK(); + } +}; + } // namespace doris::vectorized \ No newline at end of file diff --git a/be/src/vec/runtime/ip_address_cidr.h b/be/src/vec/runtime/ip_address_cidr.h new file mode 100644 index 00000000000..721722d5f8b --- /dev/null +++ b/be/src/vec/runtime/ip_address_cidr.h @@ -0,0 +1,141 @@ +// 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. +// This file is copied from +// https://github.com/ClickHouse/ClickHouse/blob/master/src/Functions/isIPAddressContainedIn.cpp +// and modified by Doris + +#pragma once + +#include "vec/common/format_ip.h" + +namespace doris { + +class IPAddressVariant { +public: + explicit IPAddressVariant(std::string_view address_str) { + vectorized::Int64 v4 = 0; + if (vectorized::parseIPv4whole(address_str.begin(), address_str.end(), + reinterpret_cast<unsigned char*>(&v4))) { + _addr = static_cast<vectorized::UInt32>(v4); + } else { + _addr = IPv6AddrType(); + if (!vectorized::parseIPv6whole(address_str.begin(), address_str.end(), + std::get<IPv6AddrType>(_addr).data())) { + throw Exception(ErrorCode::INVALID_ARGUMENT, "Neither IPv4 nor IPv6 address: '{}'", + address_str); + } + } + } + + vectorized::UInt32 as_v4() const { + if (const auto* val = std::get_if<IPv4AddrType>(&_addr)) { + return *val; + } + return 0; + } + + const vectorized::UInt8* as_v6() const { + if (const auto* val = std::get_if<IPv6AddrType>(&_addr)) { + return val->data(); + } + return nullptr; + } + +private: + using IPv4AddrType = vectorized::UInt32; + using IPv6AddrType = std::array<vectorized::UInt8, IPV6_BINARY_LENGTH>; + + std::variant<IPv4AddrType, IPv6AddrType> _addr; +}; + +struct IPAddressCIDR { + IPAddressVariant _address; + vectorized::UInt8 _prefix; +}; + +bool match_ipv4_subnet(uint32_t addr, uint32_t cidr_addr, uint8_t prefix) { + uint32_t mask = (prefix >= 32) ? 0xffffffffu : ~(0xffffffffu >> prefix); + return (addr & mask) == (cidr_addr & mask); +} + +bool match_ipv6_subnet(const uint8_t* addr, const uint8_t* cidr_addr, uint8_t prefix) { + if (prefix > IPV6_BINARY_LENGTH * 8U) { + prefix = IPV6_BINARY_LENGTH * 8U; + } + size_t i = 0; + + for (; prefix >= 8; ++i, prefix -= 8) { + if (addr[i] != cidr_addr[i]) { + return false; + } + } + + if (prefix == 0) { + return true; + } + + auto mask = ~(0xff >> prefix); + return (addr[i] & mask) == (cidr_addr[i] & mask); +} + +IPAddressCIDR parse_ip_with_cidr(std::string_view cidr_str) { + size_t pos_slash = cidr_str.find('/'); + + if (pos_slash == 0) { + throw Exception(ErrorCode::INVALID_ARGUMENT, "Error parsing IP address with prefix: {}", + std::string(cidr_str)); + } + + if (pos_slash == std::string_view::npos) { + throw Exception(ErrorCode::INVALID_ARGUMENT, "The text does not contain '/': {}", + std::string(cidr_str)); + } + + std::string_view addr_str = cidr_str.substr(0, pos_slash); + IPAddressVariant addr(addr_str); + + uint8_t prefix = 0; + auto prefix_str = cidr_str.substr(pos_slash + 1); + + const auto* prefix_str_end = prefix_str.data() + prefix_str.size(); + auto [parse_end, parse_error] = std::from_chars(prefix_str.data(), prefix_str_end, prefix); + uint8_t max_prefix = (addr.as_v6() ? IPV6_BINARY_LENGTH : IPV4_BINARY_LENGTH) * 8; + + if (parse_error != std::errc() || parse_end != prefix_str_end || prefix > max_prefix) { + throw Exception(ErrorCode::INVALID_ARGUMENT, "The CIDR has a malformed prefix bits: {}", + std::string(cidr_str)); + } + + return {addr, static_cast<uint8_t>(prefix)}; +} + +inline bool is_address_in_range(const IPAddressVariant& address, const IPAddressCIDR& cidr) { + const auto* cidr_v6 = cidr._address.as_v6(); + const auto* addr_v6 = address.as_v6(); + if (cidr_v6) { + if (addr_v6) { + return match_ipv6_subnet(addr_v6, cidr_v6, cidr._prefix); + } + } else { + if (!addr_v6) { + return match_ipv4_subnet(address.as_v4(), cidr._address.as_v4(), cidr._prefix); + } + } + return false; +} + +} // namespace doris \ No newline at end of file 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 185e3bdada3..9a499cd9f91 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,7 @@ 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.IsIpAddressInRange; 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; @@ -601,8 +602,9 @@ 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(IsIpv4String.class, "is_ipv4_string"), + scalar(IsIpv6String.class, "is_ipv6_string"), + scalar(IsIpAddressInRange.class, "is_ip_address_in_range"), 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/IsIpv6String.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/IsIpAddressInRange.java similarity index 75% copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/IsIpv6String.java copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/IsIpAddressInRange.java index 9963501840f..d15af4235b7 100644 --- 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/IsIpAddressInRange.java @@ -19,7 +19,7 @@ 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.AlwaysNotNullable; 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; @@ -33,26 +33,26 @@ import com.google.common.collect.ImmutableList; import java.util.List; /** - * scalar function IsIpv6String + * scalar function `is_ip_address_in_range` */ -public class IsIpv6String extends ScalarFunction - implements BinaryExpression, ExplicitlyCastableSignature, AlwaysNullable { +public class IsIpAddressInRange extends ScalarFunction + implements BinaryExpression, ExplicitlyCastableSignature, AlwaysNotNullable { public static final List<FunctionSignature> SIGNATURES = ImmutableList.of( - FunctionSignature.ret(BooleanType.INSTANCE).args(VarcharType.SYSTEM_DEFAULT), - FunctionSignature.ret(BooleanType.INSTANCE).args(StringType.INSTANCE)); + FunctionSignature.ret(BooleanType.INSTANCE).args(VarcharType.SYSTEM_DEFAULT, VarcharType.SYSTEM_DEFAULT), + FunctionSignature.ret(BooleanType.INSTANCE).args(StringType.INSTANCE, StringType.INSTANCE)); - public IsIpv6String(Expression arg0) { - super("isipv6string", arg0); + public IsIpAddressInRange(Expression arg0, Expression arg1) { + super("is_ip_address_in_range", arg0, arg1); } @Override - public IsIpv6String withChildren(List<Expression> children) { - Preconditions.checkArgument(children.size() == 1, - "isipv6string accept 1 args, but got %s (%s)", + public IsIpAddressInRange withChildren(List<Expression> children) { + Preconditions.checkArgument(children.size() == 2, + "is_ip_address_in_range accept 2 args, but got %s (%s)", children.size(), children); - return new IsIpv6String(children.get(0)); + return new IsIpAddressInRange(children.get(0), children.get(1)); } @Override @@ -62,6 +62,6 @@ public class IsIpv6String extends ScalarFunction @Override public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) { - return visitor.visitIsIpv6String(this, context); + return visitor.visitIsIPAddressInRange(this, context); } } 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 index 2216d749f21..b1ea28d7518 100644 --- 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 @@ -33,7 +33,7 @@ import com.google.common.collect.ImmutableList; import java.util.List; /** - * scalar function IsIpv4String + * scalar function is_ipv4_string */ public class IsIpv4String extends ScalarFunction implements BinaryExpression, ExplicitlyCastableSignature, AlwaysNullable { @@ -43,13 +43,13 @@ public class IsIpv4String extends ScalarFunction FunctionSignature.ret(BooleanType.INSTANCE).args(StringType.INSTANCE)); public IsIpv4String(Expression arg0) { - super("isipv4string", arg0); + super("is_ipv4_string", arg0); } @Override public IsIpv4String withChildren(List<Expression> children) { Preconditions.checkArgument(children.size() == 1, - "isipv4string accept 1 args, but got %s (%s)", + "is_ipv4_string accept 1 args, but got %s (%s)", children.size(), children); return new IsIpv4String(children.get(0)); 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 index 9963501840f..850e35cf3d8 100644 --- 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 @@ -33,7 +33,7 @@ import com.google.common.collect.ImmutableList; import java.util.List; /** - * scalar function IsIpv6String + * scalar function is_ipv6_string */ public class IsIpv6String extends ScalarFunction implements BinaryExpression, ExplicitlyCastableSignature, AlwaysNullable { @@ -43,13 +43,13 @@ public class IsIpv6String extends ScalarFunction FunctionSignature.ret(BooleanType.INSTANCE).args(StringType.INSTANCE)); public IsIpv6String(Expression arg0) { - super("isipv6string", arg0); + super("is_ipv6_string", arg0); } @Override public IsIpv6String withChildren(List<Expression> children) { Preconditions.checkArgument(children.size() == 1, - "isipv6string accept 1 args, but got %s (%s)", + "is_ipv6_string accept 1 args, but got %s (%s)", children.size(), children); return new IsIpv6String(children.get(0)); 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 73756dd2c6d..4a9dc84bec4 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,7 @@ 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.IsIpAddressInRange; 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; @@ -1146,6 +1147,10 @@ public interface ScalarFunctionVisitor<R, C> { return visitScalarFunction(isIpv6String, context); } + default R visitIsIPAddressInRange(IsIpAddressInRange isIpAddressInRange, C context) { + return visitScalarFunction(isIpAddressInRange, 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 b3f5a7b58bc..cbf5e626412 100644 --- a/gensrc/script/doris_builtins_functions.py +++ b/gensrc/script/doris_builtins_functions.py @@ -2012,11 +2012,12 @@ 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'], + [['is_ipv4_string'], 'BOOLEAN', ['VARCHAR'], 'ALWAYS_NULLABLE'], + [['is_ipv4_string'], 'BOOLEAN', ['STRING'], 'ALWAYS_NULLABLE'], + [['is_ipv6_string'], 'BOOLEAN', ['VARCHAR'], 'ALWAYS_NULLABLE'], + [['is_ipv6_string'], 'BOOLEAN', ['STRING'], 'ALWAYS_NULLABLE'], + [['is_ip_address_in_range'], 'BOOLEAN', ['VARCHAR', 'VARCHAR'], 'ALWAYS_NOT_NULLABLE'], + [['is_ip_address_in_range'], 'BOOLEAN', ['STRING', 'STRING'], 'ALWAYS_NOT_NULLABLE'], ], "NonNullalbe": [ diff --git a/regression-test/data/query_p0/sql_functions/ip_functions/test_is_ip_address_in_range_function.out b/regression-test/data/query_p0/sql_functions/ip_functions/test_is_ip_address_in_range_function.out new file mode 100644 index 00000000000..c21ca672a38 --- /dev/null +++ b/regression-test/data/query_p0/sql_functions/ip_functions/test_is_ip_address_in_range_function.out @@ -0,0 +1,27 @@ +-- !sql -- +1 true +2 false +3 true +4 false +5 false +6 true +7 true +8 false +9 false +10 true +11 true +12 false +13 true +14 true +15 false +16 true +17 true +18 false +19 true +20 false +21 true +22 false +23 false +24 false +25 false +26 false diff --git a/regression-test/suites/nereids_function_p0/ip_functions.groovy b/regression-test/suites/nereids_function_p0/ip_functions.groovy index dc6e3de7d68..1ac00102094 100644 --- a/regression-test/suites/nereids_function_p0/ip_functions.groovy +++ b/regression-test/suites/nereids_function_p0/ip_functions.groovy @@ -73,8 +73,8 @@ suite("ip_functions") { 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');" + qt_ip52 "SELECT is_ipv4_string('255.255.255.255');" + qt_ip53 "SELECT is_ipv4_string('255.255.255.256');" + qt_ip54 "SELECT is_ipv6_string('2001:5b0:23ff:fffa::113');" + qt_ip55 "SELECT is_ipv6_string('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_address_in_range_function.groovy b/regression-test/suites/query_p0/sql_functions/ip_functions/test_is_ip_address_in_range_function.groovy new file mode 100644 index 00000000000..d1283bd8391 --- /dev/null +++ b/regression-test/suites/query_p0/sql_functions/ip_functions/test_is_ip_address_in_range_function.groovy @@ -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. + +suite("test_is_ip_address_in_range_function") { + sql """ DROP TABLE IF EXISTS test_is_ip_address_in_range_function """ + + sql """ SET enable_nereids_planner=true """ + sql """ SET enable_fallback_to_original_planner=false """ + + sql """ + CREATE TABLE test_is_ip_address_in_range_function ( + `id` int, + `addr` string, + `cidr` string + ) ENGINE=OLAP + UNIQUE KEY (`id`) + DISTRIBUTED BY HASH(`id`) BUCKETS 4 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1" + ); + """ + + sql "insert into test_is_ip_address_in_range_function values(1, '127.0.0.1', '127.0.0.0/8')" + sql "insert into test_is_ip_address_in_range_function values(2, '128.0.0.1', '127.0.0.0/8')" + sql "insert into test_is_ip_address_in_range_function values(3, 'ffff::1', 'ffff::/16')" + sql "insert into test_is_ip_address_in_range_function values(4, 'fffe::1', 'ffff::/16')" + sql "insert into test_is_ip_address_in_range_function values(5, '192.168.99.255', '192.168.100.0/22')" + sql "insert into test_is_ip_address_in_range_function values(6, '192.168.100.1', '192.168.100.0/22')" + sql "insert into test_is_ip_address_in_range_function values(7, '192.168.103.255', '192.168.100.0/22')" + sql "insert into test_is_ip_address_in_range_function values(8, '192.168.104.0', '192.168.100.0/22')" + sql "insert into test_is_ip_address_in_range_function values(9, '::192.168.99.255', '::192.168.100.0/118')" + sql "insert into test_is_ip_address_in_range_function values(10, '::192.168.100.1', '::192.168.100.0/118')" + sql "insert into test_is_ip_address_in_range_function values(11, '::192.168.103.255', '::192.168.100.0/118')" + sql "insert into test_is_ip_address_in_range_function values(12, '::192.168.104.0', '::192.168.100.0/118')" + sql "insert into test_is_ip_address_in_range_function values(13, '192.168.100.1', '192.168.100.0/22')" + sql "insert into test_is_ip_address_in_range_function values(14, '192.168.100.1', '192.168.100.0/24')" + sql "insert into test_is_ip_address_in_range_function values(15, '192.168.100.1', '192.168.100.0/32')" + sql "insert into test_is_ip_address_in_range_function values(16, '::192.168.100.1', '::192.168.100.0/118')" + sql "insert into test_is_ip_address_in_range_function values(17, '::192.168.100.1', '::192.168.100.0/120')" + sql "insert into test_is_ip_address_in_range_function values(18, '::192.168.100.1', '::192.168.100.0/128')" + sql "insert into test_is_ip_address_in_range_function values(19, '192.168.100.1', '192.168.100.0/22')" + sql "insert into test_is_ip_address_in_range_function values(20, '192.168.103.255', '192.168.100.0/24')" + sql "insert into test_is_ip_address_in_range_function values(21, '::192.168.100.1', '::192.168.100.0/118')" + sql "insert into test_is_ip_address_in_range_function values(22, '::192.168.103.255', '::192.168.100.0/120')" + sql "insert into test_is_ip_address_in_range_function values(23, '127.0.0.1', 'ffff::/16')" + sql "insert into test_is_ip_address_in_range_function values(24, '127.0.0.1', '::127.0.0.1/128')" + sql "insert into test_is_ip_address_in_range_function values(25, '::1', '127.0.0.0/8')" + sql "insert into test_is_ip_address_in_range_function values(26, '::127.0.0.1', '127.0.0.1/32')" + + qt_sql "select id, is_ip_address_in_range(addr, cidr) from test_is_ip_address_in_range_function order by id" + + sql """ DROP TABLE IF EXISTS test_is_ip_address_in_range_function """ +} \ 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 index 70740dd4798..08764730793 100644 --- 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 @@ -37,8 +37,8 @@ suite("test_is_ip_string_functions") { 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" + qt_sql1 "select is_ipv4_string(ip_v4) from test_is_ip_string order by id" + qt_sql2 "select is_ipv6_string(ip_v6) from test_is_ip_string order by id" sql "DROP TABLE test_is_ip_string" } \ No newline at end of file --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org