1#include <zlib.h>
2#include <DataTypes/DataTypeString.h>
3#include <Functions/FunctionFactory.h>
4#include <Functions/FunctionStringOrArrayToT.h>
5
6
7namespace
8{
9
10template <class T>
11struct CRCBase
12{
13 T tab[256];
14 CRCBase(T polynomial)
15 {
16 for (size_t i = 0; i < 256; ++i)
17 {
18 T c = i;
19 for (size_t j = 0; j < 8; ++j)
20 {
21 c = c & 1 ? polynomial ^ (c >> 1) : c >> 1;
22 }
23 tab[i] = c;
24 }
25 }
26};
27
28template <class T, T polynomial>
29struct CRCImpl
30{
31 using ReturnType = T;
32
33 static T make_crc(const unsigned char *buf, size_t size)
34 {
35 static CRCBase<ReturnType> base(polynomial);
36
37 T i, crc;
38
39 crc = 0;
40 for (i = 0; i < size; i++)
41 {
42 crc = base.tab[(crc ^ buf[i]) & 0xff] ^ (crc >> 8);
43 }
44 return crc;
45 }
46};
47
48static constexpr UInt64 CRC64_ECMA = 0xc96c5795d7870f42ULL;
49struct CRC64ECMAImpl : public CRCImpl<UInt64, CRC64_ECMA>
50{
51 static constexpr auto name = "CRC64";
52};
53
54static constexpr UInt32 CRC32_IEEE = 0xedb88320;
55struct CRC32IEEEImpl : public CRCImpl<UInt32, CRC32_IEEE>
56{
57 static constexpr auto name = "CRC32IEEE";
58};
59
60struct CRC32ZLIBImpl
61{
62 using ReturnType = UInt32;
63 static constexpr auto name = "CRC32";
64
65 static UInt32 make_crc(const unsigned char *buf, size_t size)
66 { return crc32_z(0L, buf, size); }
67};
68
69} // \anonymous
70
71namespace DB
72{
73
74namespace ErrorCodes
75{
76 extern const int ILLEGAL_TYPE_OF_ARGUMENT;
77}
78
79template <class Impl>
80struct CRCFunctionWrapper
81{
82 static constexpr auto is_fixed_to_constant = true;
83 using ReturnType = typename Impl::ReturnType;
84
85 static void vector(const ColumnString::Chars & data, const ColumnString::Offsets & offsets, PaddedPODArray<ReturnType> & res)
86 {
87 size_t size = offsets.size();
88
89 ColumnString::Offset prev_offset = 0;
90 for (size_t i = 0; i < size; ++i)
91 {
92 res[i] = do_crc(data, prev_offset, offsets[i] - prev_offset - 1);
93 prev_offset = offsets[i];
94 }
95 }
96
97 static void vector_fixed_to_constant(const ColumnString::Chars & data, size_t n, ReturnType & res) { res = do_crc(data, 0, n); }
98
99 static void vector_fixed_to_vector(const ColumnString::Chars & data, size_t n, PaddedPODArray<ReturnType> & res)
100 {
101 size_t size = data.size() / n;
102
103 for (size_t i = 0; i < size; ++i)
104 {
105 res[i] = do_crc(data, i * n, n);
106 }
107 }
108
109 [[noreturn]] static void array(const ColumnString::Offsets & /*offsets*/, PaddedPODArray<ReturnType> & /*res*/)
110 {
111 throw Exception("Cannot apply function " + std::string(Impl::name) + " to Array argument", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
112 }
113
114private:
115 static ReturnType do_crc(const ColumnString::Chars & buf, size_t offset, size_t size)
116 {
117 const unsigned char * p = reinterpret_cast<const unsigned char *>(&buf[0]) + offset;
118 return Impl::make_crc(p, size);
119 }
120};
121
122template <class T>
123using FunctionCRC = FunctionStringOrArrayToT<CRCFunctionWrapper<T>, T, typename T::ReturnType>;
124// The same as IEEE variant, but uses 0xffffffff as initial value
125// This is the default
126//
127// (And zlib is used here, since it has optimized version)
128using FunctionCRC32ZLIB = FunctionCRC<CRC32ZLIBImpl>;
129// Uses CRC-32-IEEE 802.3 polynomial
130using FunctionCRC32IEEE = FunctionCRC<CRC32IEEEImpl>;
131// Uses CRC-64-ECMA polynomial
132using FunctionCRC64ECMA = FunctionCRC<CRC64ECMAImpl>;
133
134template <class T>
135void registerFunctionCRCImpl(FunctionFactory & factory)
136{
137 factory.registerFunction<T>(T::name, FunctionFactory::CaseInsensitive);
138}
139
140void registerFunctionCRC(FunctionFactory & factory)
141{
142 registerFunctionCRCImpl<FunctionCRC32ZLIB>(factory);
143 registerFunctionCRCImpl<FunctionCRC32IEEE>(factory);
144 registerFunctionCRCImpl<FunctionCRC64ECMA>(factory);
145}
146
147}
148