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 d6ed4149f5b [feature](function) support ip function is_ipv4_compat, is_ipv4_mapped (#29954) d6ed4149f5b is described below commit d6ed4149f5b2b15e97a5a8861387141749c0339e Author: Chester <42577861+superdiaod...@users.noreply.github.com> AuthorDate: Sun Jan 21 10:51:58 2024 +0800 [feature](function) support ip function is_ipv4_compat, is_ipv4_mapped (#29954) --- be/src/vec/common/unaligned.h | 33 +++++- be/src/vec/functions/function_ip.cpp | 4 + be/src/vec/functions/function_ip.h | 130 ++++++++++++++------- .../sql-functions/ip-functions/is-ipv4-compat.md | 65 +++++++++++ .../sql-functions/ip-functions/is-ipv4-mapped.md | 69 +++++++++++ docs/sidebars.json | 7 +- .../sql-functions/ip-functions/is-ipv4-compat.md | 65 +++++++++++ .../sql-functions/ip-functions/is-ipv4-mapped.md | 68 +++++++++++ .../doris/catalog/BuiltinScalarFunctions.java | 4 + .../expressions/functions/scalar/IsIpv4Compat.java | 67 +++++++++++ .../expressions/functions/scalar/IsIpv4Mapped.java | 67 +++++++++++ .../expressions/visitor/ScalarFunctionVisitor.java | 10 ++ gensrc/script/doris_builtins_functions.py | 4 + .../data/nereids_function_p0/ip_functions.out | 32 ++++- .../ip_functions/test_ip_functions.out | 32 ++++- .../suites/nereids_function_p0/ip_functions.groovy | 12 ++ .../ip_functions/test_ip_functions.groovy | 12 ++ 17 files changed, 635 insertions(+), 46 deletions(-) diff --git a/be/src/vec/common/unaligned.h b/be/src/vec/common/unaligned.h index d56eca59b23..ee807c606e5 100644 --- a/be/src/vec/common/unaligned.h +++ b/be/src/vec/common/unaligned.h @@ -20,8 +20,9 @@ #pragma once -#include <string.h> - +#include <bit> +#include <cstdint> +#include <cstring> #include <type_traits> template <typename T> @@ -40,3 +41,31 @@ void unaligned_store(void* address, const typename std::enable_if<true, T>::type static_assert(std::is_trivially_copyable_v<T>); memcpy(address, &src, sizeof(src)); } + +inline void reverse_memcpy(void* dst, const void* src, size_t size) { + uint8_t* uint_dst = reinterpret_cast<uint8_t*>(dst) + size; // Perform addition here + const uint8_t* uint_src = reinterpret_cast<const uint8_t*>(src); + + while (size) { + --uint_dst; + *uint_dst = *uint_src; + ++uint_src; + --size; + } +} + +template <std::endian endian, typename T> +inline T unaligned_load_endian(const void* address) { + T res {}; + if constexpr (std::endian::native == endian) { + memcpy(&res, address, sizeof(res)); + } else { + reverse_memcpy(&res, address, sizeof(res)); + } + return res; +} + +template <typename T> +inline T unaligned_load_little_endian(const void* address) { + return unaligned_load_endian<std::endian::little, T>(address); +} \ No newline at end of file diff --git a/be/src/vec/functions/function_ip.cpp b/be/src/vec/functions/function_ip.cpp index 3faa6a42d8c..140100d22b3 100644 --- a/be/src/vec/functions/function_ip.cpp +++ b/be/src/vec/functions/function_ip.cpp @@ -27,6 +27,7 @@ void register_function_ip(SimpleFunctionFactory& factory) { factory.register_function<FunctionIPv4StringToNum<IPStringToNumExceptionMode::Null>>(); factory.register_alias(FunctionIPv4StringToNum<IPStringToNumExceptionMode::Throw>::name, "inet_aton"); + factory.register_function<FunctionIPv6NumToString>(); factory.register_alias(FunctionIPv6NumToString::name, "inet6_ntoa"); factory.register_function<FunctionIPv6StringToNum<IPStringToNumExceptionMode::Throw>>(); @@ -34,6 +35,9 @@ void register_function_ip(SimpleFunctionFactory& factory) { factory.register_function<FunctionIPv6StringToNum<IPStringToNumExceptionMode::Null>>(); factory.register_alias(FunctionIPv6StringToNum<IPStringToNumExceptionMode::Throw>::name, "inet6_aton"); + + factory.register_function<FunctionIsIPv4Compat>(); + factory.register_function<FunctionIsIPv4Mapped>(); factory.register_function<FunctionIsIPString<IPv4>>(); factory.register_function<FunctionIsIPString<IPv6>>(); factory.register_function<FunctionIsIPAddressInRange>(); diff --git a/be/src/vec/functions/function_ip.h b/be/src/vec/functions/function_ip.h index 313ad0fdd65..8a260b8fd82 100644 --- a/be/src/vec/functions/function_ip.h +++ b/be/src/vec/functions/function_ip.h @@ -364,44 +364,6 @@ ColumnPtr convertToIPv6(const StringColumnType& string_column, vec_null_map_to = &col_null_map_to->get_data(); } - /// This is a special treatment for source column of type String - /// to preserve previous behavior when IPv6 was a domain type of String - if constexpr (std::is_same_v<StringColumnType, ColumnString>) { - if (string_column.get_offsets()[0] - 1 == IPV6_BINARY_LENGTH) { - if constexpr (std::is_same_v<ToColumn, ColumnString>) { - auto col_res = ColumnString::create(); - - if constexpr (exception_mode == IPStringToNumExceptionMode::Null) { - col_null_map_to = ColumnUInt8::create(column_size, false); - if (null_map) { - memcpy(col_null_map_to->get_data().data(), null_map->data(), column_size); - } - - return ColumnNullable::create(std::move(col_res), std::move(col_null_map_to)); - } - - return col_res; - } else { - auto col_res = ColumnIPv6::create(); - auto& vec_res = col_res->get_data(); - - vec_res.resize(column_size); - memcpy(vec_res.data(), string_column.get_chars().data(), - column_size * IPV6_BINARY_LENGTH); - - if constexpr (exception_mode == IPStringToNumExceptionMode::Null) { - col_null_map_to = ColumnUInt8::create(column_size, false); - if (null_map) { - memcpy(col_null_map_to->get_data().data(), null_map->data(), column_size); - } - return ColumnNullable::create(std::move(col_res), std::move(col_null_map_to)); - } - - return col_res; - } - } - } - auto column_create = [](size_t column_size) -> typename ToColumn::MutablePtr { if constexpr (std::is_same_v<ToColumn, ColumnString>) { auto column_string = ColumnString::create(); @@ -833,4 +795,94 @@ private: } }; -} // namespace doris::vectorized \ No newline at end of file +class FunctionIsIPv4Compat : public IFunction { +public: + static constexpr auto name = "is_ipv4_compat"; + static FunctionPtr create() { return std::make_shared<FunctionIsIPv4Compat>(); } + + 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 std::make_shared<DataTypeUInt8>(); + } + + Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments, + size_t result, size_t input_rows_count) const override { + const ColumnPtr& column = block.get_by_position(arguments[0]).column; + const auto* col_in = check_and_get_column<ColumnString>(column.get()); + + if (!col_in) + throw Exception(ErrorCode::INVALID_ARGUMENT, + "Illegal column {} of argument of function {}, expected String", + column->get_name(), get_name()); + size_t col_size = col_in->size(); + auto col_res = ColumnUInt8::create(col_size, 0); + auto& col_res_data = col_res->get_data(); + + for (size_t i = 0; i < col_size; ++i) { + auto ipv4_in = col_in->get_data_at(i); + if (is_ipv4_compat(reinterpret_cast<const UInt8*>(ipv4_in.data))) { + col_res_data[i] = 1; + } + } + + block.replace_by_position(result, std::move(col_res)); + return Status::OK(); + } + +private: + static bool is_ipv4_compat(const UInt8* address) { + return (unaligned_load_little_endian<UInt64>(address) == 0) && + (unaligned_load_little_endian<UInt32>(address + 8) == 0) && + (unaligned_load_little_endian<UInt32>(address + 12) != 0); + } +}; + +class FunctionIsIPv4Mapped : public IFunction { +public: + static constexpr auto name = "is_ipv4_mapped"; + static FunctionPtr create() { return std::make_shared<FunctionIsIPv4Mapped>(); } + + 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 std::make_shared<DataTypeUInt8>(); + } + + Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments, + size_t result, size_t input_rows_count) const override { + const ColumnPtr& column = block.get_by_position(arguments[0]).column; + const auto* col_in = check_and_get_column<ColumnString>(column.get()); + + if (!col_in) + throw Exception(ErrorCode::INVALID_ARGUMENT, + "Illegal column {} of argument of function {}, expected String", + column->get_name(), get_name()); + size_t col_size = col_in->size(); + auto col_res = ColumnUInt8::create(col_size, 0); + auto& col_res_data = col_res->get_data(); + + for (size_t i = 0; i < col_size; ++i) { + auto ipv4_in = col_in->get_data_at(i); + if (is_ipv4_mapped(reinterpret_cast<const UInt8*>(ipv4_in.data))) { + col_res_data[i] = 1; + } + } + + block.replace_by_position(result, std::move(col_res)); + return Status::OK(); + } + +private: + static bool is_ipv4_mapped(const UInt8* address) { + return (unaligned_load_little_endian<UInt64>(address) == 0) && + ((unaligned_load_little_endian<UInt64>(address + 8) & 0x00000000FFFFFFFFULL) == + 0x00000000FFFF0000ULL); + } +}; + +} // namespace doris::vectorized diff --git a/docs/en/docs/sql-manual/sql-functions/ip-functions/is-ipv4-compat.md b/docs/en/docs/sql-manual/sql-functions/ip-functions/is-ipv4-compat.md new file mode 100644 index 00000000000..84c5aff9b63 --- /dev/null +++ b/docs/en/docs/sql-manual/sql-functions/ip-functions/is-ipv4-compat.md @@ -0,0 +1,65 @@ +--- +{ +"title": "IS_IPV4_COMPAT", +"language": "en" +} +--- + +<!-- +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. +--> + +## IS_IPV4_COMPAT + +<version since="dev"> + +IS_IPV4_COMPAT + +</version> + +### description + +#### Syntax + +`VARCHAR IS_IPV4_COMPAT(INET6_ATON(VARCHAR ipv4_addr))` + +This function takes an IPv6 address represented in numeric form as a binary string, as returned by INET6_ATON(). +It returns 1 if the argument is a valid IPv4-compatible IPv6 address, 0 otherwise (unless expr is NULL, in which case the function returns NULL). +IPv4-compatible addresses have the form ::ipv4_address. + +### example + +``` +mysql> SELECT IS_IPV4_COMPAT(INET6_ATON('::ffff:10.0.5.9')) AS is_result; ++-----------+ +| is_result | ++-----------+ +| 0 | ++-----------+ +1 row in set (0.02 sec) + +mysql> SELECT IS_IPV4_COMPAT(INET6_ATON('::10.0.5.9')) AS is_result; ++-----------+ +| is_result | ++-----------+ +| 1 | ++-----------+ +1 row in set (0.03 sec) +``` + +### keywords + +IS_IPV4_COMPAT, IP \ No newline at end of file diff --git a/docs/en/docs/sql-manual/sql-functions/ip-functions/is-ipv4-mapped.md b/docs/en/docs/sql-manual/sql-functions/ip-functions/is-ipv4-mapped.md new file mode 100644 index 00000000000..9e338eb1353 --- /dev/null +++ b/docs/en/docs/sql-manual/sql-functions/ip-functions/is-ipv4-mapped.md @@ -0,0 +1,69 @@ +--- +{ +"title": "IS_IPV4_MAPPED", +"language": "en" +} +--- + +<!-- +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. +--> + +## IS_IPV4_MAPPED + +<version since="dev"> + +IS_IPV4_MAPPED + +</version> + +### description + +#### Syntax + +`VARCHAR IS_IPV4_MAPPED(INET6_ATON(VARCHAR ipv4_addr))` + +This function takes an IPv6 address represented in numeric form as a binary string, as returned by INET6_ATON(). +It returns 1 if the argument is a valid IPv4-mapped IPv6 address, 0 otherwise, unless expr is NULL, in which case the function returns NULL. +IPv4-mapped addresses have the form ::ffff:ipv4_address. + +### notice + +`When the source input doesn't have a prefix of '::ffff:', but if it's still a valid ipv4 address, this result will also be 1 for the reason that the INET6_ATON() automatically adds the prefix for it.` + +### example + +``` +mysql> SELECT IS_IPV4_MAPPED(INET6_ATON('::ffff:10.0.5.9')) AS is_result; ++-----------+ +| is_result | ++-----------+ +| 1 | ++-----------+ +1 row in set (0.02 sec) + +mysql> SELECT IS_IPV4_MAPPED(INET6_ATON('::10.0.5.9')) AS is_result; ++-----------+ +| is_result | ++-----------+ +| 0 | ++-----------+ +1 row in set (0.03 sec) +``` + +### keywords + +IS_IPV4_MAPPED, IP \ No newline at end of file diff --git a/docs/sidebars.json b/docs/sidebars.json index 6b94989d180..bda6b8da310 100644 --- a/docs/sidebars.json +++ b/docs/sidebars.json @@ -811,11 +811,12 @@ "sql-manual/sql-functions/ip-functions/ipv4-string-to-num-or-null", "sql-manual/sql-functions/ip-functions/ipv6-num-to-string", "sql-manual/sql-functions/ip-functions/inet6-ntoa", - "sql-manual/sql-functions/ip-functions/ipv6-num-to-string", + "sql-manual/sql-functions/ip-functions/ipv6-string-to-num", "sql-manual/sql-functions/ip-functions/inet6-aton", "sql-manual/sql-functions/ip-functions/ipv6-string-to-num-or-default", - "sql-manual/sql-functions/ip-functions/ipv6-string-to-num-or-null" - + "sql-manual/sql-functions/ip-functions/ipv6-string-to-num-or-null", + "sql-manual/sql-functions/ip-functions/is-ipv4-compat", + "sql-manual/sql-functions/ip-functions/is-ipv4-mapped" ] }, { diff --git a/docs/zh-CN/docs/sql-manual/sql-functions/ip-functions/is-ipv4-compat.md b/docs/zh-CN/docs/sql-manual/sql-functions/ip-functions/is-ipv4-compat.md new file mode 100644 index 00000000000..fba93b83430 --- /dev/null +++ b/docs/zh-CN/docs/sql-manual/sql-functions/ip-functions/is-ipv4-compat.md @@ -0,0 +1,65 @@ +--- +{ +"title": "IS_IPV4_COMPAT", +"language": "zh-CN" +} +--- + +<!-- +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. +--> + +## IS_IPV4_COMPAT + +<version since="dev"> + +IS_IPV4_COMPAT + +</version> + +### description + +#### Syntax + +`VARCHAR IS_IPV4_COMPAT(INET6_ATON(VARCHAR ipv4_addr))` + +该函数采用以数字形式表示的二进制字符串形式的 IPv6 地址,由 INET6_ATON() 返回。 +如果参数是有效的 IPv4 兼容 IPv6 地址,则返回 1,否则返回 0(除非 expr 为 NULL,在这种情况下该函数返回 NULL)。 +IPv4 兼容地址的格式为::ipv4_address。 + +### example + +``` +mysql> SELECT IS_IPV4_COMPAT(INET6_ATON('::ffff:10.0.5.9')) AS is_result; ++-----------+ +| is_result | ++-----------+ +| 0 | ++-----------+ +1 row in set (0.02 sec) + +mysql> SELECT IS_IPV4_COMPAT(INET6_ATON('::10.0.5.9')) AS is_result; ++-----------+ +| is_result | ++-----------+ +| 1 | ++-----------+ +1 row in set (0.03 sec) +``` + +### keywords + +IS_IPV4_COMPAT, IP \ No newline at end of file diff --git a/docs/zh-CN/docs/sql-manual/sql-functions/ip-functions/is-ipv4-mapped.md b/docs/zh-CN/docs/sql-manual/sql-functions/ip-functions/is-ipv4-mapped.md new file mode 100644 index 00000000000..66de4022209 --- /dev/null +++ b/docs/zh-CN/docs/sql-manual/sql-functions/ip-functions/is-ipv4-mapped.md @@ -0,0 +1,68 @@ +--- +{ +"title": "IS_IPV4_MAPPED", +"language": "zh-CN" +} +--- + +<!-- +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. +--> + +## IS_IPV4_MAPPED + +<version since="dev"> + +IS_IPV4_MAPPED + +</version> + +### description + +#### Syntax + +`VARCHAR IS_IPV4_MAPPED(INET6_ATON(VARCHAR ipv4_addr))` + +该函数采用以数字形式表示的二进制字符串形式的lPv6地址,由INET6_ATON返回。 +如果参数是有效的IPv4映射IPv6地址,则返回1,否则返回0,除非expr为 NULL,在这种情况下该函数返回NULL。 +IPv4映射地址的格式为::ffff:ipv4_address + +### notice +`当源输入没有'::ffff:'前缀时,但如果它仍然是有效的ipv4地址,则该结果也将为1,因为INET6_ATON()会自动为有效的ipv4地址添加前缀。` + +### example + +``` +mysql> SELECT IS_IPV4_MAPPED(INET6_ATON('::ffff:10.0.5.9')) AS is_result; ++-----------+ +| is_result | ++-----------+ +| 1 | ++-----------+ +1 row in set (0.02 sec) + +mysql> SELECT IS_IPV4_MAPPED(INET6_ATON('::10.0.5.9')) AS is_result; ++-----------+ +| is_result | ++-----------+ +| 0 | ++-----------+ +1 row in set (0.03 sec) +``` + +### keywords + +IS_IPV4_MAPPED, IP \ 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 f4f7af5cf38..68da4df08ab 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 @@ -203,6 +203,8 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.Ipv6StringToN 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.IsIpv4Compat; +import org.apache.doris.nereids.trees.expressions.functions.scalar.IsIpv4Mapped; 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; @@ -609,6 +611,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(IsIpv4Compat.class, "is_ipv4_compat"), + scalar(IsIpv4Mapped.class, "is_ipv4_mapped"), scalar(IsIpv4String.class, "is_ipv4_string"), scalar(IsIpv6String.class, "is_ipv6_string"), scalar(IsIpAddressInRange.class, "is_ip_address_in_range"), diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/IsIpv4Compat.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/IsIpv4Compat.java new file mode 100644 index 00000000000..684eee0e9c9 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/IsIpv4Compat.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.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.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 is_ipv4_compat + */ +public class IsIpv4Compat extends ScalarFunction + implements BinaryExpression, ExplicitlyCastableSignature, PropagateNullable { + + public static final List<FunctionSignature> SIGNATURES = ImmutableList.of( + FunctionSignature.ret(BooleanType.INSTANCE).args(VarcharType.SYSTEM_DEFAULT), + FunctionSignature.ret(BooleanType.INSTANCE).args(StringType.INSTANCE)); + + public IsIpv4Compat(Expression arg0) { + super("is_ipv4_compat", arg0); + } + + @Override + public IsIpv4Compat withChildren(List<Expression> children) { + Preconditions.checkArgument(children.size() == 1, + "is_ipv4_compat accept 1 args, but got %s (%s)", + children.size(), + children); + return new IsIpv4Compat(children.get(0)); + } + + @Override + public List<FunctionSignature> getSignatures() { + return SIGNATURES; + } + + @Override + public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) { + return visitor.visitIsIpv4Compat(this, context); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/IsIpv4Mapped.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/IsIpv4Mapped.java new file mode 100644 index 00000000000..c3640af5437 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/IsIpv4Mapped.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.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.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 is_ipv4_mapped + */ +public class IsIpv4Mapped extends ScalarFunction + implements BinaryExpression, ExplicitlyCastableSignature, PropagateNullable { + + public static final List<FunctionSignature> SIGNATURES = ImmutableList.of( + FunctionSignature.ret(BooleanType.INSTANCE).args(VarcharType.SYSTEM_DEFAULT), + FunctionSignature.ret(BooleanType.INSTANCE).args(StringType.INSTANCE)); + + public IsIpv4Mapped(Expression arg0) { + super("is_ipv4_mapped", arg0); + } + + @Override + public IsIpv4Mapped withChildren(List<Expression> children) { + Preconditions.checkArgument(children.size() == 1, + "is_ipv4_mapped accept 1 args, but got %s (%s)", + children.size(), + children); + return new IsIpv4Mapped(children.get(0)); + } + + @Override + public List<FunctionSignature> getSignatures() { + return SIGNATURES; + } + + @Override + public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) { + return visitor.visitIsIpv4Mapped(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 899a31abbd7..01823f78199 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 @@ -199,6 +199,8 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.Ipv6StringToN 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.IsIpv4Compat; +import org.apache.doris.nereids.trees.expressions.functions.scalar.IsIpv4Mapped; 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; @@ -1155,6 +1157,14 @@ public interface ScalarFunctionVisitor<R, C> { return visitScalarFunction(ipv6StringToNumOrNull, context); } + default R visitIsIpv4Compat(IsIpv4Compat isIpv4Compat, C context) { + return visitScalarFunction(isIpv4Compat, context); + } + + default R visitIsIpv4Mapped(IsIpv4Mapped isIpv4Mapped, C context) { + return visitScalarFunction(isIpv4Mapped, context); + } + default R visitIsIpv4String(IsIpv4String isIpv4String, C context) { return visitScalarFunction(isIpv4String, context); } diff --git a/gensrc/script/doris_builtins_functions.py b/gensrc/script/doris_builtins_functions.py index 973a4675621..6a6ff96e83d 100644 --- a/gensrc/script/doris_builtins_functions.py +++ b/gensrc/script/doris_builtins_functions.py @@ -2014,6 +2014,10 @@ 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'], + [['is_ipv4_compat'], 'BOOLEAN', ['VARCHAR'], ''], + [['is_ipv4_compat'], 'BOOLEAN', ['STRING'], ''], + [['is_ipv4_mapped'], 'BOOLEAN', ['VARCHAR'], ''], + [['is_ipv4_mapped'], 'BOOLEAN', ['STRING'], ''], [['is_ipv4_string'], 'BOOLEAN', ['VARCHAR'], ''], [['is_ipv4_string'], 'BOOLEAN', ['STRING'], ''], [['is_ipv6_string'], 'BOOLEAN', ['VARCHAR'], ''], diff --git a/regression-test/data/nereids_function_p0/ip_functions.out b/regression-test/data/nereids_function_p0/ip_functions.out index 2e3b749a152..914b5ccd683 100644 --- a/regression-test/data/nereids_function_p0/ip_functions.out +++ b/regression-test/data/nereids_function_p0/ip_functions.out @@ -162,4 +162,34 @@ false true -- !ip55 -- -false \ No newline at end of file +false + +-- !ip56 -- +true + +-- !ip57 -- +false + +-- !ip58 -- +false + +-- !ip59 -- +true + +-- !ip60 -- +false + +-- !ip61 -- +true + +-- !ip62 -- +false + +-- !ip63 -- +true + +-- !ip64 -- +false + +-- !ip65 -- +true \ No newline at end of file diff --git a/regression-test/data/query_p0/sql_functions/ip_functions/test_ip_functions.out b/regression-test/data/query_p0/sql_functions/ip_functions/test_ip_functions.out index 71f02449d3b..1837acc4bab 100644 --- a/regression-test/data/query_p0/sql_functions/ip_functions/test_ip_functions.out +++ b/regression-test/data/query_p0/sql_functions/ip_functions/test_ip_functions.out @@ -137,4 +137,34 @@ AAAAAAAAFFFFFFFFFFFFFFFFAAAAAAAA 00000000000000000000FFFFC0A80001 -- !sql -- -2A0206B8000000000000000000000011 \ No newline at end of file +2A0206B8000000000000000000000011 + +-- !sql -- +true + +-- !sql -- +false + +-- !sql -- +false + +-- !sql -- +true + +-- !sql -- +false + +-- !sql -- +true + +-- !sql -- +false + +-- !sql -- +true + +-- !sql -- +false + +-- !sql -- +true \ No newline at end of file diff --git a/regression-test/suites/nereids_function_p0/ip_functions.groovy b/regression-test/suites/nereids_function_p0/ip_functions.groovy index 1ac00102094..b5d4d177e89 100644 --- a/regression-test/suites/nereids_function_p0/ip_functions.groovy +++ b/regression-test/suites/nereids_function_p0/ip_functions.groovy @@ -77,4 +77,16 @@ suite("ip_functions") { 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');" + + qt_ip56 "SELECT is_ipv4_compat(inet6_aton('::10.0.5.9'));" + qt_ip57 "SELECT is_ipv4_compat(inet6_aton('::ffff:10.0.5.9'));" + qt_ip58 "SELECT is_ipv4_compat(inet6_aton('::'));" + qt_ip59 "SELECT is_ipv4_compat(inet6_aton('::c0a8:0001'));" + qt_ip60 "SELECT is_ipv4_compat(inet6_aton('::0.0.0.0'));" + qt_ip61 "SELECT is_ipv4_compat(inet6_aton('::255.255.255.255'));" + + qt_ip62 "SELECT is_ipv4_mapped(inet6_aton('::10.0.5.9'));" + qt_ip63 "SELECT is_ipv4_mapped(inet6_aton('::ffff:10.0.5.9'));" + qt_ip64 "SELECT is_ipv4_mapped(inet6_aton('::'));" + qt_ip65 "SELECT is_ipv4_mapped(inet6_aton('::ffff:c0a8:0001'));" } \ No newline at end of file diff --git a/regression-test/suites/query_p0/sql_functions/ip_functions/test_ip_functions.groovy b/regression-test/suites/query_p0/sql_functions/ip_functions/test_ip_functions.groovy index 828de6cbe41..c5ff6d36a13 100644 --- a/regression-test/suites/query_p0/sql_functions/ip_functions/test_ip_functions.groovy +++ b/regression-test/suites/query_p0/sql_functions/ip_functions/test_ip_functions.groovy @@ -67,4 +67,16 @@ suite("test_ip_functions", "arrow_flight_sql") { qt_sql "SELECT hex(ipv6_string_to_num_or_null('aaaa:aaaa:ffff:ffff:ffff:ffff:aaaa:aaaa'));" qt_sql "SELECT hex(inet6_aton('192.168.0.1'));" qt_sql "SELECT hex(inet6_aton('2a02:6b8::11'));" + + qt_sql "SELECT is_ipv4_compat(inet6_aton('::10.0.5.9'));" + qt_sql "SELECT is_ipv4_compat(inet6_aton('::ffff:10.0.5.9'));" + qt_sql "SELECT is_ipv4_compat(inet6_aton('::'));" + qt_sql "SELECT is_ipv4_compat(inet6_aton('::c0a8:0001'));" + qt_sql "SELECT is_ipv4_compat(inet6_aton('::0.0.0.0'));" + qt_sql "SELECT is_ipv4_compat(inet6_aton('::255.255.255.255'));" + + qt_sql "SELECT is_ipv4_mapped(inet6_aton('::10.0.5.9'));" + qt_sql "SELECT is_ipv4_mapped(inet6_aton('::ffff:10.0.5.9'));" + qt_sql "SELECT is_ipv4_mapped(inet6_aton('::'));" + qt_sql "SELECT is_ipv4_mapped(inet6_aton('::ffff:c0a8:0001'));" } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org