diff --git a/be/src/vec/common/ipv6_to_binary.h b/be/src/vec/common/ipv6_to_binary.h new file mode 100644 index 0000000000..0f22740fbc --- /dev/null +++ b/be/src/vec/common/ipv6_to_binary.h @@ -0,0 +1,69 @@ +// 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/Common/IPv6ToBinary.cpp +// and modified by Doris + +#pragma once + +#include "vec/common/format_ip.h" + +namespace doris::vectorized { + +/// Result array could be indexed with all possible uint8 values without extra check. +/// For values greater than 128 we will store same value as for 128 (all bits set). +constexpr size_t IPV6_MASKS_COUNT = 256; +using RawMaskArrayV6 = std::array; + +template +static constexpr RawMaskArrayT generate_bit_mask(size_t prefix) { + RawMaskArrayT arr {0}; + if (prefix >= arr.size() * 8) { + prefix = arr.size() * 8; + } + size_t i = 0; + for (; prefix >= 8; ++i, prefix -= 8) { + arr[i] = 0xff; + } + if (prefix > 0) { + arr[i++] = ~(0xff >> prefix); + } + while (i < arr.size()) { + arr[i++] = 0x00; + } + return arr; +} + +template +static constexpr std::array generate_bit_masks() { + std::array arr {}; + for (size_t i = 0; i < masksCount; ++i) { + arr[i] = generate_bit_mask(i); + } + return arr; +} + +/// Returns a reference to 16-byte array containing mask with first `prefix_len` bits set to `1` and `128 - prefix_len` to `0`. +/// The reference is valid during all program execution time. +/// Values of prefix_len greater than 128 interpreted as 128 exactly. +const std::array& get_cidr_mask_ipv6(uint8_t prefix_len) { + static constexpr auto IPV6_RAW_MASK_ARRAY = + generate_bit_masks(); + return IPV6_RAW_MASK_ARRAY[prefix_len]; +} + +} // namespace doris::vectorized diff --git a/be/src/vec/data_types/data_type.h b/be/src/vec/data_types/data_type.h index 8fa41f8888..bc53fac6a3 100644 --- a/be/src/vec/data_types/data_type.h +++ b/be/src/vec/data_types/data_type.h @@ -285,6 +285,10 @@ struct WhichDataType { bool is_date_or_datetime() const { return is_date() || is_date_time(); } bool is_date_v2_or_datetime_v2() const { return is_date_v2() || is_date_time_v2(); } + bool is_ipv4() const { return idx == TypeIndex::IPv4; } + bool is_ipv6() const { return idx == TypeIndex::IPv6; } + bool is_ip() const { return is_ipv4() || is_ipv6(); } + bool is_string() const { return idx == TypeIndex::String; } bool is_fixed_string() const { return idx == TypeIndex::FixedString; } bool is_string_or_fixed_string() const { return is_string() || is_fixed_string(); } @@ -307,42 +311,36 @@ struct WhichDataType { /// IDataType helpers (alternative for IDataType virtual methods with single point of truth) -inline bool is_date(const DataTypePtr& data_type) { - return WhichDataType(data_type).is_date(); -} -inline bool is_date_v2(const DataTypePtr& data_type) { - return WhichDataType(data_type).is_date_v2(); -} -inline bool is_date_time_v2(const DataTypePtr& data_type) { - return WhichDataType(data_type).is_date_time_v2(); -} -inline bool is_date_or_datetime(const DataTypePtr& data_type) { - return WhichDataType(data_type).is_date_or_datetime(); -} -inline bool is_date_v2_or_datetime_v2(const DataTypePtr& data_type) { - return WhichDataType(data_type).is_date_v2_or_datetime_v2(); -} -inline bool is_decimal(const DataTypePtr& data_type) { - return WhichDataType(data_type).is_decimal(); -} -inline bool is_decimal_v2(const DataTypePtr& data_type) { - return WhichDataType(data_type).is_decimal128v2(); -} -inline bool is_tuple(const DataTypePtr& data_type) { - return WhichDataType(data_type).is_tuple(); -} -inline bool is_array(const DataTypePtr& data_type) { - return WhichDataType(data_type).is_array(); -} -inline bool is_map(const DataTypePtr& data_type) { - return WhichDataType(data_type).is_map(); -} -inline bool is_struct(const DataTypePtr& data_type) { - return WhichDataType(data_type).is_struct(); -} -inline bool is_nothing(const DataTypePtr& data_type) { - return WhichDataType(data_type).is_nothing(); -} +#define IS_DATATYPE(name, method) \ + inline bool is_##name(const DataTypePtr& data_type) { \ + return WhichDataType(data_type).is_##method(); \ + } + +IS_DATATYPE(uint8, uint8) +IS_DATATYPE(uint16, uint16) +IS_DATATYPE(uint32, uint32) +IS_DATATYPE(uint64, uint64) +IS_DATATYPE(uint128, uint128) +IS_DATATYPE(int8, int8) +IS_DATATYPE(int16, int16) +IS_DATATYPE(int32, int32) +IS_DATATYPE(int64, int64) +IS_DATATYPE(int128, int128) +IS_DATATYPE(date, date) +IS_DATATYPE(date_v2, date_v2) +IS_DATATYPE(date_time_v2, date_time_v2) +IS_DATATYPE(date_or_datetime, date_or_datetime) +IS_DATATYPE(date_v2_or_datetime_v2, date_v2_or_datetime_v2) +IS_DATATYPE(decimal, decimal) +IS_DATATYPE(decimal_v2, decimal128v2) +IS_DATATYPE(tuple, tuple) +IS_DATATYPE(array, array) +IS_DATATYPE(map, map) +IS_DATATYPE(struct, struct) +IS_DATATYPE(ipv4, ipv4) +IS_DATATYPE(ipv6, ipv6) +IS_DATATYPE(ip, ip) +IS_DATATYPE(nothing, nothing) template bool is_uint8(const T& data_type) { diff --git a/be/src/vec/functions/function_ip.cpp b/be/src/vec/functions/function_ip.cpp index fb0c346e6a..dce648bfaa 100644 --- a/be/src/vec/functions/function_ip.cpp +++ b/be/src/vec/functions/function_ip.cpp @@ -37,5 +37,6 @@ void register_function_ip(SimpleFunctionFactory& factory) { factory.register_function(); factory.register_function(); 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 18c2033ff8..2997153049 100644 --- a/be/src/vec/functions/function_ip.h +++ b/be/src/vec/functions/function_ip.h @@ -23,12 +23,15 @@ #include "vec/columns/column.h" #include "vec/columns/column_string.h" +#include "vec/columns/column_struct.h" #include "vec/columns/column_vector.h" #include "vec/common/format_ip.h" +#include "vec/common/ipv6_to_binary.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/data_types/data_type_struct.h" #include "vec/functions/function.h" #include "vec/functions/function_helpers.h" #include "vec/functions/simple_function_factory.h" @@ -832,4 +835,138 @@ public: } }; +class FunctionIPv6CIDRToRange : public IFunction { +public: + static constexpr auto name = "ipv6_cidr_to_range"; + static FunctionPtr create() { return std::make_shared(); } + + 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 { + const auto& ipv6_type = arguments[0]; + if (!is_string(remove_nullable(ipv6_type)) && !is_ipv6(remove_nullable(ipv6_type))) { + throw Exception( + ErrorCode::INVALID_ARGUMENT, + "Illegal type {} of first argument of function {}, expected String or IPv6", + ipv6_type->get_name(), get_name()); + } + const auto& cidr_type = arguments[1]; + if (!is_int16(remove_nullable(cidr_type))) { + throw Exception(ErrorCode::INVALID_ARGUMENT, + "Illegal type {} of second argument of function {}, expected Int16", + cidr_type->get_name(), get_name()); + } + DataTypePtr element = std::make_shared(); + return make_nullable(std::make_shared(DataTypes {element, element}, + Strings {"min", "max"})); + } + + 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 auto& addr_column_with_type_and_name = block.get_by_position(arguments[0]); + const auto& cidr_column_with_type_and_name = block.get_by_position(arguments[1]); + WhichDataType addr_type(addr_column_with_type_and_name.type); + WhichDataType cidr_type(cidr_column_with_type_and_name.type); + const ColumnPtr& addr_column = addr_column_with_type_and_name.column; + const ColumnPtr& cidr_column = cidr_column_with_type_and_name.column; + const ColumnInt16* cidr_col = nullptr; + const NullMap* cidr_null_map = nullptr; + ColumnPtr col_res = nullptr; + + if (cidr_type.is_nullable()) { + const auto* cidr_column_nullable = + assert_cast(cidr_column.get()); + cidr_col = assert_cast(&cidr_column_nullable->get_nested_column()); + cidr_null_map = &cidr_column_nullable->get_null_map_data(); + } else { + cidr_col = assert_cast(cidr_column.get()); + } + + if (addr_type.is_nullable()) { + const auto* addr_column_nullable = + assert_cast(addr_column.get()); + const NullMap* addr_null_map = &addr_column_nullable->get_null_map_data(); + WhichDataType sub_addr_type(remove_nullable(addr_column_with_type_and_name.type)); + + if (sub_addr_type.is_ipv6()) { + const auto* ipv6_addr_column = + check_and_get_column(addr_column_nullable->get_nested_column()); + col_res = execute_impl(*ipv6_addr_column, addr_null_map, *cidr_col, + cidr_null_map, input_rows_count); + } else if (sub_addr_type.is_string()) { + const auto* str_addr_column = check_and_get_column( + addr_column_nullable->get_nested_column()); + col_res = execute_impl(*str_addr_column, addr_null_map, *cidr_col, + cidr_null_map, input_rows_count); + } else { + return Status::RuntimeError( + "Illegal column {} of argument of function {}, Expected IPv6 or String", + addr_column->get_name(), get_name()); + } + } else { + if (addr_type.is_ipv6()) { + const auto* ipv6_addr_column = check_and_get_column(addr_column.get()); + col_res = execute_impl(*ipv6_addr_column, nullptr, *cidr_col, nullptr, + input_rows_count); + } else if (addr_type.is_string()) { + const auto* str_addr_column = check_and_get_column(addr_column.get()); + col_res = execute_impl(*str_addr_column, nullptr, *cidr_col, nullptr, + input_rows_count); + } else { + return Status::RuntimeError( + "Illegal column {} of argument of function {}, Expected IPv6 or String", + addr_column->get_name(), get_name()); + } + } + + block.replace_by_position(result, std::move(col_res)); + return Status::OK(); + } + + template + static ColumnPtr execute_impl(const FromColumn& from_column, const NullMap* from_null_map, + const ColumnInt16& cidr_column, const NullMap* cidr_null_map, + size_t input_rows_count) { + auto col_res_lower_range = ColumnIPv6::create(input_rows_count, 0); + auto col_res_upper_range = ColumnIPv6::create(input_rows_count, 0); + auto col_res_null_map = ColumnUInt8::create(input_rows_count, 0); + auto& vec_res_lower_range = col_res_lower_range->get_data(); + auto& vec_res_upper_range = col_res_upper_range->get_data(); + auto& vec_res_null_map = col_res_null_map->get_data(); + + static constexpr Int64 max_cidr_mask = IPV6_BINARY_LENGTH * 8; + + for (size_t i = 0; i < input_rows_count; ++i) { + if ((from_null_map && (*from_null_map)[i]) || (cidr_null_map && (*cidr_null_map)[i])) { + vec_res_null_map[i] = 1; + continue; + } + Int64 cidr = cidr_column.get_int(i); + cidr = std::min(cidr, max_cidr_mask); + apply_cidr_mask(from_column.get_data_at(i).data, + reinterpret_cast(&vec_res_lower_range[i]), + reinterpret_cast(&vec_res_upper_range[i]), cidr); + } + + auto col_res_struct = ColumnStruct::create( + Columns {std::move(col_res_lower_range), std::move(col_res_upper_range)}); + return ColumnNullable::create(std::move(col_res_struct), std::move(col_res_null_map)); + } + +private: + static void apply_cidr_mask(const char* __restrict src, char* __restrict dst_lower, + char* __restrict dst_upper, UInt8 bits_to_keep) { + const auto& mask = get_cidr_mask_ipv6(bits_to_keep); + + for (size_t i = 0; i < IPV6_BINARY_LENGTH; ++i) { + dst_lower[i] = src[i] & mask[i]; + dst_upper[i] = dst_lower[i] | ~mask[i]; + } + } +}; + } // namespace doris::vectorized \ 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 c4c4043bf7..903a77b449 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 @@ -188,6 +188,7 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.HourFloor; import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursAdd; import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursDiff; import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursSub; +import org.apache.doris.nereids.trees.expressions.functions.scalar.IPv6CIDRToRange; import org.apache.doris.nereids.trees.expressions.functions.scalar.If; import org.apache.doris.nereids.trees.expressions.functions.scalar.Ignore; import org.apache.doris.nereids.trees.expressions.functions.scalar.Initcap; @@ -611,6 +612,7 @@ public class BuiltinScalarFunctions implements FunctionHelper { scalar(IsIpv4String.class, "is_ipv4_string"), scalar(IsIpv6String.class, "is_ipv6_string"), scalar(IsIpAddressInRange.class, "is_ip_address_in_range"), + scalar(IPv6CIDRToRange.class, "ipv6_cidr_to_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/IPv6CIDRToRange.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/IPv6CIDRToRange.java new file mode 100644 index 0000000000..2ada5b0e09 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/IPv6CIDRToRange.java @@ -0,0 +1,79 @@ +// 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.IPv6Type; +import org.apache.doris.nereids.types.SmallIntType; +import org.apache.doris.nereids.types.StringType; +import org.apache.doris.nereids.types.StructField; +import org.apache.doris.nereids.types.StructType; +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 `ipv6_cidr_to_range` + */ +public class IPv6CIDRToRange extends ScalarFunction + implements BinaryExpression, ExplicitlyCastableSignature, AlwaysNullable { + + public static final List SIGNATURES; + + static { + ImmutableList.Builder structFields = ImmutableList.builder(); + structFields.add(new StructField("min", IPv6Type.INSTANCE, false, "")); + structFields.add(new StructField("max", IPv6Type.INSTANCE, false, "")); + StructType retType = new StructType(structFields.build()); + SIGNATURES = ImmutableList.of( + FunctionSignature.ret(retType).args(IPv6Type.INSTANCE, SmallIntType.INSTANCE), + FunctionSignature.ret(retType).args(VarcharType.SYSTEM_DEFAULT, SmallIntType.INSTANCE), + FunctionSignature.ret(retType).args(StringType.INSTANCE, SmallIntType.INSTANCE)); + } + + public IPv6CIDRToRange(Expression arg0, Expression arg1) { + super("ipv6_cidr_to_range", arg0, arg1); + } + + @Override + public IPv6CIDRToRange withChildren(List children) { + Preconditions.checkArgument(children.size() == 2, + "ipv6_cidr_to_range accept 2 args, but got %s (%s)", + children.size(), + children); + return new IPv6CIDRToRange(children.get(0), children.get(1)); + } + + @Override + public List getSignatures() { + return SIGNATURES; + } + + @Override + public R accept(ExpressionVisitor visitor, C context) { + return visitor.visitIpv6CIDRToRange(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 81ce549d58..6f43a45dd7 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 @@ -184,6 +184,7 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.HourFloor; import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursAdd; import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursDiff; import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursSub; +import org.apache.doris.nereids.trees.expressions.functions.scalar.IPv6CIDRToRange; import org.apache.doris.nereids.trees.expressions.functions.scalar.If; import org.apache.doris.nereids.trees.expressions.functions.scalar.Ignore; import org.apache.doris.nereids.trees.expressions.functions.scalar.Initcap; @@ -1166,6 +1167,10 @@ public interface ScalarFunctionVisitor { return visitScalarFunction(isIpAddressInRange, context); } + default R visitIpv6CIDRToRange(IPv6CIDRToRange ipv6CIDRToRange, C context) { + return visitScalarFunction(ipv6CIDRToRange, 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 302cefd806..4f4c2f37b8 100644 --- a/gensrc/script/doris_builtins_functions.py +++ b/gensrc/script/doris_builtins_functions.py @@ -2020,6 +2020,8 @@ visible_functions = { [['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'], + [['ipv6_cidr_to_range'], 'STRUCT', ['VARCHAR', 'SMALLINT'], 'ALWAYS_NULLABLE'], + [['ipv6_cidr_to_range'], 'STRUCT', ['STRING', 'SMALLINT'], 'ALWAYS_NULLABLE'], ], "NonNullalbe": [ diff --git a/regression-test/data/query_p0/sql_functions/ip_functions/test_ipv6_cidr_to_range_function.out b/regression-test/data/query_p0/sql_functions/ip_functions/test_ipv6_cidr_to_range_function.out new file mode 100644 index 0000000000..411010046c --- /dev/null +++ b/regression-test/data/query_p0/sql_functions/ip_functions/test_ipv6_cidr_to_range_function.out @@ -0,0 +1,32 @@ +-- !sql -- +1 :: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff +2 2001:db8:: 2001:db8:ffff:ffff:ffff:ffff:ffff:ffff +3 ffff:: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff +4 2001:df8:: 2001:df8:ffff:ffff:ffff:ffff:ffff:ffff +5 2001:: 2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff +6 :: ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff +7 f000:: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff + +-- !sql -- +1 :: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff +2 2001:db8:: 2001:db8:ffff:ffff:ffff:ffff:ffff:ffff +3 ffff:: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff +4 2001:df8:: 2001:df8:ffff:ffff:ffff:ffff:ffff:ffff +5 2001:: 2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff +6 :: ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff +7 f000:: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff + +-- !sql -- +{"min": "::", "max": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"} + +-- !sql -- +{"min": "2001:db8:0:85a3::ac1f:8001", "max": "2001:db8:0:85a3::ac1f:8001"} + +-- !sql -- +{"min": "ffff:ffff:ffff:ffff::", "max": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"} + +-- !sql -- +{"min": "::", "max": "ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"} + +-- !sql -- +{"min": "f000::", "max": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"} diff --git a/regression-test/suites/query_p0/sql_functions/ip_functions/test_ipv6_cidr_to_range_function.groovy b/regression-test/suites/query_p0/sql_functions/ip_functions/test_ipv6_cidr_to_range_function.groovy new file mode 100644 index 0000000000..f606460377 --- /dev/null +++ b/regression-test/suites/query_p0/sql_functions/ip_functions/test_ipv6_cidr_to_range_function.groovy @@ -0,0 +1,85 @@ +// 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_ipv6_cidr_to_range_function") { + sql """ DROP TABLE IF EXISTS test_ipv6_cidr_to_range_function """ + + sql """ SET enable_nereids_planner=true """ + sql """ SET enable_fallback_to_original_planner=false """ + + sql """ + CREATE TABLE test_ipv6_cidr_to_range_function ( + `id` int, + `addr` ipv6, + `cidr` int + ) ENGINE=OLAP + UNIQUE KEY (`id`) + DISTRIBUTED BY HASH(`id`) BUCKETS 4 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1" + ); + """ + + sql """ + insert into test_ipv6_cidr_to_range_function values + (1, '2001:0db8:0000:85a3:0000:0000:ac1f:8001', 0), + (2, '2001:0db8:0000:85a3:ffff:ffff:ffff:ffff', 32), + (3, 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', 16), + (4, '2001:df8:0:85a3::ac1f:8001', 32), + (5, '2001:0db8:85a3:85a3:0000:0000:ac1f:8001', 16), + (6, '0000:0000:0000:0000:0000:0000:0000:0000', 8), + (7, 'ffff:0000:0000:0000:0000:0000:0000:0000', 4) + """ + + qt_sql "select id, struct_element(ipv6_cidr_to_range(addr, cidr), 'min') as min_range, struct_element(ipv6_cidr_to_range(addr, cidr), 'max') as max_range from test_ipv6_cidr_to_range_function order by id" + + sql """ DROP TABLE IF EXISTS test_ipv6_cidr_to_range_function """ + + sql """ + CREATE TABLE test_str_cidr_to_range_function ( + `id` int, + `addr` string, + `cidr` int + ) ENGINE=OLAP + UNIQUE KEY (`id`) + DISTRIBUTED BY HASH(`id`) BUCKETS 4 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1" + ); + """ + + sql """ + insert into test_str_cidr_to_range_function values + (1, '2001:0db8:0000:85a3:0000:0000:ac1f:8001', 0), + (2, '2001:0db8:0000:85a3:ffff:ffff:ffff:ffff', 32), + (3, 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', 16), + (4, '2001:df8:0:85a3::ac1f:8001', 32), + (5, '2001:0db8:85a3:85a3:0000:0000:ac1f:8001', 16), + (6, '0000:0000:0000:0000:0000:0000:0000:0000', 8), + (7, 'ffff:0000:0000:0000:0000:0000:0000:0000', 4) + """ + + qt_sql "select id, struct_element(ipv6_cidr_to_range(ipv6_string_to_num(addr), cidr), 'min') as min_range, struct_element(ipv6_cidr_to_range(ipv6_string_to_num(addr), cidr), 'max') as max_range from test_str_cidr_to_range_function order by id" + + sql """ DROP TABLE IF EXISTS test_str_cidr_to_range_function """ + + qt_sql "select ipv6_cidr_to_range(ipv6_string_to_num('2001:0db8:0000:85a3:0000:0000:ac1f:8001'), 0)" + qt_sql "select ipv6_cidr_to_range(ipv6_string_to_num('2001:0db8:0000:85a3:0000:0000:ac1f:8001'), 128)" + qt_sql "select ipv6_cidr_to_range(ipv6_string_to_num('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'), 64)" + qt_sql "select ipv6_cidr_to_range(ipv6_string_to_num('0000:0000:0000:0000:0000:0000:0000:0000'), 8)" + qt_sql "select ipv6_cidr_to_range(ipv6_string_to_num('ffff:0000:0000:0000:0000:0000:0000:0000'), 4)" +} \ No newline at end of file