ClickHouse

Форк
0
/
FunctionsBinaryRepresentation.cpp 
724 строки · 24.8 Кб
1
#include <Columns/ColumnDecimal.h>
2
#include <Columns/ColumnFixedString.h>
3
#include <Columns/ColumnString.h>
4
#include <Columns/ColumnVector.h>
5
#include <Columns/ColumnsNumber.h>
6
#include <Common/BitHelpers.h>
7
#include <Common/BinStringDecodeHelper.h>
8
#include <DataTypes/DataTypeString.h>
9
#include <Functions/FunctionFactory.h>
10
#include <Functions/IFunction.h>
11
#include <IO/WriteHelpers.h>
12
#include <Interpreters/Context_fwd.h>
13
#include <Interpreters/castColumn.h>
14

15
namespace DB
16
{
17

18
namespace ErrorCodes
19
{
20
    extern const int ILLEGAL_TYPE_OF_ARGUMENT;
21
    extern const int LOGICAL_ERROR;
22
    extern const int ILLEGAL_COLUMN;
23
}
24

25
/*
26
 * hex(x) - Returns hexadecimal representation; capital letters; there are no prefixes 0x or suffixes h.
27
 *          For numbers, returns a variable-length string - hex in the "human" (big endian) format, with the leading zeros being cut,
28
 *          but only by whole bytes. For dates and datetimes - the same as for numbers.
29
 *          For example, hex(257) = '0101'.
30
 *
31
 * unhex(string) - Returns a string, hex of which is equal to `string` with regard of case and discarding one leading zero.
32
 *                 If such a string does not exist, could return arbitrary implementation specific value.
33
 *
34
 * bin(x) - Returns binary representation.
35
 *
36
 * unbin(x) - Returns a string, opposite to `bin`.
37
 *
38
 */
39

40
struct HexImpl
41
{
42
    static constexpr auto name = "hex";
43
    static constexpr size_t word_size = 2;
44

45
    template <typename T>
46
    static void executeOneUIntOrInt(T x, char *& out, bool skip_leading_zero = true, bool auto_close = true)
47
    {
48
        bool was_nonzero = false;
49
        for (int offset = (sizeof(T) - 1) * 8; offset >= 0; offset -= 8)
50
        {
51
            UInt8 byte = x >> offset;
52

53
            /// Skip leading zeros
54
            if (byte == 0 && !was_nonzero && offset && skip_leading_zero)
55
                continue;
56

57
            was_nonzero = true;
58
            writeHexByteUppercase(byte, out);
59
            out += word_size;
60
        }
61
        if (auto_close)
62
        {
63
            *out = '\0';
64
            ++out;
65
        }
66
    }
67

68
    static void executeOneString(const UInt8 * pos, const UInt8 * end, char *& out, bool reverse_order = false)
69
    {
70
        if (!reverse_order)
71
        {
72
            while (pos < end)
73
            {
74
                writeHexByteUppercase(*pos, out);
75
                ++pos;
76
                out += word_size;
77
            }
78
        }
79
        else
80
        {
81
            const auto * start_pos = pos;
82
            pos = end - 1;
83
            while (pos >= start_pos)
84
            {
85
                writeHexByteUppercase(*pos, out);
86
                --pos;
87
                out += word_size;
88
            }
89
        }
90
        *out = '\0';
91
        ++out;
92
    }
93

94
    template <typename T>
95
    static void executeFloatAndDecimal(const T & in_vec, ColumnPtr & col_res, const size_t type_size_in_bytes)
96
    {
97
        const size_t hex_length = type_size_in_bytes * word_size + 1; /// Including trailing zero byte.
98
        auto col_str = ColumnString::create();
99

100
        ColumnString::Chars & out_vec = col_str->getChars();
101
        ColumnString::Offsets & out_offsets = col_str->getOffsets();
102

103
        size_t size = in_vec.size();
104
        out_offsets.resize(size);
105
        out_vec.resize(size * hex_length);
106

107
        size_t pos = 0;
108
        char * out = reinterpret_cast<char *>(out_vec.data());
109
        for (size_t i = 0; i < size; ++i)
110
        {
111
            const UInt8 * in_pos = reinterpret_cast<const UInt8 *>(&in_vec[i]);
112
            bool reverse_order = (std::endian::native == std::endian::big);
113
            executeOneString(in_pos, in_pos + type_size_in_bytes, out, reverse_order);
114

115
            pos += hex_length;
116
            out_offsets[i] = pos;
117
        }
118
        col_res = std::move(col_str);
119
    }
120
};
121

122
struct UnhexImpl
123
{
124
    static constexpr auto name = "unhex";
125
    static constexpr size_t word_size = 2;
126

127
    static void decode(const char * pos, const char * end, char *& out)
128
    {
129
        hexStringDecode(pos, end, out, word_size);
130
    }
131
};
132

133
struct BinImpl
134
{
135
    static constexpr auto name = "bin";
136
    static constexpr size_t word_size = 8;
137

138
    template <typename T>
139
    static void executeOneUIntOrInt(T x, char *& out, bool skip_leading_zero = true, bool auto_close = true)
140
    {
141
        bool was_nonzero = false;
142
        for (int offset = (sizeof(T) - 1) * 8; offset >= 0; offset -= 8)
143
        {
144
            UInt8 byte = x >> offset;
145

146
            /// Skip leading zeros
147
            if (byte == 0 && !was_nonzero && offset && skip_leading_zero)
148
                continue;
149

150
            was_nonzero = true;
151
            writeBinByte(byte, out);
152
            out += word_size;
153
        }
154
        if (auto_close)
155
        {
156
            *out = '\0';
157
            ++out;
158
        }
159
    }
160

161
    template <typename T>
162
    static void executeFloatAndDecimal(const T & in_vec, ColumnPtr & col_res, const size_t type_size_in_bytes)
163
    {
164
        const size_t hex_length = type_size_in_bytes * word_size + 1; /// Including trailing zero byte.
165
        auto col_str = ColumnString::create();
166

167
        ColumnString::Chars & out_vec = col_str->getChars();
168
        ColumnString::Offsets & out_offsets = col_str->getOffsets();
169

170
        size_t size = in_vec.size();
171
        out_offsets.resize(size);
172
        out_vec.resize(size * hex_length);
173

174
        size_t pos = 0;
175
        char * out = reinterpret_cast<char *>(out_vec.data());
176
        for (size_t i = 0; i < size; ++i)
177
        {
178
            const UInt8 * in_pos = reinterpret_cast<const UInt8 *>(&in_vec[i]);
179

180
            bool reverse_order = (std::endian::native == std::endian::big);
181
            executeOneString(in_pos, in_pos + type_size_in_bytes, out, reverse_order);
182

183
            pos += hex_length;
184
            out_offsets[i] = pos;
185
        }
186
        col_res = std::move(col_str);
187
    }
188

189
    static void executeOneString(const UInt8 * pos, const UInt8 * end, char *& out, bool reverse_order = false)
190
    {
191
        if (!reverse_order)
192
        {
193
            while (pos < end)
194
            {
195
                writeBinByte(*pos, out);
196
                ++pos;
197
                out += word_size;
198
            }
199
        }
200
        else
201
        {
202
            const auto * start_pos = pos;
203
            pos = end - 1;
204
            while (pos >= start_pos)
205
            {
206
                writeBinByte(*pos, out);
207
                --pos;
208
                out += word_size;
209
            }
210
        }
211
        *out = '\0';
212
        ++out;
213
    }
214
};
215

216
struct UnbinImpl
217
{
218
    static constexpr auto name = "unbin";
219
    static constexpr size_t word_size = 8;
220

221
    static void decode(const char * pos, const char * end, char *& out)
222
    {
223
        binStringDecode(pos, end, out);
224
    }
225
};
226

227
/// Encode number or string to string with binary or hexadecimal representation
228
template <typename Impl>
229
class EncodeToBinaryRepresentation : public IFunction
230
{
231
public:
232
    static constexpr auto name = Impl::name;
233
    static constexpr size_t word_size = Impl::word_size;
234

235
    static FunctionPtr create(ContextPtr) { return std::make_shared<EncodeToBinaryRepresentation>(); }
236

237
    String getName() const override { return name; }
238

239
    size_t getNumberOfArguments() const override { return 1; }
240

241
    bool useDefaultImplementationForConstants() const override { return true; }
242

243
    bool isInjective(const ColumnsWithTypeAndName &) const override { return true; }
244

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

247
    DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
248
    {
249
        WhichDataType which(arguments[0]);
250

251
        if (!which.isStringOrFixedString() &&
252
            !which.isDate() &&
253
            !which.isDateTime() &&
254
            !which.isDateTime64() &&
255
            !which.isUInt() &&
256
            !which.isInt() &&
257
            !which.isFloat() &&
258
            !which.isDecimal() &&
259
            !which.isUUID() &&
260
            !which.isIPv4() &&
261
            !which.isIPv6() &&
262
            !which.isAggregateFunction())
263
            throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type {} of argument of function {}",
264
                            arguments[0]->getName(), getName());
265

266
        return std::make_shared<DataTypeString>();
267
    }
268

269
    ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t /*input_rows_count*/) const override
270
    {
271
        const IColumn * column = arguments[0].column.get();
272
        ColumnPtr res_column;
273

274
        WhichDataType which(column->getDataType());
275
        if (which.isAggregateFunction())
276
        {
277
            const ColumnPtr to_string = castColumn(arguments[0], std::make_shared<DataTypeString>());
278
            const auto * str_column = checkAndGetColumn<ColumnString>(to_string.get());
279
            tryExecuteString(str_column, res_column);
280
            return res_column;
281
        }
282

283
        if (tryExecuteUIntOrInt<UInt8>(column, res_column) ||
284
            tryExecuteUIntOrInt<UInt16>(column, res_column) ||
285
            tryExecuteUIntOrInt<UInt32>(column, res_column) ||
286
            tryExecuteUIntOrInt<UInt64>(column, res_column) ||
287
            tryExecuteUIntOrInt<UInt128>(column, res_column) ||
288
            tryExecuteUIntOrInt<UInt256>(column, res_column) ||
289
            tryExecuteUIntOrInt<Int8>(column, res_column) ||
290
            tryExecuteUIntOrInt<Int16>(column, res_column) ||
291
            tryExecuteUIntOrInt<Int32>(column, res_column) ||
292
            tryExecuteUIntOrInt<Int64>(column, res_column) ||
293
            tryExecuteUIntOrInt<Int128>(column, res_column) ||
294
            tryExecuteUIntOrInt<Int256>(column, res_column) ||
295
            tryExecuteString(column, res_column) ||
296
            tryExecuteFixedString(column, res_column) ||
297
            tryExecuteFloat<Float32>(column, res_column) ||
298
            tryExecuteFloat<Float64>(column, res_column) ||
299
            tryExecuteDecimal<Decimal32>(column, res_column) ||
300
            tryExecuteDecimal<Decimal64>(column, res_column) ||
301
            tryExecuteDecimal<Decimal128>(column, res_column) ||
302
            tryExecuteDecimal<Decimal256>(column, res_column) ||
303
            tryExecuteUUID(column, res_column) ||
304
            tryExecuteIPv4(column, res_column) ||
305
            tryExecuteIPv6(column, res_column))
306
            return res_column;
307

308
        throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of argument of function {}",
309
                        arguments[0].column->getName(), getName());
310
    }
311

312
    template <typename T>
313
    bool tryExecuteUIntOrInt(const IColumn * col, ColumnPtr & col_res) const
314
    {
315
        const ColumnVector<T> * col_vec = checkAndGetColumn<ColumnVector<T>>(col);
316

317
        static constexpr size_t MAX_LENGTH = sizeof(T) * word_size + 1;    /// Including trailing zero byte.
318

319
        if (col_vec)
320
        {
321
            auto col_str = ColumnString::create();
322
            ColumnString::Chars & out_vec = col_str->getChars();
323
            ColumnString::Offsets & out_offsets = col_str->getOffsets();
324

325
            const typename ColumnVector<T>::Container & in_vec = col_vec->getData();
326

327
            size_t size = in_vec.size();
328
            out_offsets.resize(size);
329
            out_vec.resize(size * (word_size+1) + MAX_LENGTH); /// word_size+1 is length of one byte in hex/bin plus zero byte.
330

331
            size_t pos = 0;
332
            for (size_t i = 0; i < size; ++i)
333
            {
334
                /// Manual exponential growth, so as not to rely on the linear amortized work time of `resize` (no one guarantees it).
335
                if (pos + MAX_LENGTH > out_vec.size())
336
                    out_vec.resize(out_vec.size() * word_size + MAX_LENGTH);
337

338
                char * begin = reinterpret_cast<char *>(&out_vec[pos]);
339
                char * end = begin;
340
                Impl::executeOneUIntOrInt(in_vec[i], end);
341

342
                pos += end - begin;
343
                out_offsets[i] = pos;
344
            }
345
            out_vec.resize(pos);
346

347
            col_res = std::move(col_str);
348
            return true;
349
        }
350
        else
351
        {
352
            return false;
353
        }
354
    }
355

356
    bool tryExecuteString(const IColumn *col, ColumnPtr &col_res) const
357
    {
358
        const ColumnString * col_str_in = checkAndGetColumn<ColumnString>(col);
359

360
        if (col_str_in)
361
        {
362
            auto col_str = ColumnString::create();
363
            ColumnString::Chars & out_vec = col_str->getChars();
364
            ColumnString::Offsets & out_offsets = col_str->getOffsets();
365

366
            const ColumnString::Chars & in_vec = col_str_in->getChars();
367
            const ColumnString::Offsets & in_offsets = col_str_in->getOffsets();
368

369
            size_t size = in_offsets.size();
370

371
            out_offsets.resize(size);
372
            /// reserve `word_size` bytes for each non trailing zero byte from input + `size` bytes for trailing zeros
373
            out_vec.resize((in_vec.size() - size) * word_size + size);
374

375
            char * begin = reinterpret_cast<char *>(out_vec.data());
376
            char * pos = begin;
377
            size_t prev_offset = 0;
378

379
            for (size_t i = 0; i < size; ++i)
380
            {
381
                size_t new_offset = in_offsets[i];
382

383
                Impl::executeOneString(&in_vec[prev_offset], &in_vec[new_offset - 1], pos);
384

385
                out_offsets[i] = pos - begin;
386

387
                prev_offset = new_offset;
388
            }
389
            if (!out_offsets.empty() && out_offsets.back() != out_vec.size())
390
                throw Exception(ErrorCodes::LOGICAL_ERROR, "Column size mismatch (internal logical error)");
391

392
            col_res = std::move(col_str);
393
            return true;
394
        }
395
        else
396
        {
397
            return false;
398
        }
399
    }
400

401
    template <typename T>
402
    bool tryExecuteDecimal(const IColumn * col, ColumnPtr & col_res) const
403
    {
404
        const ColumnDecimal<T> * col_dec = checkAndGetColumn<ColumnDecimal<T>>(col);
405
        if (col_dec)
406
        {
407
            const typename ColumnDecimal<T>::Container & in_vec = col_dec->getData();
408
            Impl::executeFloatAndDecimal(in_vec, col_res, sizeof(T));
409
            return true;
410
        }
411
        else
412
        {
413
            return false;
414
        }
415
    }
416

417
    static bool tryExecuteFixedString(const IColumn * col, ColumnPtr & col_res)
418
    {
419
        const ColumnFixedString * col_fstr_in = checkAndGetColumn<ColumnFixedString>(col);
420

421
        if (col_fstr_in)
422
        {
423
            auto col_str = ColumnString::create();
424
            ColumnString::Chars & out_vec = col_str->getChars();
425
            ColumnString::Offsets & out_offsets = col_str->getOffsets();
426

427
            const ColumnString::Chars & in_vec = col_fstr_in->getChars();
428

429
            size_t size = col_fstr_in->size();
430

431
            out_offsets.resize(size);
432
            out_vec.resize(in_vec.size() * word_size + size);
433

434
            char * begin = reinterpret_cast<char *>(out_vec.data());
435
            char * pos = begin;
436

437
            size_t n = col_fstr_in->getN();
438

439
            size_t prev_offset = 0;
440

441
            for (size_t i = 0; i < size; ++i)
442
            {
443
                size_t new_offset = prev_offset + n;
444

445
                Impl::executeOneString(&in_vec[prev_offset], &in_vec[new_offset], pos);
446

447
                out_offsets[i] = pos - begin;
448
                prev_offset = new_offset;
449
            }
450

451
            if (!out_offsets.empty() && out_offsets.back() != out_vec.size())
452
                throw Exception(ErrorCodes::LOGICAL_ERROR, "Column size mismatch (internal logical error)");
453

454
            col_res = std::move(col_str);
455
            return true;
456
        }
457
        else
458
        {
459
            return false;
460
        }
461
    }
462

463
    template <typename T>
464
    bool tryExecuteFloat(const IColumn * col, ColumnPtr & col_res) const
465
    {
466
        const ColumnVector<T> * col_vec = checkAndGetColumn<ColumnVector<T>>(col);
467
        if (col_vec)
468
        {
469
            const typename ColumnVector<T>::Container & in_vec = col_vec->getData();
470
            Impl::executeFloatAndDecimal(in_vec, col_res, sizeof(T));
471
            return true;
472
        }
473
        else
474
        {
475
            return false;
476
        }
477
    }
478

479
    bool tryExecuteUUID(const IColumn * col, ColumnPtr & col_res) const
480
    {
481
        const ColumnUUID * col_vec = checkAndGetColumn<ColumnUUID>(col);
482

483
        static constexpr size_t MAX_LENGTH = sizeof(UUID) * word_size + 1;    /// Including trailing zero byte.
484

485
        if (col_vec)
486
        {
487
            auto col_str = ColumnString::create();
488
            ColumnString::Chars & out_vec = col_str->getChars();
489
            ColumnString::Offsets & out_offsets = col_str->getOffsets();
490

491
            const typename ColumnUUID::Container & in_vec = col_vec->getData();
492
            const UUID* uuid = in_vec.data();
493

494
            size_t size = in_vec.size();
495
            out_offsets.resize(size);
496
            out_vec.resize(size * (word_size+1) + MAX_LENGTH); /// word_size+1 is length of one byte in hex/bin plus zero byte.
497

498
            size_t pos = 0;
499
            for (size_t i = 0; i < size; ++i)
500
            {
501
                /// Manual exponential growth, so as not to rely on the linear amortized work time of `resize` (no one guarantees it).
502
                if (pos + MAX_LENGTH > out_vec.size())
503
                    out_vec.resize(out_vec.size() * word_size + MAX_LENGTH);
504

505
                char * begin = reinterpret_cast<char *>(&out_vec[pos]);
506
                char * end = begin;
507

508
                // use executeOnUInt instead of using executeOneString
509
                // because the latter one outputs the string in the memory order
510
                Impl::executeOneUIntOrInt(UUIDHelpers::getHighBytes(uuid[i]), end, false, false);
511
                Impl::executeOneUIntOrInt(UUIDHelpers::getLowBytes(uuid[i]), end, false, true);
512

513
                pos += end - begin;
514
                out_offsets[i] = pos;
515
            }
516
            out_vec.resize(pos);
517

518
            col_res = std::move(col_str);
519
            return true;
520
        }
521
        else
522
        {
523
            return false;
524
        }
525
    }
526

527
    bool tryExecuteIPv6(const IColumn * col, ColumnPtr & col_res) const
528
    {
529
        const ColumnIPv6 * col_vec = checkAndGetColumn<ColumnIPv6>(col);
530

531
        static constexpr size_t MAX_LENGTH = sizeof(IPv6) * word_size + 1;    /// Including trailing zero byte.
532

533
        if (!col_vec)
534
            return false;
535

536
        auto col_str = ColumnString::create();
537
        ColumnString::Chars & out_vec = col_str->getChars();
538
        ColumnString::Offsets & out_offsets = col_str->getOffsets();
539

540
        const typename ColumnIPv6::Container & in_vec = col_vec->getData();
541
        const IPv6* ip = in_vec.data();
542

543
        size_t size = in_vec.size();
544
        out_offsets.resize(size);
545
        out_vec.resize(size * (word_size+1) + MAX_LENGTH); /// word_size+1 is length of one byte in hex/bin plus zero byte.
546

547
        size_t pos = 0;
548
        for (size_t i = 0; i < size; ++i)
549
        {
550
            /// Manual exponential growth, so as not to rely on the linear amortized work time of `resize` (no one guarantees it).
551
            if (pos + MAX_LENGTH > out_vec.size())
552
                out_vec.resize(out_vec.size() * word_size + MAX_LENGTH);
553

554
            char * begin = reinterpret_cast<char *>(&out_vec[pos]);
555
            char * end = begin;
556

557
            Impl::executeOneString(reinterpret_cast<const UInt8 *>(&ip[i].toUnderType().items[0]), reinterpret_cast<const UInt8 *>(&ip[i].toUnderType().items[2]), end);
558

559
            pos += end - begin;
560
            out_offsets[i] = pos;
561
        }
562
        out_vec.resize(pos);
563

564
        col_res = std::move(col_str);
565
        return true;
566
    }
567

568
    bool tryExecuteIPv4(const IColumn * col, ColumnPtr & col_res) const
569
    {
570
        const ColumnIPv4 * col_vec = checkAndGetColumn<ColumnIPv4>(col);
571

572
        static constexpr size_t MAX_LENGTH = sizeof(IPv4) * word_size + 1;    /// Including trailing zero byte.
573

574
        if (!col_vec)
575
            return false;
576

577
        auto col_str = ColumnString::create();
578
        ColumnString::Chars & out_vec = col_str->getChars();
579
        ColumnString::Offsets & out_offsets = col_str->getOffsets();
580

581
        const typename ColumnIPv4::Container & in_vec = col_vec->getData();
582
        const IPv4* ip = in_vec.data();
583

584
        size_t size = in_vec.size();
585
        out_offsets.resize(size);
586
        out_vec.resize(size * (word_size+1) + MAX_LENGTH); /// word_size+1 is length of one byte in hex/bin plus zero byte.
587

588
        size_t pos = 0;
589
        for (size_t i = 0; i < size; ++i)
590
        {
591
            /// Manual exponential growth, so as not to rely on the linear amortized work time of `resize` (no one guarantees it).
592
            if (pos + MAX_LENGTH > out_vec.size())
593
                out_vec.resize(out_vec.size() * word_size + MAX_LENGTH);
594

595
            char * begin = reinterpret_cast<char *>(&out_vec[pos]);
596
            char * end = begin;
597

598
            Impl::executeOneUIntOrInt(ip[i].toUnderType(), end);
599

600
            pos += end - begin;
601
            out_offsets[i] = pos;
602
        }
603
        out_vec.resize(pos);
604

605
        col_res = std::move(col_str);
606
        return true;
607
    }
608
};
609

610
/// Decode number or string from string with binary or hexadecimal representation
611
template <typename Impl>
612
class DecodeFromBinaryRepresentation : public IFunction
613
{
614
public:
615
    static constexpr auto name = Impl::name;
616
    static constexpr size_t word_size = Impl::word_size;
617
    static FunctionPtr create(ContextPtr) { return std::make_shared<DecodeFromBinaryRepresentation>(); }
618

619
    String getName() const override { return name; }
620

621
    size_t getNumberOfArguments() const override { return 1; }
622
    bool isInjective(const ColumnsWithTypeAndName &) const override { return true; }
623

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

626
    DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
627
    {
628
        WhichDataType which(arguments[0]);
629
        if (!which.isStringOrFixedString())
630
            throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type {} of argument of function {}",
631
                            arguments[0]->getName(), getName());
632

633
        return std::make_shared<DataTypeString>();
634
    }
635

636
    bool useDefaultImplementationForConstants() const override { return true; }
637

638
    ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t /*input_rows_count*/) const override
639
    {
640
        const ColumnPtr & column = arguments[0].column;
641

642
        if (const ColumnString * col = checkAndGetColumn<ColumnString>(column.get()))
643
        {
644
            auto col_res = ColumnString::create();
645

646
            ColumnString::Chars & out_vec = col_res->getChars();
647
            ColumnString::Offsets & out_offsets = col_res->getOffsets();
648

649
            const ColumnString::Chars & in_vec = col->getChars();
650
            const ColumnString::Offsets & in_offsets = col->getOffsets();
651

652
            size_t size = in_offsets.size();
653
            out_offsets.resize(size);
654
            out_vec.resize(in_vec.size() / word_size + size);
655

656
            char * begin = reinterpret_cast<char *>(out_vec.data());
657
            char * pos = begin;
658
            size_t prev_offset = 0;
659

660
            for (size_t i = 0; i < size; ++i)
661
            {
662
                size_t new_offset = in_offsets[i];
663

664
                Impl::decode(reinterpret_cast<const char *>(&in_vec[prev_offset]), reinterpret_cast<const char *>(&in_vec[new_offset - 1]), pos);
665

666
                out_offsets[i] = pos - begin;
667

668
                prev_offset = new_offset;
669
            }
670

671
            out_vec.resize(pos - begin);
672

673
            return col_res;
674
        }
675
        else if (const ColumnFixedString * col_fix_string = checkAndGetColumn<ColumnFixedString>(column.get()))
676
        {
677
            auto col_res = ColumnString::create();
678

679
            ColumnString::Chars & out_vec = col_res->getChars();
680
            ColumnString::Offsets & out_offsets = col_res->getOffsets();
681

682
            const ColumnString::Chars & in_vec = col_fix_string->getChars();
683
            size_t n = col_fix_string->getN();
684

685
            size_t size = col_fix_string->size();
686
            out_offsets.resize(size);
687
            out_vec.resize(in_vec.size() / word_size + size);
688

689
            char * begin = reinterpret_cast<char *>(out_vec.data());
690
            char * pos = begin;
691
            size_t prev_offset = 0;
692

693
            for (size_t i = 0; i < size; ++i)
694
            {
695
                size_t new_offset = prev_offset + n;
696

697
                Impl::decode(reinterpret_cast<const char *>(&in_vec[prev_offset]), reinterpret_cast<const char *>(&in_vec[new_offset]), pos);
698

699
                out_offsets[i] = pos - begin;
700

701
                prev_offset = new_offset;
702
            }
703

704
            out_vec.resize(pos - begin);
705

706
            return col_res;
707
        }
708
        else
709
        {
710
            throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of argument of function {}",
711
                            arguments[0].column->getName(), getName());
712
        }
713
    }
714
};
715

716
REGISTER_FUNCTION(BinaryRepr)
717
{
718
    factory.registerFunction<EncodeToBinaryRepresentation<HexImpl>>({}, FunctionFactory::CaseInsensitive);
719
    factory.registerFunction<DecodeFromBinaryRepresentation<UnhexImpl>>({}, FunctionFactory::CaseInsensitive);
720
    factory.registerFunction<EncodeToBinaryRepresentation<BinImpl>>({}, FunctionFactory::CaseInsensitive);
721
    factory.registerFunction<DecodeFromBinaryRepresentation<UnbinImpl>>({}, FunctionFactory::CaseInsensitive);
722
}
723

724
}
725

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

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

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

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