ClickHouse

Форк
0
/
FunctionsCodingIP.cpp 
1177 строк · 47.4 Кб
1
#include <functional>
2
#pragma clang diagnostic ignored "-Wreserved-identifier"
3

4
#include <Functions/FunctionsCodingIP.h>
5

6
#include <Columns/ColumnArray.h>
7
#include <Columns/ColumnConst.h>
8
#include <Columns/ColumnFixedString.h>
9
#include <Columns/ColumnString.h>
10
#include <Columns/ColumnTuple.h>
11
#include <Columns/ColumnsNumber.h>
12
#include <Columns/ColumnNullable.h>
13
#include <DataTypes/DataTypeDate.h>
14
#include <DataTypes/DataTypeFactory.h>
15
#include <DataTypes/DataTypeFixedString.h>
16
#include <DataTypes/DataTypeString.h>
17
#include <DataTypes/DataTypeTuple.h>
18
#include <DataTypes/DataTypesNumber.h>
19
#include <DataTypes/DataTypeIPv4andIPv6.h>
20
#include <Functions/FunctionFactory.h>
21
#include <Functions/FunctionHelpers.h>
22
#include <Functions/IFunction.h>
23
#include <Interpreters/Context.h>
24
#include <IO/WriteHelpers.h>
25
#include <Common/IPv6ToBinary.h>
26
#include <Common/formatIPv6.h>
27
#include <base/hex.h>
28
#include <Common/typeid_cast.h>
29

30
#include <arpa/inet.h>
31
#include <type_traits>
32
#include <array>
33

34

35
namespace DB
36
{
37

38
namespace ErrorCodes
39
{
40
    extern const int ILLEGAL_TYPE_OF_ARGUMENT;
41
    extern const int ILLEGAL_COLUMN;
42
}
43

44

45
/** Encoding functions for network addresses:
46
  *
47
  * IPv6NumToString (num) - See below.
48
  * IPv6StringToNum(string) - Convert, for example, '::1' to 1 and vice versa.
49
  */
50
class FunctionIPv6NumToString : public IFunction
51
{
52
public:
53
    static constexpr auto name = "IPv6NumToString";
54
    static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionIPv6NumToString>(); }
55

56
    String getName() const override { return name; }
57

58
    size_t getNumberOfArguments() const override { return 1; }
59
    bool isInjective(const ColumnsWithTypeAndName &) const override { return true; }
60
    bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
61

62
    DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
63
    {
64
        const auto * arg_string = checkAndGetDataType<DataTypeFixedString>(arguments[0].get());
65
        const auto * arg_ipv6 = checkAndGetDataType<DataTypeIPv6>(arguments[0].get());
66
        if (!arg_ipv6 && !(arg_string && arg_string->getN() == IPV6_BINARY_LENGTH))
67
            throw Exception(
68
                ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
69
                "Illegal type {} of argument of function {}, expected IPv6 or FixedString({})",
70
                arguments[0]->getName(), getName(), IPV6_BINARY_LENGTH
71
            );
72

73
        return std::make_shared<DataTypeString>();
74
    }
75

76
    bool useDefaultImplementationForConstants() const override { return true; }
77

78
    ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
79
    {
80
        const ColumnPtr & column = arguments[0].column;
81
        const auto * col_ipv6 = checkAndGetColumn<ColumnIPv6>(column.get());
82
        const auto * col_string = checkAndGetColumn<ColumnFixedString>(column.get());
83
        if (!col_ipv6 && !(col_string && col_string->getN() == IPV6_BINARY_LENGTH))
84
            throw Exception(
85
                ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
86
                "Illegal column {} of argument of function {}, expected IPv6 or FixedString({})",
87
                arguments[0].name, getName(), IPV6_BINARY_LENGTH
88
            );
89

90
        auto col_res = ColumnString::create();
91
        ColumnString::Chars & vec_res = col_res->getChars();
92
        ColumnString::Offsets & offsets_res = col_res->getOffsets();
93
        vec_res.resize(input_rows_count * (IPV6_MAX_TEXT_LENGTH + 1));
94
        offsets_res.resize(input_rows_count);
95

96
        auto * begin = reinterpret_cast<char *>(vec_res.data());
97
        auto * pos = begin;
98

99
        if (col_ipv6)
100
        {
101
            const auto & vec_in = col_ipv6->getData();
102

103
            for (size_t i = 0; i < input_rows_count; ++i)
104
            {
105
                formatIPv6(reinterpret_cast<const unsigned char *>(&vec_in[i]), pos);
106
                offsets_res[i] = pos - begin;
107
            }
108
        }
109
        else
110
        {
111
            const auto & vec_in = col_string->getChars();
112

113
            for (size_t i = 0; i < input_rows_count; ++i)
114
            {
115
                formatIPv6(reinterpret_cast<const unsigned char *>(&vec_in[i * IPV6_BINARY_LENGTH]), pos);
116
                offsets_res[i] = pos - begin;
117
            }
118
        }
119

120
        vec_res.resize(pos - begin);
121
        return col_res;
122
    }
123
};
124

125

126
class FunctionCutIPv6 : public IFunction
127
{
128
public:
129
    static constexpr auto name = "cutIPv6";
130
    static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionCutIPv6>(); }
131

132
    String getName() const override { return name; }
133

134
    size_t getNumberOfArguments() const override { return 3; }
135

136
    bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
137

138
    DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
139
    {
140
        if (!checkAndGetDataType<DataTypeIPv6>(arguments[0].get()))
141
        {
142
            const auto * ptr = checkAndGetDataType<DataTypeFixedString>(arguments[0].get());
143
            if (!ptr || ptr->getN() != IPV6_BINARY_LENGTH)
144
                throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
145
                                "Illegal type {} of argument 1 of function {}, expected FixedString({})",
146
                                arguments[0]->getName(), getName(), toString(IPV6_BINARY_LENGTH));
147
        }
148

149
        if (!WhichDataType(arguments[1]).isUInt8())
150
            throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type {} of argument 2 of function {}",
151
                            arguments[1]->getName(), getName());
152

153
        if (!WhichDataType(arguments[2]).isUInt8())
154
            throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type {} of argument 3 of function {}",
155
                            arguments[2]->getName(), getName());
156

157
        return std::make_shared<DataTypeString>();
158
    }
159

160
    bool useDefaultImplementationForConstants() const override { return true; }
161
    ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1, 2}; }
162

163
    ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
164
    {
165
        const auto & col_type_name = arguments[0];
166
        const ColumnPtr & column = col_type_name.column;
167

168
        const auto & col_ipv6_zeroed_tail_bytes_type = arguments[1];
169
        const auto & col_ipv6_zeroed_tail_bytes = col_ipv6_zeroed_tail_bytes_type.column;
170
        const auto & col_ipv4_zeroed_tail_bytes_type = arguments[2];
171
        const auto & col_ipv4_zeroed_tail_bytes = col_ipv4_zeroed_tail_bytes_type.column;
172

173
        const auto * col_in_str = checkAndGetColumn<ColumnFixedString>(column.get());
174
        const auto * col_in_ip = checkAndGetColumn<ColumnIPv6>(column.get());
175

176
        if (!col_in_str && !col_in_ip)
177
            throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of argument of function {}",
178
                            arguments[0].column->getName(), getName());
179

180
        if (col_in_str && col_in_str->getN() != IPV6_BINARY_LENGTH)
181
            throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
182
                            "Illegal type {} of column {} argument of function {}, expected FixedString({})",
183
                            col_type_name.type->getName(), col_in_str->getName(),
184
                            getName(), toString(IPV6_BINARY_LENGTH));
185

186
        const auto * ipv6_zeroed_tail_bytes = checkAndGetColumnConst<ColumnVector<UInt8>>(col_ipv6_zeroed_tail_bytes.get());
187
        if (!ipv6_zeroed_tail_bytes)
188
            throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type {} of argument 2 of function {}",
189
                            col_ipv6_zeroed_tail_bytes_type.type->getName(), getName());
190

191
        UInt8 ipv6_zeroed_tail_bytes_count = ipv6_zeroed_tail_bytes->getValue<UInt8>();
192
        if (ipv6_zeroed_tail_bytes_count > IPV6_BINARY_LENGTH)
193
            throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal value for argument 2 {} of function {}",
194
                            col_ipv6_zeroed_tail_bytes_type.type->getName(), getName());
195

196
        const auto * ipv4_zeroed_tail_bytes = checkAndGetColumnConst<ColumnVector<UInt8>>(col_ipv4_zeroed_tail_bytes.get());
197
        if (!ipv4_zeroed_tail_bytes)
198
            throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type {} of argument 3 of function {}",
199
                            col_ipv4_zeroed_tail_bytes_type.type->getName(), getName());
200

201
        UInt8 ipv4_zeroed_tail_bytes_count = ipv4_zeroed_tail_bytes->getValue<UInt8>();
202
        if (ipv4_zeroed_tail_bytes_count > IPV6_BINARY_LENGTH)
203
            throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal value for argument 3 {} of function {}",
204
                            col_ipv4_zeroed_tail_bytes_type.type->getName(), getName());
205

206
        auto col_res = ColumnString::create();
207
        ColumnString::Chars & vec_res = col_res->getChars();
208
        ColumnString::Offsets & offsets_res = col_res->getOffsets();
209
        vec_res.resize(input_rows_count * (IPV6_MAX_TEXT_LENGTH + 1));
210
        offsets_res.resize(input_rows_count);
211

212
        auto * begin = reinterpret_cast<char *>(vec_res.data());
213
        auto * pos = begin;
214

215
        if (col_in_str)
216
        {
217
            const auto & vec_in = col_in_str->getChars();
218

219
            for (size_t offset = 0, i = 0; i < input_rows_count; offset += IPV6_BINARY_LENGTH, ++i)
220
            {
221
                const auto * address = &vec_in[offset];
222
                UInt8 zeroed_tail_bytes_count = isIPv4Mapped(address) ? ipv4_zeroed_tail_bytes_count : ipv6_zeroed_tail_bytes_count;
223
                cutAddress(reinterpret_cast<const unsigned char *>(address), pos, zeroed_tail_bytes_count);
224
                offsets_res[i] = pos - begin;
225
            }
226
        }
227
        else
228
        {
229
            const auto & vec_in = col_in_ip->getData();
230

231
            for (size_t i = 0; i < input_rows_count; ++i)
232
            {
233
                const auto * address = reinterpret_cast<const UInt8 *>(&vec_in[i]);
234
                UInt8 zeroed_tail_bytes_count = isIPv4Mapped(address) ? ipv4_zeroed_tail_bytes_count : ipv6_zeroed_tail_bytes_count;
235
                cutAddress(reinterpret_cast<const unsigned char *>(address), pos, zeroed_tail_bytes_count);
236
                offsets_res[i] = pos - begin;
237
            }
238
        }
239

240
        vec_res.resize(pos - begin);
241

242
        return col_res;
243
    }
244

245
private:
246
    static bool isIPv4Mapped(const UInt8 * address)
247
    {
248
        return (unalignedLoadLittleEndian<UInt64>(address) == 0) &&
249
               ((unalignedLoadLittleEndian<UInt64>(address + 8) & 0x00000000FFFFFFFFull) == 0x00000000FFFF0000ull);
250
    }
251

252
    static void cutAddress(const unsigned char * address, char *& dst, UInt8 zeroed_tail_bytes_count)
253
    {
254
        formatIPv6(address, dst, zeroed_tail_bytes_count);
255
    }
256
};
257

258
template <IPStringToNumExceptionMode exception_mode>
259
class FunctionIPv6StringToNum : public IFunction
260
{
261
public:
262
    static constexpr auto name = exception_mode == IPStringToNumExceptionMode::Throw
263
        ? "IPv6StringToNum"
264
        : (exception_mode == IPStringToNumExceptionMode::Default ? "IPv6StringToNumOrDefault" : "IPv6StringToNumOrNull");
265

266
    static FunctionPtr create(ContextPtr context) { return std::make_shared<FunctionIPv6StringToNum>(context); }
267

268
    explicit FunctionIPv6StringToNum(ContextPtr context)
269
        : cast_ipv4_ipv6_default_on_conversion_error(context->getSettingsRef().cast_ipv4_ipv6_default_on_conversion_error)
270
    {
271
    }
272

273
    String getName() const override { return name; }
274

275
    size_t getNumberOfArguments() const override { return 1; }
276

277
    bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
278

279
    bool useDefaultImplementationForConstants() const override { return true; }
280

281
    bool useDefaultImplementationForNulls() const override { return false; }
282

283
    DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
284
    {
285
        if (!isStringOrFixedString(removeNullable(arguments[0])))
286
        {
287
            throw Exception(
288
                ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type {} of argument of function {}", arguments[0]->getName(), getName());
289
        }
290

291
        auto result_type = std::make_shared<DataTypeFixedString>(IPV6_BINARY_LENGTH);
292

293
        if constexpr (exception_mode == IPStringToNumExceptionMode::Null)
294
        {
295
            return makeNullable(result_type);
296
        }
297

298
        return arguments[0]->isNullable() ? makeNullable(result_type) : result_type;
299
    }
300

301
    ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t /*input_rows_count*/) const override
302
    {
303
        ColumnPtr column = arguments[0].column;
304
        ColumnPtr null_map_column;
305
        const NullMap * null_map = nullptr;
306
        if (column->isNullable())
307
        {
308
            const auto * column_nullable = assert_cast<const ColumnNullable *>(column.get());
309
            column = column_nullable->getNestedColumnPtr();
310
            null_map_column = column_nullable->getNullMapColumnPtr();
311
            null_map = &column_nullable->getNullMapData();
312
        }
313

314
        if constexpr (exception_mode == IPStringToNumExceptionMode::Throw)
315
        {
316
            if (cast_ipv4_ipv6_default_on_conversion_error)
317
            {
318
                auto result = convertToIPv6<IPStringToNumExceptionMode::Default, ColumnFixedString>(column, null_map);
319
                if (null_map && !result->isNullable())
320
                    return ColumnNullable::create(result, null_map_column);
321
                return result;
322
            }
323
        }
324

325
        auto result = convertToIPv6<exception_mode, ColumnFixedString>(column, null_map);
326
        if (null_map && !result->isNullable())
327
            return ColumnNullable::create(IColumn::mutate(result), IColumn::mutate(null_map_column));
328
        return result;
329
    }
330

331
private:
332
    bool cast_ipv4_ipv6_default_on_conversion_error = false;
333
};
334

335

336
/** If mask_tail_octets > 0, the last specified number of octets will be filled with "xxx".
337
  */
338
template <size_t mask_tail_octets, typename Name>
339
class FunctionIPv4NumToString : public IFunction
340
{
341
private:
342
    template <typename ArgType>
343
    ColumnPtr executeTyped(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t /*input_rows_count*/) const
344
    {
345
        using ColumnType = ColumnVector<ArgType>;
346

347
        const ColumnPtr & column = arguments[0].column;
348

349
        if (const ColumnType * col = typeid_cast<const ColumnType *>(column.get()))
350
        {
351
            const typename ColumnType::Container & vec_in = col->getData();
352

353
            auto col_res = ColumnString::create();
354

355
            ColumnString::Chars & vec_res = col_res->getChars();
356
            ColumnString::Offsets & offsets_res = col_res->getOffsets();
357

358
            vec_res.resize(vec_in.size() * (IPV4_MAX_TEXT_LENGTH + 1)); /// the longest value is: 255.255.255.255\0
359
            offsets_res.resize(vec_in.size());
360
            char * begin = reinterpret_cast<char *>(vec_res.data());
361
            char * pos = begin;
362

363
            for (size_t i = 0; i < vec_in.size(); ++i)
364
            {
365
                DB::formatIPv4(reinterpret_cast<const unsigned char*>(&vec_in[i]), sizeof(ArgType), pos, mask_tail_octets, "xxx");
366
                offsets_res[i] = pos - begin;
367
            }
368

369
            vec_res.resize(pos - begin);
370

371
            return col_res;
372
        }
373
        else
374
            throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of argument of function {}",
375
                            arguments[0].column->getName(), getName());
376
    }
377
public:
378
    static constexpr auto name = Name::name;
379
    static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionIPv4NumToString<mask_tail_octets, Name>>(); }
380

381
    String getName() const override
382
    {
383
        return name;
384
    }
385

386
    size_t getNumberOfArguments() const override { return 1; }
387
    bool isInjective(const ColumnsWithTypeAndName &) const override { return mask_tail_octets == 0; }
388
    bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
389

390
    DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
391
    {
392
        WhichDataType arg_type(arguments[0]);
393
        if (!(arg_type.isIPv4() || arg_type.isUInt8() || arg_type.isUInt16() || arg_type.isUInt32()))
394
            throw Exception(
395
                ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
396
                "Illegal type {} of first argument of function {}, expected IPv4 or UInt8 or UInt16 or UInt32",
397
                arguments[0]->getName(), getName()
398
            );
399

400
        return std::make_shared<DataTypeString>();
401
    }
402

403
    bool useDefaultImplementationForConstants() const override { return true; }
404

405
    ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & ret_type, size_t input_rows_count) const override
406
    {
407

408
        switch (arguments[0].type->getTypeId())
409
        {
410
            case TypeIndex::IPv4: return executeTyped<IPv4>(arguments, ret_type, input_rows_count);
411
            case TypeIndex::UInt8: return executeTyped<UInt8>(arguments, ret_type, input_rows_count);
412
            case TypeIndex::UInt16: return executeTyped<UInt16>(arguments, ret_type, input_rows_count);
413
            case TypeIndex::UInt32: return executeTyped<UInt32>(arguments, ret_type, input_rows_count);
414
            default: break;
415
        }
416

417
        throw Exception(
418
            ErrorCodes::ILLEGAL_COLUMN,
419
            "Illegal column {} of argument of function {}, expected IPv4 or UInt8 or UInt16 or UInt32",
420
            arguments[0].column->getName(), getName()
421
        );
422
    }
423
};
424

425
template <IPStringToNumExceptionMode exception_mode>
426
class FunctionIPv4StringToNum : public IFunction
427
{
428
public:
429
    static constexpr auto name = exception_mode == IPStringToNumExceptionMode::Throw
430
        ? "IPv4StringToNum"
431
        : (exception_mode == IPStringToNumExceptionMode::Default ? "IPv4StringToNumOrDefault" : "IPv4StringToNumOrNull");
432

433
    static FunctionPtr create(ContextPtr context) { return std::make_shared<FunctionIPv4StringToNum>(context); }
434

435
    explicit FunctionIPv4StringToNum(ContextPtr context)
436
        : cast_ipv4_ipv6_default_on_conversion_error(context->getSettingsRef().cast_ipv4_ipv6_default_on_conversion_error)
437
    {
438
    }
439

440
    String getName() const override { return name; }
441

442
    size_t getNumberOfArguments() const override { return 1; }
443

444
    bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
445

446
    bool useDefaultImplementationForConstants() const override { return true; }
447

448
    bool useDefaultImplementationForNulls() const override { return false; }
449

450
    DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
451
    {
452
        if (!isString(removeNullable(arguments[0])))
453
        {
454
            throw Exception(
455
                ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type {} of argument of function {}", arguments[0]->getName(), getName());
456
        }
457

458
        auto result_type = std::make_shared<DataTypeUInt32>();
459

460
        if constexpr (exception_mode == IPStringToNumExceptionMode::Null)
461
        {
462
            return makeNullable(result_type);
463
        }
464

465
        return arguments[0]->isNullable() ? makeNullable(result_type) : result_type;
466
    }
467

468
    ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t /*input_rows_count*/) const override
469
    {
470
        ColumnPtr column = arguments[0].column;
471
        ColumnPtr null_map_column;
472
        const NullMap * null_map = nullptr;
473
        if (column->isNullable())
474
        {
475
            const auto * column_nullable = assert_cast<const ColumnNullable *>(column.get());
476
            column = column_nullable->getNestedColumnPtr();
477
            null_map_column = column_nullable->getNullMapColumnPtr();
478
            null_map = &column_nullable->getNullMapData();
479
        }
480

481
        if constexpr (exception_mode == IPStringToNumExceptionMode::Throw)
482
        {
483
            if (cast_ipv4_ipv6_default_on_conversion_error)
484
            {
485
                auto result = convertToIPv4<IPStringToNumExceptionMode::Default, ColumnUInt32>(column, null_map);
486
                if (null_map && !result->isNullable())
487
                    return ColumnNullable::create(result, null_map_column);
488
                return result;
489
            }
490
        }
491

492
        auto result = convertToIPv4<exception_mode, ColumnUInt32>(column, null_map);
493
        if (null_map && !result->isNullable())
494
            return ColumnNullable::create(IColumn::mutate(result), IColumn::mutate(null_map_column));
495
        return result;
496
    }
497

498
private:
499
    bool cast_ipv4_ipv6_default_on_conversion_error = false;
500
};
501

502

503
class FunctionIPv4ToIPv6 : public IFunction
504
{
505
public:
506
    static constexpr auto name = "IPv4ToIPv6";
507
    static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionIPv4ToIPv6>(); }
508

509
    String getName() const override { return name; }
510

511
    size_t getNumberOfArguments() const override { return 1; }
512
    bool isInjective(const ColumnsWithTypeAndName &) const override { return true; }
513
    bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
514

515
    /// for backward compatibility IPv4ToIPv6 is overloaded, and result type depends on type of argument -
516
    ///   if it is UInt32 (presenting IPv4) then result is FixedString(16), if IPv4 - result is IPv6
517
    DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
518
    {
519
        const auto * dt_uint32 = checkAndGetDataType<DataTypeUInt32>(arguments[0].get());
520
        const auto * dt_ipv4 = checkAndGetDataType<DataTypeIPv4>(arguments[0].get());
521
        if (!dt_uint32 && !dt_ipv4)
522
            throw Exception(
523
                ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
524
                "Illegal type {} of argument of function {}", arguments[0]->getName(), getName()
525
            );
526

527
        if (dt_uint32)
528
            return std::make_shared<DataTypeFixedString>(16);
529
        return std::make_shared<DataTypeIPv6>();
530
    }
531

532
    bool useDefaultImplementationForConstants() const override { return true; }
533

534
    ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t /*input_rows_count*/) const override
535
    {
536
        const auto & col_type_name = arguments[0];
537
        const ColumnPtr & column = col_type_name.column;
538

539
        if (const auto * col_in = checkAndGetColumn<ColumnIPv4>(*column))
540
        {
541
            auto col_res = ColumnIPv6::create();
542

543
            auto & vec_res = col_res->getData();
544
            vec_res.resize(col_in->size());
545

546
            const auto & vec_in = col_in->getData();
547

548
            for (size_t i = 0; i < vec_res.size(); ++i)
549
                mapIPv4ToIPv6(vec_in[i], reinterpret_cast<UInt8 *>(&vec_res[i].toUnderType()));
550

551
            return col_res;
552
        }
553

554
        if (const auto * col_in = checkAndGetColumn<ColumnUInt32>(*column))
555
        {
556
            auto col_res = ColumnFixedString::create(IPV6_BINARY_LENGTH);
557

558
            auto & vec_res = col_res->getChars();
559
            vec_res.resize(col_in->size() * IPV6_BINARY_LENGTH);
560

561
            const auto & vec_in = col_in->getData();
562

563
            for (size_t out_offset = 0, i = 0; out_offset < vec_res.size(); out_offset += IPV6_BINARY_LENGTH, ++i)
564
                mapIPv4ToIPv6(vec_in[i], &vec_res[out_offset]);
565

566
            return col_res;
567
        }
568

569
        throw Exception(
570
            ErrorCodes::ILLEGAL_COLUMN,
571
            "Illegal column {} of argument of function {}", arguments[0].column->getName(), getName()
572
        );
573
    }
574

575
private:
576
    static void mapIPv4ToIPv6(UInt32 in, UInt8 * buf)
577
    {
578
        unalignedStore<UInt64>(buf, 0);
579

580
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
581
            unalignedStoreLittleEndian<UInt64>(buf + 8, 0x00000000FFFF0000ull | (static_cast<UInt64>(ntohl(in)) << 32));
582
#else
583
            unalignedStoreLittleEndian<UInt64>(buf + 8, 0x00000000FFFF0000ull | (static_cast<UInt64>(std::byteswap(in)) << 32));
584
#endif
585
    }
586
};
587

588
class FunctionMACNumToString : public IFunction
589
{
590
public:
591
    static constexpr auto name = "MACNumToString";
592
    static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionMACNumToString>(); }
593

594
    String getName() const override
595
    {
596
        return name;
597
    }
598

599
    size_t getNumberOfArguments() const override { return 1; }
600
    bool isInjective(const ColumnsWithTypeAndName &) const override { return true; }
601
    bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
602

603
    DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
604
    {
605
        if (!WhichDataType(arguments[0]).isUInt64())
606
            throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type {} of argument of function {}, expected UInt64",
607
                            arguments[0]->getName(), getName());
608

609
        return std::make_shared<DataTypeString>();
610
    }
611

612
    static void formatMAC(UInt64 mac, UInt8 * out)
613
    {
614
        /// MAC address is represented in UInt64 in natural order (so, MAC addresses are compared in same order as UInt64).
615
        /// Higher two bytes in UInt64 are just ignored.
616

617
        writeHexByteUppercase(mac >> 40, &out[0]);
618
        out[2] = ':';
619
        writeHexByteUppercase(mac >> 32, &out[3]);
620
        out[5] = ':';
621
        writeHexByteUppercase(mac >> 24, &out[6]);
622
        out[8] = ':';
623
        writeHexByteUppercase(mac >> 16, &out[9]);
624
        out[11] = ':';
625
        writeHexByteUppercase(mac >> 8, &out[12]);
626
        out[14] = ':';
627
        writeHexByteUppercase(mac, &out[15]);
628
        out[17] = '\0';
629
    }
630

631
    bool useDefaultImplementationForConstants() const override { return true; }
632

633
    ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t /*input_rows_count*/) const override
634
    {
635
        const ColumnPtr & column = arguments[0].column;
636

637
        if (const ColumnUInt64 * col = typeid_cast<const ColumnUInt64 *>(column.get()))
638
        {
639
            const ColumnUInt64::Container & vec_in = col->getData();
640

641
            auto col_res = ColumnString::create();
642

643
            ColumnString::Chars & vec_res = col_res->getChars();
644
            ColumnString::Offsets & offsets_res = col_res->getOffsets();
645

646
            vec_res.resize(vec_in.size() * 18); /// the value is: xx:xx:xx:xx:xx:xx\0
647
            offsets_res.resize(vec_in.size());
648

649
            size_t current_offset = 0;
650
            for (size_t i = 0; i < vec_in.size(); ++i)
651
            {
652
                formatMAC(vec_in[i], &vec_res[current_offset]);
653
                current_offset += 18;
654
                offsets_res[i] = current_offset;
655
            }
656

657
            return col_res;
658
        }
659
        else
660
            throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of argument of function {}",
661
                            arguments[0].column->getName(), getName());
662
    }
663
};
664

665

666
struct ParseMACImpl
667
{
668
    static constexpr size_t min_string_size = 17;
669
    static constexpr size_t max_string_size = 17;
670

671
    /** Example: 01:02:03:04:05:06.
672
      * There could be any separators instead of : and them are just ignored.
673
      * The order of resulting integers are correspond to the order of MAC address.
674
      * If there are any chars other than valid hex digits for bytes, the behaviour is implementation specific.
675
      */
676
    static UInt64 parse(const char * pos)
677
    {
678
        return (static_cast<UInt64>(unhex(pos[0])) << 44)
679
               | (static_cast<UInt64>(unhex(pos[1])) << 40)
680
               | (static_cast<UInt64>(unhex(pos[3])) << 36)
681
               | (static_cast<UInt64>(unhex(pos[4])) << 32)
682
               | (static_cast<UInt64>(unhex(pos[6])) << 28)
683
               | (static_cast<UInt64>(unhex(pos[7])) << 24)
684
               | (static_cast<UInt64>(unhex(pos[9])) << 20)
685
               | (static_cast<UInt64>(unhex(pos[10])) << 16)
686
               | (static_cast<UInt64>(unhex(pos[12])) << 12)
687
               | (static_cast<UInt64>(unhex(pos[13])) << 8)
688
               | (static_cast<UInt64>(unhex(pos[15])) << 4)
689
               | (static_cast<UInt64>(unhex(pos[16])));
690
    }
691

692
    static constexpr auto name = "MACStringToNum";
693
};
694

695
struct ParseOUIImpl
696
{
697
    static constexpr size_t min_string_size = 8;
698
    static constexpr size_t max_string_size = 17;
699

700
    /** OUI is the first three bytes of MAC address.
701
      * Example: 01:02:03.
702
      */
703
    static UInt64 parse(const char * pos)
704
    {
705
        return (static_cast<UInt64>(unhex(pos[0])) << 20)
706
               | (static_cast<UInt64>(unhex(pos[1])) << 16)
707
               | (static_cast<UInt64>(unhex(pos[3])) << 12)
708
               | (static_cast<UInt64>(unhex(pos[4])) << 8)
709
               | (static_cast<UInt64>(unhex(pos[6])) << 4)
710
               | (static_cast<UInt64>(unhex(pos[7])));
711
    }
712

713
    static constexpr auto name = "MACStringToOUI";
714
};
715

716

717
template <typename Impl>
718
class FunctionMACStringTo : public IFunction
719
{
720
public:
721
    static constexpr auto name = Impl::name;
722
    static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionMACStringTo<Impl>>(); }
723

724
    String getName() const override
725
    {
726
        return name;
727
    }
728

729
    size_t getNumberOfArguments() const override { return 1; }
730

731
    bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
732

733
    DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
734
    {
735
        if (!isString(arguments[0]))
736
            throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type {} of argument of function {}",
737
                            arguments[0]->getName(), getName());
738

739
        return std::make_shared<DataTypeUInt64>();
740
    }
741

742
    bool useDefaultImplementationForConstants() const override { return true; }
743

744
    ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t /*input_rows_count*/) const override
745
    {
746
        const ColumnPtr & column = arguments[0].column;
747

748
        if (const ColumnString * col = checkAndGetColumn<ColumnString>(column.get()))
749
        {
750
            auto col_res = ColumnUInt64::create();
751

752
            ColumnUInt64::Container & vec_res = col_res->getData();
753
            vec_res.resize(col->size());
754

755
            const ColumnString::Chars & vec_src = col->getChars();
756
            const ColumnString::Offsets & offsets_src = col->getOffsets();
757
            size_t prev_offset = 0;
758

759
            for (size_t i = 0; i < vec_res.size(); ++i)
760
            {
761
                size_t current_offset = offsets_src[i];
762
                size_t string_size = current_offset - prev_offset - 1; /// mind the terminating zero byte
763

764
                if (string_size >= Impl::min_string_size && string_size <= Impl::max_string_size)
765
                    vec_res[i] = Impl::parse(reinterpret_cast<const char *>(&vec_src[prev_offset]));
766
                else
767
                    vec_res[i] = 0;
768

769
                prev_offset = current_offset;
770
            }
771

772
            return col_res;
773
        }
774
        else
775
            throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of argument of function {}",
776
                            arguments[0].column->getName(), getName());
777
    }
778
};
779

780
class FunctionIPv6CIDRToRange : public IFunction
781
{
782
private:
783

784
#if defined(__SSE2__)
785

786
#include <emmintrin.h>
787

788
    static inline void applyCIDRMask(const char * __restrict src, char * __restrict dst_lower, char * __restrict dst_upper, UInt8 bits_to_keep)
789
    {
790
        __m128i mask = _mm_loadu_si128(reinterpret_cast<const __m128i *>(getCIDRMaskIPv6(bits_to_keep).data()));
791
        __m128i lower = _mm_and_si128(_mm_loadu_si128(reinterpret_cast<const __m128i *>(src)), mask);
792
        _mm_storeu_si128(reinterpret_cast<__m128i *>(dst_lower), lower);
793

794
        __m128i inv_mask = _mm_xor_si128(mask, _mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128()));
795
        __m128i upper = _mm_or_si128(lower, inv_mask);
796
        _mm_storeu_si128(reinterpret_cast<__m128i *>(dst_upper), upper);
797
    }
798

799
#else
800

801
    /// NOTE IPv6 is stored in memory in big endian format that makes some difficulties.
802
    static void applyCIDRMask(const char * __restrict src, char * __restrict dst_lower, char * __restrict dst_upper, UInt8 bits_to_keep)
803
    {
804
        const auto & mask = getCIDRMaskIPv6(bits_to_keep);
805

806
        for (size_t i = 0; i < 16; ++i)
807
        {
808
            dst_lower[i] = src[i] & mask[i];
809
            dst_upper[i] = dst_lower[i] | ~mask[i];
810
        }
811
    }
812

813
#endif
814

815
public:
816
    static constexpr auto name = "IPv6CIDRToRange";
817
    static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionIPv6CIDRToRange>(); }
818

819
    String getName() const override { return name; }
820
    size_t getNumberOfArguments() const override { return 2; }
821
    bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
822

823
    DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
824
    {
825
        const auto * ipv6 = checkAndGetDataType<DataTypeIPv6>(arguments[0].get());
826
        const auto * str = checkAndGetDataType<DataTypeFixedString>(arguments[0].get());
827
        if (!ipv6 && !(str && str->getN() == IPV6_BINARY_LENGTH))
828
            throw Exception(
829
                ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
830
                "Illegal type {} of first argument of function {}, expected IPv6 or FixedString({})",
831
                arguments[0]->getName(), getName(), IPV6_BINARY_LENGTH
832
            );
833

834
        const DataTypePtr & second_argument = arguments[1];
835
        if (!isUInt8(second_argument))
836
            throw Exception(
837
                ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
838
                "Illegal type {} of second argument of function {}, expected UInt8",
839
                second_argument->getName(), getName()
840
            );
841

842
        DataTypePtr element = std::make_shared<DataTypeIPv6>();
843
        return std::make_shared<DataTypeTuple>(DataTypes{element, element});
844
    }
845

846
    bool useDefaultImplementationForConstants() const override { return true; }
847

848

849
    ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
850
    {
851
        const auto & col_type_name_cidr = arguments[1];
852
        const ColumnPtr & column_cidr = col_type_name_cidr.column;
853

854
        const auto * col_const_cidr_in = checkAndGetColumnConst<ColumnUInt8>(column_cidr.get());
855
        const auto * col_cidr_in = checkAndGetColumn<ColumnUInt8>(column_cidr.get());
856

857
        if (!col_const_cidr_in && !col_cidr_in)
858
            throw Exception(
859
                ErrorCodes::ILLEGAL_COLUMN,
860
                "Illegal column {} of argument of function {}",
861
                arguments[1].column->getName(), getName()
862
            );
863

864
        const auto & col_type_name_ip = arguments[0];
865
        const ColumnPtr & column_ip = col_type_name_ip.column;
866

867
        const auto * col_const_ip_in = checkAndGetColumnConst<ColumnIPv6>(column_ip.get());
868
        const auto * col_ip_in = checkAndGetColumn<ColumnIPv6>(column_ip.get());
869

870
        const auto * col_const_str_in = checkAndGetColumnConst<ColumnFixedString>(column_ip.get());
871
        const auto * col_str_in = checkAndGetColumn<ColumnFixedString>(column_ip.get());
872

873
        std::function<const char *(size_t)> get_ip_data;
874
        if (col_const_ip_in)
875
            get_ip_data = [col_const_ip_in](size_t) { return col_const_ip_in->getDataAt(0).data; };
876
        else if (col_const_str_in)
877
            get_ip_data = [col_const_str_in](size_t) { return col_const_str_in->getDataAt(0).data; };
878
        else if (col_ip_in)
879
            get_ip_data = [col_ip_in](size_t i) { return reinterpret_cast<const char *>(&col_ip_in->getData()[i]); };
880
        else if (col_str_in)
881
            get_ip_data = [col_str_in](size_t i) { return reinterpret_cast<const char *>(&col_str_in->getChars().data()[i * IPV6_BINARY_LENGTH]); };
882
        else
883
            throw Exception(
884
                ErrorCodes::ILLEGAL_COLUMN,
885
                "Illegal column {} of argument of function {}",
886
                arguments[0].column->getName(), getName()
887
            );
888

889
        auto col_res_lower_range = ColumnIPv6::create();
890
        auto col_res_upper_range = ColumnIPv6::create();
891

892
        auto & vec_res_lower_range = col_res_lower_range->getData();
893
        vec_res_lower_range.resize(input_rows_count);
894

895
        auto & vec_res_upper_range = col_res_upper_range->getData();
896
        vec_res_upper_range.resize(input_rows_count);
897

898
        static constexpr UInt8 max_cidr_mask = IPV6_BINARY_LENGTH * 8;
899

900
        for (size_t i = 0; i < input_rows_count; ++i)
901
        {
902
            UInt8 cidr = col_const_cidr_in
903
                        ? col_const_cidr_in->getValue<UInt8>()
904
                        : col_cidr_in->getData()[i];
905

906
            cidr = std::min(cidr, max_cidr_mask);
907

908
            applyCIDRMask(get_ip_data(i), reinterpret_cast<char *>(&vec_res_lower_range[i]), reinterpret_cast<char *>(&vec_res_upper_range[i]), cidr);
909
        }
910

911
        return ColumnTuple::create(Columns{std::move(col_res_lower_range), std::move(col_res_upper_range)});
912
    }
913
};
914

915

916
class FunctionIPv4CIDRToRange : public IFunction
917
{
918
private:
919
    static inline std::pair<UInt32, UInt32> applyCIDRMask(UInt32 src, UInt8 bits_to_keep)
920
    {
921
        if (bits_to_keep >= 8 * sizeof(UInt32))
922
            return { src, src };
923
        if (bits_to_keep == 0)
924
            return { static_cast<UInt32>(0), static_cast<UInt32>(-1) };
925

926
        UInt32 mask = static_cast<UInt32>(-1) << (8 * sizeof(UInt32) - bits_to_keep);
927
        UInt32 lower = src & mask;
928
        UInt32 upper = lower | ~mask;
929

930
        return { lower, upper };
931
    }
932

933
    template <typename ArgType>
934
    ColumnPtr executeTyped(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const
935
    {
936
        using ColumnType = ColumnVector<ArgType>;
937
        const auto & col_type_name_ip = arguments[0];
938
        const ColumnPtr & column_ip = col_type_name_ip.column;
939

940
        const auto * col_const_ip_in = checkAndGetColumnConst<ColumnType>(column_ip.get());
941
        const auto * col_ip_in = checkAndGetColumn<ColumnType>(column_ip.get());
942

943
        const auto & col_type_name_cidr = arguments[1];
944
        const ColumnPtr & column_cidr = col_type_name_cidr.column;
945

946
        const auto * col_const_cidr_in = checkAndGetColumnConst<ColumnUInt8>(column_cidr.get());
947
        const auto * col_cidr_in = checkAndGetColumn<ColumnUInt8>(column_cidr.get());
948

949
        auto col_res_lower_range = ColumnIPv4::create();
950
        auto col_res_upper_range = ColumnIPv4::create();
951

952
        auto & vec_res_lower_range = col_res_lower_range->getData();
953
        vec_res_lower_range.resize(input_rows_count);
954

955
        auto & vec_res_upper_range = col_res_upper_range->getData();
956
        vec_res_upper_range.resize(input_rows_count);
957

958
        for (size_t i = 0; i < input_rows_count; ++i)
959
        {
960
            ArgType ip = col_const_ip_in
961
                        ? col_const_ip_in->template getValue<ArgType>()
962
                        : col_ip_in->getData()[i];
963

964
            UInt8 cidr = col_const_cidr_in
965
                         ? col_const_cidr_in->getValue<UInt8>()
966
                         : col_cidr_in->getData()[i];
967

968
            std::tie(vec_res_lower_range[i], vec_res_upper_range[i]) = applyCIDRMask(ip, cidr);
969
        }
970

971
        return ColumnTuple::create(Columns{std::move(col_res_lower_range), std::move(col_res_upper_range)});
972
    }
973

974
public:
975
    static constexpr auto name = "IPv4CIDRToRange";
976
    static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionIPv4CIDRToRange>(); }
977

978
    String getName() const override { return name; }
979
    size_t getNumberOfArguments() const override { return 2; }
980
    bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
981

982
    DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
983
    {
984
        WhichDataType arg_type(arguments[0]);
985
        if (!(arg_type.isIPv4() || arg_type.isUInt8() || arg_type.isUInt16() || arg_type.isUInt32()))
986
            throw Exception(
987
                ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
988
                "Illegal type {} of first argument of function {}, expected IPv4 or UInt8 or UInt16 or UInt32",
989
                arguments[0]->getName(), getName()
990
            );
991

992

993
        const DataTypePtr & second_argument = arguments[1];
994
        if (!isUInt8(second_argument))
995
            throw Exception(
996
                ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
997
                "Illegal type {} of second argument of function {}, expected UInt8",
998
                second_argument->getName(), getName()
999
            );
1000

1001
        DataTypePtr element = DataTypeFactory::instance().get("IPv4");
1002
        return std::make_shared<DataTypeTuple>(DataTypes{element, element});
1003
    }
1004

1005
    bool useDefaultImplementationForConstants() const override { return true; }
1006

1007

1008
    ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & ret_type, size_t input_rows_count) const override
1009
    {
1010
        if (arguments[1].type->getTypeId() != TypeIndex::UInt8)
1011
            throw Exception(
1012
                ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
1013
                "Illegal type {} of second argument of function {}, expected UInt8", arguments[1].type->getName(), getName()
1014
            );
1015

1016
        switch (arguments[0].type->getTypeId())
1017
        {
1018
            case TypeIndex::IPv4: return executeTyped<IPv4>(arguments, ret_type, input_rows_count);
1019
            case TypeIndex::UInt8: return executeTyped<UInt8>(arguments, ret_type, input_rows_count);
1020
            case TypeIndex::UInt16: return executeTyped<UInt16>(arguments, ret_type, input_rows_count);
1021
            case TypeIndex::UInt32: return executeTyped<UInt32>(arguments, ret_type, input_rows_count);
1022
            default: break;
1023
        }
1024

1025
        throw Exception(
1026
            ErrorCodes::ILLEGAL_COLUMN,
1027
            "Illegal column {} of argument of function {}, expected IPv4 or UInt8 or UInt16 or UInt32",
1028
            arguments[0].column->getName(), getName()
1029
        );
1030
    }
1031
};
1032

1033
class FunctionIsIPv4String : public IFunction
1034
{
1035
public:
1036
    static constexpr auto name = "isIPv4String";
1037

1038
    static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionIsIPv4String>(); }
1039

1040
    String getName() const override { return name; }
1041

1042
    size_t getNumberOfArguments() const override { return 1; }
1043

1044
    bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
1045

1046
    bool useDefaultImplementationForConstants() const override { return true; }
1047

1048
    DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
1049
    {
1050
        if (!isString(arguments[0]))
1051
            throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type {} of argument of function {}",
1052
                arguments[0]->getName(), getName());
1053
        return std::make_shared<DataTypeUInt8>();
1054
    }
1055

1056
    ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t /*input_rows_count*/) const override
1057
    {
1058
        const ColumnString * input_column = checkAndGetColumn<ColumnString>(arguments[0].column.get());
1059

1060
        if (!input_column)
1061
        {
1062
            throw Exception(
1063
                ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of argument of function {}", arguments[0].column->getName(), getName());
1064
        }
1065

1066
        auto col_res = ColumnUInt8::create();
1067

1068
        ColumnUInt8::Container & vec_res = col_res->getData();
1069
        vec_res.resize(input_column->size());
1070

1071
        const ColumnString::Chars & vec_src = input_column->getChars();
1072
        const ColumnString::Offsets & offsets_src = input_column->getOffsets();
1073
        size_t prev_offset = 0;
1074
        UInt32 result = 0;
1075

1076
        for (size_t i = 0; i < vec_res.size(); ++i)
1077
        {
1078
            vec_res[i] = DB::parseIPv4whole(reinterpret_cast<const char *>(&vec_src[prev_offset]), reinterpret_cast<unsigned char *>(&result));
1079
            prev_offset = offsets_src[i];
1080
        }
1081

1082
        return col_res;
1083
    }
1084
};
1085

1086
class FunctionIsIPv6String : public IFunction
1087
{
1088
public:
1089
    static constexpr auto name = "isIPv6String";
1090

1091
    static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionIsIPv6String>(); }
1092

1093
    String getName() const override { return name; }
1094

1095
    size_t getNumberOfArguments() const override { return 1; }
1096

1097
    bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
1098

1099
    bool useDefaultImplementationForConstants() const override { return true; }
1100

1101
    DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
1102
    {
1103
        if (!isString(arguments[0]))
1104
        {
1105
            throw Exception(
1106
                ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type {} of argument of function {}", arguments[0]->getName(), getName());
1107
        }
1108

1109
        return std::make_shared<DataTypeUInt8>();
1110
    }
1111

1112
    ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t /*input_rows_count*/) const override
1113
    {
1114
        const ColumnString * input_column = checkAndGetColumn<ColumnString>(arguments[0].column.get());
1115
        if (!input_column)
1116
        {
1117
            throw Exception(
1118
                ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of argument of function {}", arguments[0].column->getName(), getName());
1119
        }
1120

1121
        auto col_res = ColumnUInt8::create();
1122

1123
        ColumnUInt8::Container & vec_res = col_res->getData();
1124
        vec_res.resize(input_column->size());
1125

1126
        const ColumnString::Chars & vec_src = input_column->getChars();
1127
        const ColumnString::Offsets & offsets_src = input_column->getOffsets();
1128
        size_t prev_offset = 0;
1129
        char buffer[IPV6_BINARY_LENGTH];
1130

1131
        for (size_t i = 0; i < vec_res.size(); ++i)
1132
        {
1133
            vec_res[i] = DB::parseIPv6whole(reinterpret_cast<const char *>(&vec_src[prev_offset]),
1134
                                            reinterpret_cast<const char *>(&vec_src[offsets_src[i] - 1]),
1135
                                            reinterpret_cast<unsigned char *>(buffer));
1136
            prev_offset = offsets_src[i];
1137
        }
1138

1139
        return col_res;
1140
    }
1141
};
1142

1143
struct NameFunctionIPv4NumToString { static constexpr auto name = "IPv4NumToString"; };
1144
struct NameFunctionIPv4NumToStringClassC { static constexpr auto name = "IPv4NumToStringClassC"; };
1145

1146
REGISTER_FUNCTION(Coding)
1147
{
1148
    factory.registerFunction<FunctionCutIPv6>();
1149
    factory.registerFunction<FunctionIPv4ToIPv6>();
1150
    factory.registerFunction<FunctionMACNumToString>();
1151
    factory.registerFunction<FunctionMACStringTo<ParseMACImpl>>();
1152
    factory.registerFunction<FunctionMACStringTo<ParseOUIImpl>>();
1153
    factory.registerFunction<FunctionIPv6CIDRToRange>();
1154
    factory.registerFunction<FunctionIPv4CIDRToRange>();
1155
    factory.registerFunction<FunctionIsIPv4String>();
1156
    factory.registerFunction<FunctionIsIPv6String>();
1157

1158
    factory.registerFunction<FunctionIPv4NumToString<0, NameFunctionIPv4NumToString>>();
1159
    factory.registerFunction<FunctionIPv4NumToString<1, NameFunctionIPv4NumToStringClassC>>();
1160

1161
    factory.registerFunction<FunctionIPv4StringToNum<IPStringToNumExceptionMode::Throw>>();
1162
    factory.registerFunction<FunctionIPv4StringToNum<IPStringToNumExceptionMode::Default>>();
1163
    factory.registerFunction<FunctionIPv4StringToNum<IPStringToNumExceptionMode::Null>>();
1164

1165
    factory.registerFunction<FunctionIPv6NumToString>();
1166
    factory.registerFunction<FunctionIPv6StringToNum<IPStringToNumExceptionMode::Throw>>();
1167
    factory.registerFunction<FunctionIPv6StringToNum<IPStringToNumExceptionMode::Default>>();
1168
    factory.registerFunction<FunctionIPv6StringToNum<IPStringToNumExceptionMode::Null>>();
1169

1170
    /// MySQL compatibility aliases:
1171
    factory.registerAlias("INET_ATON", FunctionIPv4StringToNum<IPStringToNumExceptionMode::Throw>::name, FunctionFactory::CaseInsensitive);
1172
    factory.registerAlias("INET6_NTOA", FunctionIPv6NumToString::name, FunctionFactory::CaseInsensitive);
1173
    factory.registerAlias("INET6_ATON", FunctionIPv6StringToNum<IPStringToNumExceptionMode::Throw>::name, FunctionFactory::CaseInsensitive);
1174
    factory.registerAlias("INET_NTOA", NameFunctionIPv4NumToString::name, FunctionFactory::CaseInsensitive);
1175
}
1176

1177
}
1178

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.