[feature](function) support ip function named is_ip_address_in_range(addr, cidr) (#29681)
This commit is contained in:
@ -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
|
||||
@ -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
|
||||
141
be/src/vec/runtime/ip_address_cidr.h
Normal file
141
be/src/vec/runtime/ip_address_cidr.h
Normal 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
|
||||
@ -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"),
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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));
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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": [
|
||||
|
||||
@ -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
|
||||
@ -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');"
|
||||
}
|
||||
@ -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 """
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
Reference in New Issue
Block a user