11#include < Columns/ColumnConst.h>
22#include < Columns/ColumnString.h>
33#include < Columns/ColumnsNumber.h>
4+ #include < Columns/ColumnNullable.h>
45#include < Common/IPv6ToBinary.h>
56#include < Common/formatIPv6.h>
67#include < DataTypes/DataTypeNullable.h>
@@ -23,23 +24,65 @@ namespace DB::ErrorCodes
2324namespace
2425{
2526
27+ enum class IPKind
28+ {
29+ IPv4,
30+ IPv6,
31+ String
32+ };
33+
34+ template <IPKind kind>
35+ struct IPTrait
36+ {
37+ };
38+
39+ template <>
40+ struct IPTrait <IPKind::IPv4>
41+ {
42+ using ColumnType = DB::ColumnIPv4;
43+ using ElementType = DB::IPv4;
44+ };
45+
46+ template <>
47+ struct IPTrait <IPKind::IPv6>
48+ {
49+ using ColumnType = DB::ColumnIPv6;
50+ using ElementType = DB::UInt128;
51+ };
52+
53+ template <>
54+ struct IPTrait <IPKind::String>
55+ {
56+ using ColumnType = DB::ColumnString;
57+ using ElementType = std::string_view;
58+ };
59+
2660class IPAddressVariant
2761{
2862public:
63+ explicit IPAddressVariant (DB::IPv4 addr_): addr(addr_)
64+ {
65+ }
66+
67+ explicit IPAddressVariant (UInt128 addr_)
68+ {
69+ addr = IPv6AddrType ();
70+ auto * dst = std::get<IPv6AddrType>(addr).data ();
71+ const char * src = reinterpret_cast <const char *>(&addr_.items );
72+ memcpy (dst, src, IPV6_BINARY_LENGTH);
73+ }
2974
30- explicit IPAddressVariant (std::string_view address_str )
75+ explicit IPAddressVariant (std::string_view addr_ )
3176 {
3277 UInt32 v4;
33- if (DB::parseIPv4whole (address_str.data (), address_str.data () + address_str.size (), reinterpret_cast <unsigned char *>(&v4)))
34- {
78+ if (DB::parseIPv4whole (addr_.data (), addr_.data () + addr_.size (), reinterpret_cast <unsigned char *>(&v4)))
3579 addr = v4;
36- }
3780 else
3881 {
3982 addr = IPv6AddrType ();
40- bool success = DB::parseIPv6whole (address_str .data (), address_str .data () + address_str .size (), std::get<IPv6AddrType>(addr).data ());
83+ bool success = DB::parseIPv6whole (addr_ .data (), addr_ .data () + addr_ .size (), std::get<IPv6AddrType>(addr).data ());
4184 if (!success)
42- throw DB::Exception (DB::ErrorCodes::CANNOT_PARSE_TEXT, " Neither IPv4 nor IPv6 address: '{}'" , address_str );
85+ throw DB::Exception (DB::ErrorCodes::CANNOT_PARSE_TEXT, " Neither IPv4 nor IPv6 address: '{}'" , addr_ );
4386 }
4487 }
4588
@@ -80,13 +123,13 @@ IPAddressCIDR parseIPWithCIDR(std::string_view cidr_str)
80123 throw DB::Exception (DB::ErrorCodes::CANNOT_PARSE_TEXT, " The text does not contain '/': {}" , std::string (cidr_str));
81124
82125 std::string_view addr_str = cidr_str.substr (0 , pos_slash);
83- IPAddressVariant addr (addr_str);
126+ auto addr = IPAddressVariant (addr_str);
84127
85128 uint8_t prefix = 0 ;
86129 auto prefix_str = cidr_str.substr (pos_slash+1 );
87130
88131 const auto * prefix_str_end = prefix_str.data () + prefix_str.size ();
89- auto [parse_end, parse_error] = std::from_chars (prefix_str.data (), prefix_str_end, prefix); // / NOLINT(bugprone-suspicious-stringview-data-usage)
132+ auto [parse_end, parse_error] = std::from_chars (prefix_str.data (), prefix_str_end, prefix); // / NOLINT(bugprone-suspicious-stringview-data-usage)
90133 uint8_t max_prefix = (addr.asV6 () ? IPV6_BINARY_LENGTH : IPV4_BINARY_LENGTH) * 8 ;
91134 bool has_error = parse_error != std::errc () || parse_end != prefix_str_end || prefix > max_prefix;
92135 if (has_error)
@@ -122,6 +165,37 @@ namespace DB
122165 static FunctionPtr create (ContextPtr) { return std::make_shared<FunctionIsIPAddressContainedIn>(); }
123166 bool isSuitableForShortCircuitArgumentsExecution (const DataTypesWithConstInfo & /* arguments*/ ) const override { return true ; }
124167
168+ template <IPKind kind>
169+ static inline IPAddressVariant parseIP (const IPTrait<kind>::ColumnType * col_addr, size_t n)
170+ {
171+ if constexpr (kind == IPKind::IPv4 || kind == IPKind::IPv6)
172+ {
173+ return IPAddressVariant (col_addr->getElement (n));
174+ }
175+ return IPAddressVariant (col_addr->getDataAt (n).toView ());
176+ }
177+
178+ #pragma clang diagnostic ignored "-Wshadow"
179+ #define EXEC_IMPL (col, func, ...) \
180+ if (const auto * ipv4_column = dynamic_cast <const ColumnIPv4 *>(&(col))) \
181+ return func<IPKind::IPv4>(ipv4_column, __VA_ARGS__); \
182+ else if (const auto * ipv6_column = dynamic_cast <const ColumnIPv6 *>(&(col))) \
183+ return func<IPKind::IPv6>(ipv6_column, __VA_ARGS__); \
184+ else if (const auto * string_column = dynamic_cast <const ColumnString *>(&(col))) \
185+ return func<IPKind::String>(string_column, __VA_ARGS__);
186+
187+ static std::optional<IPAddressVariant> parseConstantIP (const ColumnConst & col_addr)
188+ {
189+ EXEC_IMPL (col_addr.getDataColumn (), parseIP, 0 )
190+ else if (col_addr.onlyNull ())
191+ return std::nullopt ;
192+ else if (const auto * nullable_column = dynamic_cast <const ColumnNullable *>(&col_addr.getDataColumn ()))
193+ {
194+ EXEC_IMPL (nullable_column->getNestedColumn (), parseIP, 0 ) // /NO-LINT
195+ }
196+ throw Exception (ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, " The IP column type must be one of: String, IPv4, IPv6, Nullable(IPv4), Nullable(IPv6), or Nullable(String)." );
197+ }
198+
125199 ColumnPtr executeImpl (const ColumnsWithTypeAndName & arguments, const DataTypePtr & /* return_type */ , size_t input_rows_count) const override
126200 {
127201 const IColumn * col_addr = arguments[0 ].column .get ();
@@ -133,7 +207,6 @@ namespace DB
133207 return executeImpl (*col_addr_const, *col_cidr_const, input_rows_count);
134208 return executeImpl (*col_addr_const, *col_cidr, input_rows_count);
135209 }
136-
137210 if (const auto * col_cidr_const = checkAndGetAnyColumnConst (col_cidr))
138211 return executeImpl (*col_addr, *col_cidr_const, input_rows_count);
139212 return executeImpl (*col_addr, *col_cidr, input_rows_count);
@@ -149,14 +222,19 @@ namespace DB
149222 const DataTypePtr & addr_type = arguments[0 ];
150223 const DataTypePtr & prefix_type = arguments[1 ];
151224
152- if (!isString (addr_type) || !isString (prefix_type))
153- throw Exception (ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, " The arguments of function {} must be String" , getName ());
225+ WhichDataType type = WhichDataType (addr_type);
226+ if (const auto * nullable_type = dynamic_cast <const DataTypeNullable *>(&*addr_type))
227+ type = WhichDataType (nullable_type->getNestedType ());
154228
155- return std::make_shared<DataTypeUInt8>();
156- }
229+ if (!(type.isString () || type.isIPv4 () || type.isIPv6 ()) || !isString (prefix_type))
230+ throw Exception (
231+ ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
232+ " The first argument of function {} must be one of: String, IPv4, IPv6, Nullable(String), Nullable(IPv4), or "
233+ " Nullable(IPv6) and the second argument must be String. Type of the first argument: {}, type of the second argument: {}" ,
234+ getName (),
235+ addr_type->getName (),
236+ prefix_type->getName ());
157237
158- DataTypePtr getReturnTypeForDefaultImplementationForDynamic () const override
159- {
160238 return std::make_shared<DataTypeUInt8>();
161239 }
162240
@@ -180,69 +258,128 @@ namespace DB
180258 const ColumnConst & col_cidr_const,
181259 size_t input_rows_count)
182260 {
183- const auto & col_addr = col_addr_const.getDataColumn ();
184261 const auto & col_cidr = col_cidr_const.getDataColumn ();
185262
186- const auto addr = IPAddressVariant (col_addr. getDataAt ( 0 ). toView () );
263+ const auto addr = parseConstantIP (col_addr_const );
187264 const auto cidr = parseIPWithCIDR (col_cidr.getDataAt (0 ).toView ());
188265
189266 ColumnUInt8::MutablePtr col_res = ColumnUInt8::create (1 );
190267 ColumnUInt8::Container & vec_res = col_res->getData ();
191268
192- vec_res[0 ] = isAddressInRange (addr, cidr) ? 1 : 0 ;
269+ vec_res[0 ] = addr. has_value () && isAddressInRange (* addr, cidr) ? 1 : 0 ;
193270
194271 return ColumnConst::create (std::move (col_res), input_rows_count);
195272 }
196273
197274 // / Address is constant.
198275 static ColumnPtr executeImpl (const ColumnConst & col_addr_const, const IColumn & col_cidr, size_t input_rows_count)
199276 {
200- const auto & col_addr = col_addr_const. getDataColumn ( );
201-
202- const auto addr = IPAddressVariant (col_addr. getDataAt ( 0 ). toView () );
277+ const auto addr = parseConstantIP (col_addr_const );
278+ if (!addr. has_value ())
279+ return ColumnUInt8::create (input_rows_count, 0 );
203280
204281 ColumnUInt8::MutablePtr col_res = ColumnUInt8::create (input_rows_count);
205282 ColumnUInt8::Container & vec_res = col_res->getData ();
206283
207284 for (size_t i = 0 ; i < input_rows_count; ++i)
208285 {
209286 const auto cidr = parseIPWithCIDR (col_cidr.getDataAt (i).toView ());
287+ vec_res[i] = isAddressInRange (*addr, cidr) ? 1 : 0 ;
288+ }
289+ return col_res;
290+ }
291+
292+ template <IPKind kind>
293+ static ColumnPtr executeImpl (const IPTrait<kind>::ColumnType * col_addr, const IPAddressCIDR & cidr, size_t input_rows_count)
294+ {
295+ ColumnUInt8::MutablePtr col_res = ColumnUInt8::create (input_rows_count);
296+ ColumnUInt8::Container & vec_res = col_res->getData ();
297+
298+ for (size_t i = 0 ; i < input_rows_count; ++i)
299+ {
300+ const auto addr = parseIP<kind>(col_addr, i);
210301 vec_res[i] = isAddressInRange (addr, cidr) ? 1 : 0 ;
211302 }
212303 return col_res;
213304 }
214305
306+ template <IPKind kind>
307+ static ColumnPtr executeImpl (
308+ const IPTrait<kind>::ColumnType * col_addr,
309+ const ColumnNullable * nullable_column,
310+ const IPAddressCIDR & cidr,
311+ size_t input_rows_count)
312+ {
313+ ColumnUInt8::MutablePtr col_res = ColumnUInt8::create (input_rows_count);
314+ ColumnUInt8::Container & vec_res = col_res->getData ();
315+
316+ for (size_t i = 0 ; i < input_rows_count; ++i)
317+ {
318+ if (nullable_column->isNullAt (i))
319+ vec_res[i] = 0 ;
320+ else
321+ {
322+ const auto addr = parseIP<kind>(col_addr, i);
323+ vec_res[i] = isAddressInRange (addr, cidr) ? 1 : 0 ;
324+ }
325+ }
326+ return col_res;
327+ }
328+
329+ template <typename T>
330+ static ColumnPtr executeImpl (const IColumn & col_addr, const T & cidr, size_t input_rows_count)
331+ {
332+ EXEC_IMPL (col_addr, executeImpl, cidr, input_rows_count)
333+ else if (const auto * nullable_column = dynamic_cast <const ColumnNullable *>(&col_addr))
334+ {
335+ EXEC_IMPL (nullable_column->getNestedColumn (), executeImpl, nullable_column, cidr, input_rows_count)
336+ }
337+ throw Exception (ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, " The IP column type must be one of: String, IPv4, IPv6, Nullable(IPv4), Nullable(IPv6), or Nullable(String)." );
338+ }
339+
215340 // / CIDR is constant.
216341 static ColumnPtr executeImpl (const IColumn & col_addr, const ColumnConst & col_cidr_const, size_t input_rows_count)
217342 {
218- const auto & col_cidr = col_cidr_const.getDataColumn ( );
219-
220- const auto cidr = parseIPWithCIDR (col_cidr. getDataAt ( 0 ). toView ());
343+ const auto cidr = parseIPWithCIDR ( col_cidr_const.getDataAt ( 0 ). toView () );
344+ return executeImpl<IPAddressCIDR>(col_addr, cidr, input_rows_count);
345+ }
221346
347+ template <IPKind kind>
348+ static ColumnPtr executeImpl (const IPTrait<kind>::ColumnType * col_addr, const IColumn & col_cidr, size_t input_rows_count)
349+ {
222350 ColumnUInt8::MutablePtr col_res = ColumnUInt8::create (input_rows_count);
223351 ColumnUInt8::Container & vec_res = col_res->getData ();
352+
224353 for (size_t i = 0 ; i < input_rows_count; ++i)
225354 {
226- const auto addr = IPAddressVariant (col_addr.getDataAt (i).toView ());
355+ const auto addr = parseIP<kind>(col_addr, i);
356+ const auto cidr = parseIPWithCIDR (col_cidr.getDataAt (i).toView ());
227357 vec_res[i] = isAddressInRange (addr, cidr) ? 1 : 0 ;
228358 }
229359 return col_res;
230360 }
231361
232- // / Neither are constant.
233- static ColumnPtr executeImpl (const IColumn & col_addr, const IColumn & col_cidr, size_t input_rows_count)
362+ template <IPKind kind>
363+ static ColumnPtr executeImpl (
364+ const IPTrait<kind>::ColumnType * col_addr,
365+ const ColumnNullable * nullable_column,
366+ const IColumn & col_cidr,
367+ size_t input_rows_count)
234368 {
235369 ColumnUInt8::MutablePtr col_res = ColumnUInt8::create (input_rows_count);
236370 ColumnUInt8::Container & vec_res = col_res->getData ();
237371
238372 for (size_t i = 0 ; i < input_rows_count; ++i)
239373 {
240- const auto addr = IPAddressVariant (col_addr.getDataAt (i).toView ());
241374 const auto cidr = parseIPWithCIDR (col_cidr.getDataAt (i).toView ());
242-
243- vec_res[i] = isAddressInRange (addr, cidr) ? 1 : 0 ;
375+ if (nullable_column->isNullAt (i))
376+ vec_res[i] = 0 ;
377+ else
378+ {
379+ const auto addr = parseIP<kind>(col_addr, i);
380+ vec_res[i] = isAddressInRange (addr, cidr) ? 1 : 0 ;
381+ }
244382 }
245-
246383 return col_res;
247384 }
248385 };
0 commit comments