1#include <Columns/ColumnTuple.h>
2#include <DataStreams/ColumnGathererStream.h>
3#include <IO/WriteBufferFromString.h>
4#include <IO/Operators.h>
5#include <ext/map.h>
6#include <ext/range.h>
7#include <Common/typeid_cast.h>
8#include <Common/assert_cast.h>
9#include <Core/Field.h>
10
11
12namespace DB
13{
14
15namespace ErrorCodes
16{
17 extern const int ILLEGAL_COLUMN;
18 extern const int NOT_IMPLEMENTED;
19 extern const int CANNOT_INSERT_VALUE_OF_DIFFERENT_SIZE_INTO_TUPLE;
20}
21
22
23std::string ColumnTuple::getName() const
24{
25 WriteBufferFromOwnString res;
26 res << "Tuple(";
27 bool is_first = true;
28 for (const auto & column : columns)
29 {
30 if (!is_first)
31 res << ", ";
32 is_first = false;
33 res << column->getName();
34 }
35 res << ")";
36 return res.str();
37}
38
39ColumnTuple::ColumnTuple(MutableColumns && mutable_columns)
40{
41 columns.reserve(mutable_columns.size());
42 for (auto & column : mutable_columns)
43 {
44 if (isColumnConst(*column))
45 throw Exception{"ColumnTuple cannot have ColumnConst as its element", ErrorCodes::ILLEGAL_COLUMN};
46
47 columns.push_back(std::move(column));
48 }
49}
50
51ColumnTuple::Ptr ColumnTuple::create(const Columns & columns)
52{
53 for (const auto & column : columns)
54 if (isColumnConst(*column))
55 throw Exception{"ColumnTuple cannot have ColumnConst as its element", ErrorCodes::ILLEGAL_COLUMN};
56
57 auto column_tuple = ColumnTuple::create(MutableColumns());
58 column_tuple->columns.assign(columns.begin(), columns.end());
59
60 return column_tuple;
61}
62
63ColumnTuple::Ptr ColumnTuple::create(const TupleColumns & columns)
64{
65 for (const auto & column : columns)
66 if (isColumnConst(*column))
67 throw Exception{"ColumnTuple cannot have ColumnConst as its element", ErrorCodes::ILLEGAL_COLUMN};
68
69 auto column_tuple = ColumnTuple::create(MutableColumns());
70 column_tuple->columns = columns;
71
72 return column_tuple;
73}
74
75MutableColumnPtr ColumnTuple::cloneEmpty() const
76{
77 const size_t tuple_size = columns.size();
78 MutableColumns new_columns(tuple_size);
79 for (size_t i = 0; i < tuple_size; ++i)
80 new_columns[i] = columns[i]->cloneEmpty();
81
82 return ColumnTuple::create(std::move(new_columns));
83}
84
85MutableColumnPtr ColumnTuple::cloneResized(size_t new_size) const
86{
87 const size_t tuple_size = columns.size();
88 MutableColumns new_columns(tuple_size);
89 for (size_t i = 0; i < tuple_size; ++i)
90 new_columns[i] = columns[i]->cloneResized(new_size);
91
92 return ColumnTuple::create(std::move(new_columns));
93}
94
95Field ColumnTuple::operator[](size_t n) const
96{
97 return ext::map<Tuple>(columns, [n] (const auto & column) { return (*column)[n]; });
98}
99
100void ColumnTuple::get(size_t n, Field & res) const
101{
102 const size_t tuple_size = columns.size();
103 Tuple tuple(tuple_size);
104 for (const auto i : ext::range(0, tuple_size))
105 columns[i]->get(n, tuple[i]);
106
107 res = tuple;
108}
109
110StringRef ColumnTuple::getDataAt(size_t) const
111{
112 throw Exception("Method getDataAt is not supported for " + getName(), ErrorCodes::NOT_IMPLEMENTED);
113}
114
115void ColumnTuple::insertData(const char *, size_t)
116{
117 throw Exception("Method insertData is not supported for " + getName(), ErrorCodes::NOT_IMPLEMENTED);
118}
119
120void ColumnTuple::insert(const Field & x)
121{
122 auto & tuple = DB::get<const Tuple &>(x);
123
124 const size_t tuple_size = columns.size();
125 if (tuple.size() != tuple_size)
126 throw Exception("Cannot insert value of different size into tuple", ErrorCodes::CANNOT_INSERT_VALUE_OF_DIFFERENT_SIZE_INTO_TUPLE);
127
128 for (size_t i = 0; i < tuple_size; ++i)
129 columns[i]->insert(tuple[i]);
130}
131
132void ColumnTuple::insertFrom(const IColumn & src_, size_t n)
133{
134 const ColumnTuple & src = assert_cast<const ColumnTuple &>(src_);
135
136 const size_t tuple_size = columns.size();
137 if (src.columns.size() != tuple_size)
138 throw Exception("Cannot insert value of different size into tuple", ErrorCodes::CANNOT_INSERT_VALUE_OF_DIFFERENT_SIZE_INTO_TUPLE);
139
140 for (size_t i = 0; i < tuple_size; ++i)
141 columns[i]->insertFrom(*src.columns[i], n);
142}
143
144void ColumnTuple::insertDefault()
145{
146 for (auto & column : columns)
147 column->insertDefault();
148}
149
150void ColumnTuple::popBack(size_t n)
151{
152 for (auto & column : columns)
153 column->popBack(n);
154}
155
156StringRef ColumnTuple::serializeValueIntoArena(size_t n, Arena & arena, char const *& begin) const
157{
158 StringRef res(begin, 0);
159 for (auto & column : columns)
160 {
161 auto value_ref = column->serializeValueIntoArena(n, arena, begin);
162 res.data = value_ref.data - res.size;
163 res.size += value_ref.size;
164 }
165
166 return res;
167}
168
169const char * ColumnTuple::deserializeAndInsertFromArena(const char * pos)
170{
171 for (auto & column : columns)
172 pos = column->deserializeAndInsertFromArena(pos);
173
174 return pos;
175}
176
177void ColumnTuple::updateHashWithValue(size_t n, SipHash & hash) const
178{
179 for (auto & column : columns)
180 column->updateHashWithValue(n, hash);
181}
182
183void ColumnTuple::insertRangeFrom(const IColumn & src, size_t start, size_t length)
184{
185 const size_t tuple_size = columns.size();
186 for (size_t i = 0; i < tuple_size; ++i)
187 columns[i]->insertRangeFrom(
188 *assert_cast<const ColumnTuple &>(src).columns[i],
189 start, length);
190}
191
192ColumnPtr ColumnTuple::filter(const Filter & filt, ssize_t result_size_hint) const
193{
194 const size_t tuple_size = columns.size();
195 Columns new_columns(tuple_size);
196
197 for (size_t i = 0; i < tuple_size; ++i)
198 new_columns[i] = columns[i]->filter(filt, result_size_hint);
199
200 return ColumnTuple::create(new_columns);
201}
202
203ColumnPtr ColumnTuple::permute(const Permutation & perm, size_t limit) const
204{
205 const size_t tuple_size = columns.size();
206 Columns new_columns(tuple_size);
207
208 for (size_t i = 0; i < tuple_size; ++i)
209 new_columns[i] = columns[i]->permute(perm, limit);
210
211 return ColumnTuple::create(new_columns);
212}
213
214ColumnPtr ColumnTuple::index(const IColumn & indexes, size_t limit) const
215{
216 const size_t tuple_size = columns.size();
217 Columns new_columns(tuple_size);
218
219 for (size_t i = 0; i < tuple_size; ++i)
220 new_columns[i] = columns[i]->index(indexes, limit);
221
222 return ColumnTuple::create(new_columns);
223}
224
225ColumnPtr ColumnTuple::replicate(const Offsets & offsets) const
226{
227 const size_t tuple_size = columns.size();
228 Columns new_columns(tuple_size);
229
230 for (size_t i = 0; i < tuple_size; ++i)
231 new_columns[i] = columns[i]->replicate(offsets);
232
233 return ColumnTuple::create(new_columns);
234}
235
236MutableColumns ColumnTuple::scatter(ColumnIndex num_columns, const Selector & selector) const
237{
238 const size_t tuple_size = columns.size();
239 std::vector<MutableColumns> scattered_tuple_elements(tuple_size);
240
241 for (size_t tuple_element_idx = 0; tuple_element_idx < tuple_size; ++tuple_element_idx)
242 scattered_tuple_elements[tuple_element_idx] = columns[tuple_element_idx]->scatter(num_columns, selector);
243
244 MutableColumns res(num_columns);
245
246 for (size_t scattered_idx = 0; scattered_idx < num_columns; ++scattered_idx)
247 {
248 MutableColumns new_columns(tuple_size);
249 for (size_t tuple_element_idx = 0; tuple_element_idx < tuple_size; ++tuple_element_idx)
250 new_columns[tuple_element_idx] = std::move(scattered_tuple_elements[tuple_element_idx][scattered_idx]);
251 res[scattered_idx] = ColumnTuple::create(std::move(new_columns));
252 }
253
254 return res;
255}
256
257int ColumnTuple::compareAt(size_t n, size_t m, const IColumn & rhs, int nan_direction_hint) const
258{
259 const size_t tuple_size = columns.size();
260 for (size_t i = 0; i < tuple_size; ++i)
261 if (int res = columns[i]->compareAt(n, m, *assert_cast<const ColumnTuple &>(rhs).columns[i], nan_direction_hint))
262 return res;
263
264 return 0;
265}
266
267template <bool positive>
268struct ColumnTuple::Less
269{
270 TupleColumns columns;
271 int nan_direction_hint;
272
273 Less(const TupleColumns & columns_, int nan_direction_hint_)
274 : columns(columns_), nan_direction_hint(nan_direction_hint_)
275 {
276 }
277
278 bool operator() (size_t a, size_t b) const
279 {
280 for (const auto & column : columns)
281 {
282 int res = column->compareAt(a, b, *column, nan_direction_hint);
283 if (res < 0)
284 return positive;
285 else if (res > 0)
286 return !positive;
287 }
288 return false;
289 }
290};
291
292void ColumnTuple::getPermutation(bool reverse, size_t limit, int nan_direction_hint, Permutation & res) const
293{
294 size_t rows = size();
295 res.resize(rows);
296 for (size_t i = 0; i < rows; ++i)
297 res[i] = i;
298
299 if (limit >= rows)
300 limit = 0;
301
302 if (limit)
303 {
304 if (reverse)
305 std::partial_sort(res.begin(), res.begin() + limit, res.end(), Less<false>(columns, nan_direction_hint));
306 else
307 std::partial_sort(res.begin(), res.begin() + limit, res.end(), Less<true>(columns, nan_direction_hint));
308 }
309 else
310 {
311 if (reverse)
312 std::sort(res.begin(), res.end(), Less<false>(columns, nan_direction_hint));
313 else
314 std::sort(res.begin(), res.end(), Less<true>(columns, nan_direction_hint));
315 }
316}
317
318void ColumnTuple::gather(ColumnGathererStream & gatherer)
319{
320 gatherer.gather(*this);
321}
322
323void ColumnTuple::reserve(size_t n)
324{
325 const size_t tuple_size = columns.size();
326 for (size_t i = 0; i < tuple_size; ++i)
327 getColumn(i).reserve(n);
328}
329
330size_t ColumnTuple::byteSize() const
331{
332 size_t res = 0;
333 for (const auto & column : columns)
334 res += column->byteSize();
335 return res;
336}
337
338size_t ColumnTuple::allocatedBytes() const
339{
340 size_t res = 0;
341 for (const auto & column : columns)
342 res += column->allocatedBytes();
343 return res;
344}
345
346void ColumnTuple::protect()
347{
348 for (auto & column : columns)
349 column->protect();
350}
351
352void ColumnTuple::getExtremes(Field & min, Field & max) const
353{
354 const size_t tuple_size = columns.size();
355
356 Tuple min_tuple(tuple_size);
357 Tuple max_tuple(tuple_size);
358
359 for (const auto i : ext::range(0, tuple_size))
360 columns[i]->getExtremes(min_tuple[i], max_tuple[i]);
361
362 min = min_tuple;
363 max = max_tuple;
364}
365
366void ColumnTuple::forEachSubcolumn(ColumnCallback callback)
367{
368 for (auto & column : columns)
369 callback(column);
370}
371
372bool ColumnTuple::structureEquals(const IColumn & rhs) const
373{
374 if (auto rhs_tuple = typeid_cast<const ColumnTuple *>(&rhs))
375 {
376 const size_t tuple_size = columns.size();
377 if (tuple_size != rhs_tuple->columns.size())
378 return false;
379
380 for (const auto i : ext::range(0, tuple_size))
381 if (!columns[i]->structureEquals(*rhs_tuple->columns[i]))
382 return false;
383
384 return true;
385 }
386 else
387 return false;
388}
389
390
391}
392