[feature](function) support ip function named is_ip_address_in_range(addr, cidr) (#29681)

This commit is contained in:
yangshijie
2024-01-09 15:19:51 +08:00
committed by yiguolei
parent 7357ca62af
commit be56bf06cf
13 changed files with 429 additions and 34 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"),

View File

@ -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.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;
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_ip_address_in_range`
*/
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, VarcharType.SYSTEM_DEFAULT),
FunctionSignature.ret(BooleanType.INSTANCE).args(StringType.INSTANCE, StringType.INSTANCE));
public IsIpAddressInRange(Expression arg0, Expression arg1) {
super("is_ip_address_in_range", arg0, arg1);
}
@Override
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 IsIpAddressInRange(children.get(0), children.get(1));
}
@Override
public List<FunctionSignature> getSignatures() {
return SIGNATURES;
}
@Override
public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
return visitor.visitIsIPAddressInRange(this, context);
}
}

View File

@ -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));

View File

@ -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));

View File

@ -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);
}

View File

@ -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": [

View File

@ -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

View File

@ -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');"
}

View File

@ -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 """
}

View File

@ -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"
}