diff --git a/be/src/vec/common/format_ip.cpp b/be/src/vec/common/format_ip.cpp index 1ad0e6899b..b673d5575d 100644 --- a/be/src/vec/common/format_ip.cpp +++ b/be/src/vec/common/format_ip.cpp @@ -23,6 +23,7 @@ #include #include +#include "vec/common/hex.h" #include "vec/core/types.h" namespace doris::vectorized { @@ -75,4 +76,119 @@ consteval std::array, N> str_make_array() { /// This will generate static array of pair for [0..255] at compile time extern constexpr std::array, 256> one_byte_to_string_lookup_table = str_make_array<256>(); + +/// integer logarithm, return ceil(log(value, base)) (the smallest integer greater or equal than log(value, base) +static constexpr UInt32 intLog(const UInt32 value, const UInt32 base, const bool carry) { + return value >= base ? 1 + intLog(value / base, base, value % base || carry) + : value % base > 1 || carry; +} + +/// Print integer in desired base, faster than sprintf. +/// NOTE This is not the best way. See https://github.com/miloyip/itoa-benchmark +/// But it doesn't matter here. +template +static void print_integer(char*& out, T value) { + if (value == 0) { + *out++ = '0'; + } else { + constexpr size_t buffer_size = sizeof(T) * intLog(256, base, false); + + char buf[buffer_size]; + auto ptr = buf; + + while (value > 0) { + *ptr = hex_digit_lowercase(value % base); + ++ptr; + value /= base; + } + + /// Copy to out reversed. + while (ptr != buf) { + --ptr; + *out = *ptr; + ++out; + } + } +} + +void formatIPv6(const unsigned char* src, char*& dst, uint8_t zeroed_tail_bytes_count) { + struct { + Int64 base, len; + } best {-1, 0}, cur {-1, 0}; + std::array words {}; + + /** Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. */ + for (size_t i = 0; i < (IPV6_BINARY_LENGTH - zeroed_tail_bytes_count); i += 2) { + words[i / 2] = (src[i] << 8) | src[i + 1]; + } + + for (size_t i = 0; i < words.size(); i++) { + if (words[i] == 0) { + if (cur.base == -1) { + cur.base = i; + cur.len = 1; + } else { + cur.len++; + } + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) { + best = cur; + } + cur.base = -1; + } + } + } + + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) { + best = cur; + } + } + if (best.base != -1 && best.len < 2) { + best.base = -1; + } + + /// Format the result. + for (size_t i = 0; i < words.size(); i++) { + /// Are we inside the best run of 0x00's? + if (best.base != -1) { + auto best_base = static_cast(best.base); + if (i >= best_base && i < (best_base + best.len)) { + if (i == best_base) { + *dst++ = ':'; + } + continue; + } + } + /// Are we following an initial run of 0x00s or any real hex? + if (i != 0) { + *dst++ = ':'; + } + /// Is this address an encapsulated IPv4? + if (i == 6 && best.base == 0 && (best.len == 6 || (best.len == 5 && words[5] == 0xffffu))) { + uint8_t ipv4_buffer[IPV4_BINARY_LENGTH] = {0}; + memcpy(ipv4_buffer, src + 12, IPV4_BINARY_LENGTH); + // Due to historical reasons formatIPv4() takes ipv4 in BE format, but inside ipv6 we store it in LE-format. +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + std::reverse(std::begin(ipv4_buffer), std::end(ipv4_buffer)); +#endif + formatIPv4(ipv4_buffer, dst, + std::min(zeroed_tail_bytes_count, static_cast(IPV4_BINARY_LENGTH)), + "0"); + // formatIPv4 has already added a null-terminator for us. + return; + } + print_integer<16>(dst, words[i]); + } + + /// Was it a trailing run of 0x00's? + if (best.base != -1 && + static_cast(best.base) + static_cast(best.len) == words.size()) { + *dst++ = ':'; + } +} + } // namespace doris::vectorized diff --git a/be/src/vec/common/format_ip.h b/be/src/vec/common/format_ip.h index ff440b11e2..ab9ac4b659 100644 --- a/be/src/vec/common/format_ip.h +++ b/be/src/vec/common/format_ip.h @@ -37,6 +37,7 @@ constexpr size_t IPV4_MAX_NUM_VALUE = 4294967295; //num value of '255.255.255.25 constexpr int IPV4_MAX_OCTET_VALUE = 255; //max vulue of octet constexpr size_t IPV4_OCTET_BITS = 8; constexpr size_t DECIMAL_BASE = 10; +constexpr size_t IPV6_BINARY_LENGTH = 16; namespace doris::vectorized { @@ -191,4 +192,10 @@ inline bool parseIPv4whole(const char* src, unsigned char* dst) { return end != nullptr && *end == '\0'; } +/** Rewritten inet_ntop6 from http://svn.apache.org/repos/asf/apr/apr/trunk/network_io/unix/inet_pton.c + * performs significantly faster than the reference implementation due to the absence of sprintf calls, + * bounds checking, unnecessary string copying and length calculation. + */ +void formatIPv6(const unsigned char* src, char*& dst, uint8_t zeroed_tail_bytes_count = 0); + } // namespace doris::vectorized diff --git a/be/src/vec/functions/function_ip.cpp b/be/src/vec/functions/function_ip.cpp index 762134780d..643c69939d 100644 --- a/be/src/vec/functions/function_ip.cpp +++ b/be/src/vec/functions/function_ip.cpp @@ -30,5 +30,7 @@ void register_function_ip(SimpleFunctionFactory& factory) { factory.register_function>(); factory.register_alias(FunctionIPv4StringToNum::name, "inet_aton"); + factory.register_function(); + factory.register_alias(FunctionIPv6NumToString::name, "inet6_ntoa"); } } // 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 18ffc655eb..4a39242e85 100644 --- a/be/src/vec/functions/function_ip.h +++ b/be/src/vec/functions/function_ip.h @@ -26,9 +26,11 @@ #include "vec/columns/column_vector.h" #include "vec/common/format_ip.h" #include "vec/core/column_with_type_and_name.h" +#include "vec/data_types/data_type_ipv6.h" #include "vec/data_types/data_type_number.h" #include "vec/data_types/data_type_string.h" #include "vec/functions/function.h" +#include "vec/functions/function_helpers.h" #include "vec/functions/simple_function_factory.h" namespace doris::vectorized { @@ -250,4 +252,100 @@ public: } }; +template +void process_ipv6_column(const ColumnPtr& column, size_t input_rows_count, + ColumnString::Chars& vec_res, ColumnString::Offsets& offsets_res, + ColumnUInt8::MutablePtr& null_map, unsigned char* ipv6_address_data) { + auto* begin = reinterpret_cast(vec_res.data()); + auto* pos = begin; + + const auto* col = check_and_get_column(column.get()); + + for (size_t i = 0; i < input_rows_count; ++i) { + bool is_empty = false; + + if constexpr (std::is_same_v) { + const auto& vec_in = col->get_data(); + memcpy(ipv6_address_data, reinterpret_cast(&vec_in[i]), + IPV6_BINARY_LENGTH); + } else { + const auto str_ref = col->get_data_at(i); + const char* value = str_ref.data; + size_t value_size = str_ref.size; + + if (value_size > IPV6_BINARY_LENGTH || value == nullptr || value_size == 0) { + is_empty = true; + } else { + memcpy(ipv6_address_data, value, value_size); + memset(ipv6_address_data + value_size, 0, IPV6_BINARY_LENGTH - value_size); + } + } + + if (is_empty) { + offsets_res[i] = pos - begin; + null_map->get_data()[i] = 1; + } else { + formatIPv6(ipv6_address_data, pos); + offsets_res[i] = pos - begin; + } + } +} + +class FunctionIPv6NumToString : public IFunction { +public: + static constexpr auto name = "ipv6numtostring"; + 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 { + const auto* arg_string = check_and_get_data_type(arguments[0].get()); + const auto* arg_ipv6 = check_and_get_data_type(arguments[0].get()); + if (!arg_ipv6 && !(arg_string)) + throw Exception(ErrorCode::INVALID_ARGUMENT, + "Illegal type {} of argument of function {}, expected IPv6 or String", + arguments[0]->get_name(), get_name()); + + 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 { + const ColumnPtr& column = block.get_by_position(arguments[0]).column; + const auto* col_ipv6 = check_and_get_column(column.get()); + const auto* col_string = check_and_get_column(column.get()); + + if (!col_ipv6 && !col_string) + throw Exception(ErrorCode::INVALID_ARGUMENT, + "Illegal column {} of argument of function {}, expected IPv6 or String", + column->get_name(), get_name()); + + auto col_res = ColumnString::create(); + ColumnString::Chars& vec_res = col_res->get_chars(); + ColumnString::Offsets& offsets_res = col_res->get_offsets(); + vec_res.resize(input_rows_count * (IPV6_MAX_TEXT_LENGTH + 1)); + offsets_res.resize(input_rows_count); + + auto null_map = ColumnUInt8::create(input_rows_count, 0); + + unsigned char ipv6_address_data[IPV6_BINARY_LENGTH]; + + if (col_ipv6) { + process_ipv6_column(column, input_rows_count, vec_res, offsets_res, + null_map, ipv6_address_data); + } else { + process_ipv6_column(column, input_rows_count, vec_res, offsets_res, + null_map, ipv6_address_data); + } + + block.replace_by_position(result, + ColumnNullable::create(std::move(col_res), std::move(null_map))); + return Status::OK(); + } +}; + } // namespace doris::vectorized \ No newline at end of file diff --git a/docs/en/docs/sql-manual/sql-functions/ip-functions/inet6-ntoa.md b/docs/en/docs/sql-manual/sql-functions/ip-functions/inet6-ntoa.md new file mode 100644 index 0000000000..638800ec44 --- /dev/null +++ b/docs/en/docs/sql-manual/sql-functions/ip-functions/inet6-ntoa.md @@ -0,0 +1,56 @@ +--- +{ +"title": "INET6_NTOA", +"language": "en" +} +--- + + + +## INET6_NTOA + + + +INET6_NTOA + + + +### description + +#### Syntax + +`VARCHAR INET6_NTOA(VARCHAR ipv6_num)` + +Takes an IPv6 address in binary format of type String. Returns the string of this address in text format. +The IPv4 address mapped by IPv6 starts with ::ffff:111.222.33. + +### example + +``` +mysql> select inet6_ntoa(unhex('2A0206B8000000000000000000000011')) as addr; ++--------------+ +| addr | ++--------------+ +| 2a02:6b8::11 | ++--------------+ +1 row in set (0.01 sec) +``` + +### keywords + +INET6_NTOA, IP \ No newline at end of file diff --git a/docs/en/docs/sql-manual/sql-functions/ip-functions/ipv6-num-to-string.md b/docs/en/docs/sql-manual/sql-functions/ip-functions/ipv6-num-to-string.md new file mode 100644 index 0000000000..96941771ec --- /dev/null +++ b/docs/en/docs/sql-manual/sql-functions/ip-functions/ipv6-num-to-string.md @@ -0,0 +1,56 @@ +--- +{ +"title": "IPV6_NUM_TO_STRING", +"language": "en" +} +--- + + + +## IPv6NumToString + + + +IPv6NumToString + + + +### description + +#### Syntax + +`VARCHAR IPv6NumToString(VARCHAR ipv6_num)` + +Takes an IPv6 address in binary format of type String. Returns the string of this address in text format. +The IPv4 address mapped by IPv6 starts with ::ffff:111.222.33. + +### example + +``` +mysql> select ipv6numtostring(unhex('2A0206B8000000000000000000000011')) as addr; ++--------------+ +| addr | ++--------------+ +| 2a02:6b8::11 | ++--------------+ +1 row in set (0.01 sec) +``` + +### keywords + +IPV6NUMTOSTRING, IP diff --git a/docs/sidebars.json b/docs/sidebars.json index 2efc051f68..4db8f54136 100644 --- a/docs/sidebars.json +++ b/docs/sidebars.json @@ -785,7 +785,9 @@ "sql-manual/sql-functions/ip-functions/ipv4-string-to-num", "sql-manual/sql-functions/ip-functions/inet-aton", "sql-manual/sql-functions/ip-functions/ipv4-string-to-num-or-default", - "sql-manual/sql-functions/ip-functions/ipv4-string-to-num-or-null" + "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" ] }, { diff --git a/docs/zh-CN/docs/sql-manual/sql-functions/ip-functions/inet6-ntoa.md b/docs/zh-CN/docs/sql-manual/sql-functions/ip-functions/inet6-ntoa.md new file mode 100644 index 0000000000..aaeb3cc0c3 --- /dev/null +++ b/docs/zh-CN/docs/sql-manual/sql-functions/ip-functions/inet6-ntoa.md @@ -0,0 +1,56 @@ +--- +{ +"title": "INET6_NTOA", +"language": "en" +} +--- + + + +## INET6_NTOA + + + +INET6_NTOA + + + +### description + +#### Syntax + +`VARCHAR INET6_NTOA(VARCHAR ipv6_num)` + +接受字符串类型的二进制格式的IPv6地址。以文本格式返回此地址的字符串。 +IPv6映射的IPv4地址以::ffff:111.222.33。 + +### example + +``` +mysql> select inet6_ntoa(unhex('2A0206B8000000000000000000000011')) as addr; ++--------------+ +| addr | ++--------------+ +| 2a02:6b8::11 | ++--------------+ +1 row in set (0.01 sec) +``` + +### keywords + +INET6_NTOA, IP \ No newline at end of file diff --git a/docs/zh-CN/docs/sql-manual/sql-functions/ip-functions/ipv6-num-to-string.md b/docs/zh-CN/docs/sql-manual/sql-functions/ip-functions/ipv6-num-to-string.md new file mode 100644 index 0000000000..c58ecf42f4 --- /dev/null +++ b/docs/zh-CN/docs/sql-manual/sql-functions/ip-functions/ipv6-num-to-string.md @@ -0,0 +1,56 @@ +--- +{ +"title": "IPV6_NUM_TO_STRING", +"language": "en" +} +--- + + + +## IPv6NumToString + + + +IPv6NumToString + + + +### description + +#### Syntax + +`VARCHAR IPv6NumToString(VARCHAR ipv6_num)` + +接受字符串类型的二进制格式的IPv6地址。以文本格式返回此地址的字符串。 +IPv6映射的IPv4地址以::ffff:111.222.33。 + +### example + +``` +mysql> select ipv6numtostring(unhex('2A0206B8000000000000000000000011')) as addr; ++--------------+ +| addr | ++--------------+ +| 2a02:6b8::11 | ++--------------+ +1 row in set (0.01 sec) +``` + +### keywords + +IPV6NUMTOSTRING, IP 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 5df7b67d36..ee646e58ed 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 @@ -193,6 +193,7 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.Ipv4NumToStri import org.apache.doris.nereids.trees.expressions.functions.scalar.Ipv4StringToNum; import org.apache.doris.nereids.trees.expressions.functions.scalar.Ipv4StringToNumOrDefault; import org.apache.doris.nereids.trees.expressions.functions.scalar.Ipv4StringToNumOrNull; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Ipv6NumToString; 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; @@ -588,6 +589,7 @@ public class BuiltinScalarFunctions implements FunctionHelper { scalar(Ipv4StringToNum.class, "ipv4stringtonum", "inet_aton"), scalar(Ipv4StringToNumOrDefault.class, "ipv4stringtonumordefault"), scalar(Ipv4StringToNumOrNull.class, "ipv4stringtonumornull"), + scalar(Ipv6NumToString.class, "ipv6numtostring", "inet6_ntoa"), 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/Ipv6NumToString.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Ipv6NumToString.java new file mode 100644 index 0000000000..fafd3fe7a4 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Ipv6NumToString.java @@ -0,0 +1,66 @@ +// 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.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 Ipv6NumToString + */ +public class Ipv6NumToString extends ScalarFunction + implements BinaryExpression, ExplicitlyCastableSignature, AlwaysNullable { + + public static final List SIGNATURES = ImmutableList.of( + FunctionSignature.ret(VarcharType.SYSTEM_DEFAULT).args(VarcharType.SYSTEM_DEFAULT), + FunctionSignature.ret(StringType.INSTANCE).args(StringType.INSTANCE)); + + public Ipv6NumToString(Expression arg0) { + super("ipv6numtostring", arg0); + } + + @Override + public Ipv6NumToString withChildren(List children) { + Preconditions.checkArgument(children.size() == 1, + "ipv6numtostring accept 1 args, but got %s (%s)", + children.size(), + children); + return new Ipv6NumToString(children.get(0)); + } + + @Override + public List getSignatures() { + return SIGNATURES; + } + + @Override + public R accept(ExpressionVisitor visitor, C context) { + return visitor.visitIpv6NumToString(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 20ba455a65..aab82b48bc 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 @@ -189,6 +189,7 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.Ipv4NumToStri import org.apache.doris.nereids.trees.expressions.functions.scalar.Ipv4StringToNum; import org.apache.doris.nereids.trees.expressions.functions.scalar.Ipv4StringToNumOrDefault; import org.apache.doris.nereids.trees.expressions.functions.scalar.Ipv4StringToNumOrNull; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Ipv6NumToString; 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; @@ -1111,6 +1112,10 @@ public interface ScalarFunctionVisitor { return visitScalarFunction(ipv4StringToNumOrNull, context); } + default R visitIpv6NumToString(Ipv6NumToString ipv6NumToString, C context) { + return visitScalarFunction(ipv6NumToString, 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 d7eff94f80..ea72795d08 100644 --- a/gensrc/script/doris_builtins_functions.py +++ b/gensrc/script/doris_builtins_functions.py @@ -2010,7 +2010,9 @@ visible_functions = { [['ipv4stringtonumordefault'], 'BIGINT', ['VARCHAR'], 'ALWAYS_NOT_NULLABLE'], [['ipv4stringtonumordefault'], 'BIGINT', ['STRING'], 'ALWAYS_NOT_NULLABLE'], [['ipv4stringtonumornull'], 'BIGINT', ['VARCHAR'], 'ALWAYS_NULLABLE'], - [['ipv4stringtonumornull'], 'BIGINT', ['STRING'], 'ALWAYS_NULLABLE'], + [['ipv4stringtonumornull'], 'BIGINT', ['STRING'], 'ALWAYS_NULLABLE'], + [['ipv6numtostring','inet6_ntoa'], 'VARCHAR', ['VARCHAR'], 'ALWAYS_NULLABLE'], + [['ipv6numtostring','inet6_ntoa'], 'STRING', ['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 8a3254a993..f906ee221f 100644 --- a/regression-test/data/nereids_function_p0/ip_functions.out +++ b/regression-test/data/nereids_function_p0/ip_functions.out @@ -34,3 +34,57 @@ -- !ip12 -- 3232235521 + +-- !ip13 -- +\N + +-- !ip14 -- +2a02:6b8::11 + +-- !ip15 -- +fdfe::5a55:caff:fefa:9089 + +-- !ip16 -- +\N + +-- !ip17 -- +\N + +-- !ip18 -- +a00:509:: + +-- !ip19 -- +abcd:1234:5600:: + +-- !ip20 -- +\N + +-- !ip21 -- +\N + +-- !ip22 -- +2a02:6b8::11 + +-- !ip23 -- +\N + +-- !ip24 -- +:: + +-- !ip25 -- +:: + +-- !ip26 -- +\N + +-- !ip27 -- +aaaa:aaaa:ffff:ffff:ffff:ffff:aaaa:aaaa + +-- !ip28 -- +\N + +-- !ip29 -- +\N + +-- !ip30 -- +::ffff:127.0.0.1 \ 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 5005a68cd4..54e2fac889 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 @@ -20,4 +20,58 @@ 0 -- !sql -- -3232235521 \ No newline at end of file +3232235521 + +-- !sql -- +\N + +-- !sql -- +2a02:6b8::11 + +-- !sql -- +fdfe::5a55:caff:fefa:9089 + +-- !sql -- +\N + +-- !sql -- +\N + +-- !sql -- +a00:509:: + +-- !sql -- +abcd:1234:5600:: + +-- !sql -- +\N + +-- !sql -- +\N + +-- !sql -- +2a02:6b8::11 + +-- !sql -- +\N + +-- !sql -- +:: + +-- !sql -- +:: + +-- !sql -- +\N + +-- !sql -- +aaaa:aaaa:ffff:ffff:ffff:ffff:aaaa:aaaa + +-- !sql -- +\N + +-- !sql -- +\N + +-- !sql -- +::ffff:127.0.0.1 \ 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 5b0588e8fd..2a6f8caad6 100644 --- a/regression-test/suites/nereids_function_p0/ip_functions.groovy +++ b/regression-test/suites/nereids_function_p0/ip_functions.groovy @@ -31,4 +31,23 @@ suite("ip_functions") { qt_ip10 "SELECT ipv4stringtonumornull('');" qt_ip11 "SELECT ipv4stringtonumordefault('');" qt_ip12 "SELECT inet_aton('192.168.0.1');" + + qt_ip13 "SELECT ipv6numtostring(unhex('0A0005091'));" + qt_ip14 "SELECT ipv6numtostring(unhex('2A0206B8000000000000000000000011'));" + qt_ip15 "SELECT ipv6numtostring(unhex('FDFE0000000000005A55CAFFFEFA9089'));" + qt_ip16 "SELECT ipv6numtostring(unhex(''));" + qt_ip17 "SELECT ipv6numtostring(unhex('KK'));" + qt_ip18 "SELECT ipv6numtostring(unhex('0A000509'));" + qt_ip19 "SELECT ipv6numtostring(unhex('abcd123456'));" + qt_ip20 "SELECT ipv6numtostring(unhex('ffffffffffffffffffffffffffffffffffffffffffffffffffffff'));" + qt_ip21 "SELECT inet6_ntoa(unhex('0A0005091'));" + qt_ip22 "SELECT inet6_ntoa(unhex('2A0206B8000000000000000000000011'));" + qt_ip23 "SELECT inet6_ntoa(unhex(NULL));" + qt_ip24 "SELECT inet6_ntoa(unhex('00000000000000000000000000000000'));" + qt_ip25 "SELECT inet6_ntoa(unhex('0000000000000000000000000000'));" + qt_ip26 "SELECT inet6_ntoa(unhex('000'));" + qt_ip27 "SELECT inet6_ntoa(unhex('aaaaaaaaFFFFFFFFFFFFFFFFaaaaaaaa'));" + qt_ip28 "SELECT inet6_ntoa(unhex('aaaa@#'));" + qt_ip29 "SELECT inet6_ntoa(unhex('\0'));" + qt_ip30 "SELECT inet6_ntoa(unhex('00000000000000000000FFFF7F000001'));" } \ 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 5d222f544a..6991da94c2 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 @@ -26,4 +26,23 @@ suite("test_ip_functions") { qt_sql "SELECT ipv4stringtonumornull('');" qt_sql "SELECT ipv4stringtonumordefault('');" qt_sql "SELECT inet_aton('192.168.0.1');" + + qt_sql "SELECT ipv6numtostring(unhex('0A0005091'));" + qt_sql "SELECT ipv6numtostring(unhex('2A0206B8000000000000000000000011'));" + qt_sql "SELECT ipv6numtostring(unhex('FDFE0000000000005A55CAFFFEFA9089'));" + qt_sql "SELECT ipv6numtostring(unhex(''));" + qt_sql "SELECT ipv6numtostring(unhex('KK'));" + qt_sql "SELECT ipv6numtostring(unhex('0A000509'));" + qt_sql "SELECT ipv6numtostring(unhex('abcd123456'));" + qt_sql "SELECT ipv6numtostring(unhex('ffffffffffffffffffffffffffffffffffffffffffffffffffffff'));" + qt_sql "SELECT inet6_ntoa(unhex('0A0005091'));" + qt_sql "SELECT inet6_ntoa(unhex('2A0206B8000000000000000000000011'));" + qt_sql "SELECT inet6_ntoa(unhex(NULL));" + qt_sql "SELECT inet6_ntoa(unhex('00000000000000000000000000000000'));" + qt_sql "SELECT inet6_ntoa(unhex('0000000000000000000000000000'));" + qt_sql "SELECT inet6_ntoa(unhex('000'));" + qt_sql "SELECT inet6_ntoa(unhex('aaaaaaaaFFFFFFFFFFFFFFFFaaaaaaaa'));" + qt_sql "SELECT inet6_ntoa(unhex('aaaa@#'));" + qt_sql "SELECT inet6_ntoa(unhex('\0'));" + qt_sql "SELECT inet6_ntoa(unhex('00000000000000000000FFFF7F000001'));" }