1#include <Common/Exception.h>
2#include <Common/Arena.h>
3#include <Common/SipHash.h>
4#include <Common/assert_cast.h>
5
6#include <common/unaligned.h>
7
8#include <IO/WriteHelpers.h>
9
10#include <Columns/ColumnsCommon.h>
11#include <Columns/ColumnDecimal.h>
12#include <DataStreams/ColumnGathererStream.h>
13
14
15template <typename T> bool decimalLess(T x, T y, UInt32 x_scale, UInt32 y_scale);
16
17namespace DB
18{
19
20namespace ErrorCodes
21{
22 extern const int PARAMETER_OUT_OF_BOUND;
23 extern const int SIZES_OF_COLUMNS_DOESNT_MATCH;
24 extern const int NOT_IMPLEMENTED;
25}
26
27template <typename T>
28int ColumnDecimal<T>::compareAt(size_t n, size_t m, const IColumn & rhs_, int) const
29{
30 auto & other = static_cast<const Self &>(rhs_);
31 const T & a = data[n];
32 const T & b = other.data[m];
33
34 if (scale == other.scale)
35 return a > b ? 1 : (a < b ? -1 : 0);
36 return decimalLess<T>(b, a, other.scale, scale) ? 1 : (decimalLess<T>(a, b, scale, other.scale) ? -1 : 0);
37}
38
39template <typename T>
40StringRef ColumnDecimal<T>::serializeValueIntoArena(size_t n, Arena & arena, char const *& begin) const
41{
42 auto pos = arena.allocContinue(sizeof(T), begin);
43 memcpy(pos, &data[n], sizeof(T));
44 return StringRef(pos, sizeof(T));
45}
46
47template <typename T>
48const char * ColumnDecimal<T>::deserializeAndInsertFromArena(const char * pos)
49{
50 data.push_back(unalignedLoad<T>(pos));
51 return pos + sizeof(T);
52}
53
54template <typename T>
55UInt64 ColumnDecimal<T>::get64(size_t n) const
56{
57 if constexpr (sizeof(T) > sizeof(UInt64))
58 throw Exception(String("Method get64 is not supported for ") + getFamilyName(), ErrorCodes::NOT_IMPLEMENTED);
59 return static_cast<typename T::NativeType>(data[n]);
60}
61
62template <typename T>
63void ColumnDecimal<T>::updateHashWithValue(size_t n, SipHash & hash) const
64{
65 hash.update(data[n]);
66}
67
68template <typename T>
69void ColumnDecimal<T>::getPermutation(bool reverse, size_t limit, int , IColumn::Permutation & res) const
70{
71#if 1 /// TODO: perf test
72 if (data.size() <= std::numeric_limits<UInt32>::max())
73 {
74 PaddedPODArray<UInt32> tmp_res;
75 permutation(reverse, limit, tmp_res);
76
77 res.resize(tmp_res.size());
78 for (size_t i = 0; i < tmp_res.size(); ++i)
79 res[i] = tmp_res[i];
80 return;
81 }
82#endif
83
84 permutation(reverse, limit, res);
85}
86
87template <typename T>
88ColumnPtr ColumnDecimal<T>::permute(const IColumn::Permutation & perm, size_t limit) const
89{
90 size_t size = limit ? std::min(data.size(), limit) : data.size();
91 if (perm.size() < size)
92 throw Exception("Size of permutation is less than required.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
93
94 auto res = this->create(size, scale);
95 typename Self::Container & res_data = res->getData();
96
97 for (size_t i = 0; i < size; ++i)
98 res_data[i] = data[perm[i]];
99
100 return res;
101}
102
103template <typename T>
104MutableColumnPtr ColumnDecimal<T>::cloneResized(size_t size) const
105{
106 auto res = this->create(0, scale);
107
108 if (size > 0)
109 {
110 auto & new_col = static_cast<Self &>(*res);
111 new_col.data.resize(size);
112
113 size_t count = std::min(this->size(), size);
114 memcpy(new_col.data.data(), data.data(), count * sizeof(data[0]));
115
116 if (size > count)
117 {
118 void * tail = &new_col.data[count];
119 memset(tail, 0, (size - count) * sizeof(T));
120 }
121 }
122
123 return res;
124}
125
126template <typename T>
127void ColumnDecimal<T>::insertData(const char * src, size_t /*length*/)
128{
129 T tmp;
130 memcpy(&tmp, src, sizeof(T));
131 data.emplace_back(tmp);
132}
133
134template <typename T>
135void ColumnDecimal<T>::insertRangeFrom(const IColumn & src, size_t start, size_t length)
136{
137 const ColumnDecimal & src_vec = assert_cast<const ColumnDecimal &>(src);
138
139 if (start + length > src_vec.data.size())
140 throw Exception("Parameters start = " + toString(start) + ", length = " + toString(length) +
141 " are out of bound in ColumnDecimal<T>::insertRangeFrom method (data.size() = " + toString(src_vec.data.size()) + ").",
142 ErrorCodes::PARAMETER_OUT_OF_BOUND);
143
144 size_t old_size = data.size();
145 data.resize(old_size + length);
146 memcpy(data.data() + old_size, &src_vec.data[start], length * sizeof(data[0]));
147}
148
149template <typename T>
150ColumnPtr ColumnDecimal<T>::filter(const IColumn::Filter & filt, ssize_t result_size_hint) const
151{
152 size_t size = data.size();
153 if (size != filt.size())
154 throw Exception("Size of filter doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
155
156 auto res = this->create(0, scale);
157 Container & res_data = res->getData();
158
159 if (result_size_hint)
160 res_data.reserve(result_size_hint > 0 ? result_size_hint : size);
161
162 const UInt8 * filt_pos = filt.data();
163 const UInt8 * filt_end = filt_pos + size;
164 const T * data_pos = data.data();
165
166 while (filt_pos < filt_end)
167 {
168 if (*filt_pos)
169 res_data.push_back(*data_pos);
170
171 ++filt_pos;
172 ++data_pos;
173 }
174
175 return res;
176}
177
178template <typename T>
179ColumnPtr ColumnDecimal<T>::index(const IColumn & indexes, size_t limit) const
180{
181 return selectIndexImpl(*this, indexes, limit);
182}
183
184template <typename T>
185ColumnPtr ColumnDecimal<T>::replicate(const IColumn::Offsets & offsets) const
186{
187 size_t size = data.size();
188 if (size != offsets.size())
189 throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
190
191 auto res = this->create(0, scale);
192 if (0 == size)
193 return res;
194
195 typename Self::Container & res_data = res->getData();
196 res_data.reserve(offsets.back());
197
198 IColumn::Offset prev_offset = 0;
199 for (size_t i = 0; i < size; ++i)
200 {
201 size_t size_to_replicate = offsets[i] - prev_offset;
202 prev_offset = offsets[i];
203
204 for (size_t j = 0; j < size_to_replicate; ++j)
205 res_data.push_back(data[i]);
206 }
207
208 return res;
209}
210
211template <typename T>
212void ColumnDecimal<T>::gather(ColumnGathererStream & gatherer)
213{
214 gatherer.gather(*this);
215}
216
217template <typename T>
218void ColumnDecimal<T>::getExtremes(Field & min, Field & max) const
219{
220 if (data.size() == 0)
221 {
222 min = NearestFieldType<T>(0, scale);
223 max = NearestFieldType<T>(0, scale);
224 return;
225 }
226
227 T cur_min = data[0];
228 T cur_max = data[0];
229
230 for (const T & x : data)
231 {
232 if (x < cur_min)
233 cur_min = x;
234 else if (x > cur_max)
235 cur_max = x;
236 }
237
238 min = NearestFieldType<T>(cur_min, scale);
239 max = NearestFieldType<T>(cur_max, scale);
240}
241
242template class ColumnDecimal<Decimal32>;
243template class ColumnDecimal<Decimal64>;
244template class ColumnDecimal<Decimal128>;
245}
246