1 | #pragma once |
2 | |
3 | #include <cassert> |
4 | #include <vector> |
5 | #include <algorithm> |
6 | #include <type_traits> |
7 | #include <functional> |
8 | |
9 | #include <Common/Exception.h> |
10 | #include <Common/UInt128.h> |
11 | #include <Core/Types.h> |
12 | #include <Core/Defines.h> |
13 | #include <Core/UUID.h> |
14 | #include <common/DayNum.h> |
15 | #include <common/strong_typedef.h> |
16 | |
17 | |
18 | namespace DB |
19 | { |
20 | |
21 | namespace ErrorCodes |
22 | { |
23 | extern const int BAD_TYPE_OF_FIELD; |
24 | extern const int BAD_GET; |
25 | extern const int NOT_IMPLEMENTED; |
26 | extern const int LOGICAL_ERROR; |
27 | extern const int ILLEGAL_TYPE_OF_ARGUMENT; |
28 | } |
29 | |
30 | template <typename T, typename SFINAE = void> |
31 | struct NearestFieldTypeImpl; |
32 | |
33 | template <typename T> |
34 | using NearestFieldType = typename NearestFieldTypeImpl<T>::Type; |
35 | |
36 | class Field; |
37 | using FieldVector = std::vector<Field>; |
38 | |
39 | /// Array and Tuple use the same storage type -- FieldVector, but we declare |
40 | /// distinct types for them, so that the caller can choose whether it wants to |
41 | /// construct a Field of Array or a Tuple type. An alternative approach would be |
42 | /// to construct both of these types from FieldVector, and have the caller |
43 | /// specify the desired Field type explicitly. |
44 | #define DEFINE_FIELD_VECTOR(X) \ |
45 | struct X : public FieldVector \ |
46 | { \ |
47 | using FieldVector::FieldVector; \ |
48 | } |
49 | |
50 | DEFINE_FIELD_VECTOR(Array); |
51 | DEFINE_FIELD_VECTOR(Tuple); |
52 | |
53 | #undef DEFINE_FIELD_VECTOR |
54 | |
55 | struct AggregateFunctionStateData |
56 | { |
57 | String name; /// Name with arguments. |
58 | String data; |
59 | |
60 | bool operator < (const AggregateFunctionStateData &) const |
61 | { |
62 | throw Exception("Operator < is not implemented for AggregateFunctionStateData." , ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); |
63 | } |
64 | |
65 | bool operator <= (const AggregateFunctionStateData &) const |
66 | { |
67 | throw Exception("Operator <= is not implemented for AggregateFunctionStateData." , ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); |
68 | } |
69 | |
70 | bool operator > (const AggregateFunctionStateData &) const |
71 | { |
72 | throw Exception("Operator > is not implemented for AggregateFunctionStateData." , ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); |
73 | } |
74 | |
75 | bool operator >= (const AggregateFunctionStateData &) const |
76 | { |
77 | throw Exception("Operator >= is not implemented for AggregateFunctionStateData." , ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); |
78 | } |
79 | |
80 | bool operator == (const AggregateFunctionStateData & rhs) const |
81 | { |
82 | if (name != rhs.name) |
83 | throw Exception("Comparing aggregate functions with different types: " + name + " and " + rhs.name, |
84 | ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); |
85 | |
86 | return data == rhs.data; |
87 | } |
88 | }; |
89 | |
90 | template <typename T> bool decimalEqual(T x, T y, UInt32 x_scale, UInt32 y_scale); |
91 | template <typename T> bool decimalLess(T x, T y, UInt32 x_scale, UInt32 y_scale); |
92 | template <typename T> bool decimalLessOrEqual(T x, T y, UInt32 x_scale, UInt32 y_scale); |
93 | |
94 | template <typename T> |
95 | class DecimalField |
96 | { |
97 | public: |
98 | DecimalField(T value, UInt32 scale_) |
99 | : dec(value), |
100 | scale(scale_) |
101 | {} |
102 | |
103 | operator T() const { return dec; } |
104 | T getValue() const { return dec; } |
105 | T getScaleMultiplier() const { return T::getScaleMultiplier(scale); } |
106 | UInt32 getScale() const { return scale; } |
107 | |
108 | template <typename U> |
109 | bool operator < (const DecimalField<U> & r) const |
110 | { |
111 | using MaxType = std::conditional_t<(sizeof(T) > sizeof(U)), T, U>; |
112 | return decimalLess<MaxType>(dec, r.getValue(), scale, r.getScale()); |
113 | } |
114 | |
115 | template <typename U> |
116 | bool operator <= (const DecimalField<U> & r) const |
117 | { |
118 | using MaxType = std::conditional_t<(sizeof(T) > sizeof(U)), T, U>; |
119 | return decimalLessOrEqual<MaxType>(dec, r.getValue(), scale, r.getScale()); |
120 | } |
121 | |
122 | template <typename U> |
123 | bool operator == (const DecimalField<U> & r) const |
124 | { |
125 | using MaxType = std::conditional_t<(sizeof(T) > sizeof(U)), T, U>; |
126 | return decimalEqual<MaxType>(dec, r.getValue(), scale, r.getScale()); |
127 | } |
128 | |
129 | template <typename U> bool operator > (const DecimalField<U> & r) const { return r < *this; } |
130 | template <typename U> bool operator >= (const DecimalField<U> & r) const { return r <= * this; } |
131 | template <typename U> bool operator != (const DecimalField<U> & r) const { return !(*this == r); } |
132 | |
133 | const DecimalField<T> & operator += (const DecimalField<T> & r) |
134 | { |
135 | if (scale != r.getScale()) |
136 | throw Exception("Add different decimal fields" , ErrorCodes::LOGICAL_ERROR); |
137 | dec += r.getValue(); |
138 | return *this; |
139 | } |
140 | |
141 | const DecimalField<T> & operator -= (const DecimalField<T> & r) |
142 | { |
143 | if (scale != r.getScale()) |
144 | throw Exception("Sub different decimal fields" , ErrorCodes::LOGICAL_ERROR); |
145 | dec -= r.getValue(); |
146 | return *this; |
147 | } |
148 | |
149 | private: |
150 | T dec; |
151 | UInt32 scale; |
152 | }; |
153 | |
154 | /// char may be signed or unsigned, and behave identically to signed char or unsigned char, |
155 | /// but they are always three different types. |
156 | /// signedness of char is different in Linux on x86 and Linux on ARM. |
157 | template <> struct NearestFieldTypeImpl<char> { using Type = std::conditional_t<is_signed_v<char>, Int64, UInt64>; }; |
158 | template <> struct NearestFieldTypeImpl<signed char> { using Type = Int64; }; |
159 | template <> struct NearestFieldTypeImpl<unsigned char> { using Type = UInt64; }; |
160 | |
161 | template <> struct NearestFieldTypeImpl<UInt16> { using Type = UInt64; }; |
162 | template <> struct NearestFieldTypeImpl<UInt32> { using Type = UInt64; }; |
163 | |
164 | template <> struct NearestFieldTypeImpl<DayNum> { using Type = UInt64; }; |
165 | template <> struct NearestFieldTypeImpl<UInt128> { using Type = UInt128; }; |
166 | template <> struct NearestFieldTypeImpl<UUID> { using Type = UInt128; }; |
167 | template <> struct NearestFieldTypeImpl<Int16> { using Type = Int64; }; |
168 | template <> struct NearestFieldTypeImpl<Int32> { using Type = Int64; }; |
169 | |
170 | /// long and long long are always different types that may behave identically or not. |
171 | /// This is different on Linux and Mac. |
172 | template <> struct NearestFieldTypeImpl<long> { using Type = Int64; }; |
173 | template <> struct NearestFieldTypeImpl<long long> { using Type = Int64; }; |
174 | template <> struct NearestFieldTypeImpl<unsigned long> { using Type = UInt64; }; |
175 | template <> struct NearestFieldTypeImpl<unsigned long long> { using Type = UInt64; }; |
176 | |
177 | template <> struct NearestFieldTypeImpl<Int128> { using Type = Int128; }; |
178 | template <> struct NearestFieldTypeImpl<Decimal32> { using Type = DecimalField<Decimal32>; }; |
179 | template <> struct NearestFieldTypeImpl<Decimal64> { using Type = DecimalField<Decimal64>; }; |
180 | template <> struct NearestFieldTypeImpl<Decimal128> { using Type = DecimalField<Decimal128>; }; |
181 | template <> struct NearestFieldTypeImpl<DecimalField<Decimal32>> { using Type = DecimalField<Decimal32>; }; |
182 | template <> struct NearestFieldTypeImpl<DecimalField<Decimal64>> { using Type = DecimalField<Decimal64>; }; |
183 | template <> struct NearestFieldTypeImpl<DecimalField<Decimal128>> { using Type = DecimalField<Decimal128>; }; |
184 | template <> struct NearestFieldTypeImpl<Float32> { using Type = Float64; }; |
185 | template <> struct NearestFieldTypeImpl<Float64> { using Type = Float64; }; |
186 | template <> struct NearestFieldTypeImpl<const char *> { using Type = String; }; |
187 | template <> struct NearestFieldTypeImpl<String> { using Type = String; }; |
188 | template <> struct NearestFieldTypeImpl<Array> { using Type = Array; }; |
189 | template <> struct NearestFieldTypeImpl<Tuple> { using Type = Tuple; }; |
190 | template <> struct NearestFieldTypeImpl<bool> { using Type = UInt64; }; |
191 | template <> struct NearestFieldTypeImpl<Null> { using Type = Null; }; |
192 | |
193 | template <> struct NearestFieldTypeImpl<AggregateFunctionStateData> { using Type = AggregateFunctionStateData; }; |
194 | |
195 | // For enum types, use the field type that corresponds to their underlying type. |
196 | template <typename T> |
197 | struct NearestFieldTypeImpl<T, std::enable_if_t<std::is_enum_v<T>>> |
198 | { |
199 | using Type = NearestFieldType<std::underlying_type_t<T>>; |
200 | }; |
201 | |
202 | /** 32 is enough. Round number is used for alignment and for better arithmetic inside std::vector. |
203 | * NOTE: Actually, sizeof(std::string) is 32 when using libc++, so Field is 40 bytes. |
204 | */ |
205 | #define DBMS_MIN_FIELD_SIZE 32 |
206 | |
207 | |
208 | /** Discriminated union of several types. |
209 | * Made for replacement of `boost::variant` |
210 | * is not generalized, |
211 | * but somewhat more efficient, and simpler. |
212 | * |
213 | * Used to represent a single value of one of several types in memory. |
214 | * Warning! Prefer to use chunks of columns instead of single values. See Column.h |
215 | */ |
216 | class Field |
217 | { |
218 | public: |
219 | struct Types |
220 | { |
221 | /// Type tag. |
222 | enum Which |
223 | { |
224 | Null = 0, |
225 | UInt64 = 1, |
226 | Int64 = 2, |
227 | Float64 = 3, |
228 | UInt128 = 4, |
229 | Int128 = 5, |
230 | |
231 | /// Non-POD types. |
232 | |
233 | String = 16, |
234 | Array = 17, |
235 | Tuple = 18, |
236 | Decimal32 = 19, |
237 | Decimal64 = 20, |
238 | Decimal128 = 21, |
239 | AggregateFunctionState = 22, |
240 | }; |
241 | |
242 | static const int MIN_NON_POD = 16; |
243 | |
244 | static const char * toString(Which which) |
245 | { |
246 | switch (which) |
247 | { |
248 | case Null: return "Null" ; |
249 | case UInt64: return "UInt64" ; |
250 | case UInt128: return "UInt128" ; |
251 | case Int64: return "Int64" ; |
252 | case Int128: return "Int128" ; |
253 | case Float64: return "Float64" ; |
254 | case String: return "String" ; |
255 | case Array: return "Array" ; |
256 | case Tuple: return "Tuple" ; |
257 | case Decimal32: return "Decimal32" ; |
258 | case Decimal64: return "Decimal64" ; |
259 | case Decimal128: return "Decimal128" ; |
260 | case AggregateFunctionState: return "AggregateFunctionState" ; |
261 | } |
262 | |
263 | throw Exception("Bad type of Field" , ErrorCodes::BAD_TYPE_OF_FIELD); |
264 | } |
265 | }; |
266 | |
267 | |
268 | /// Returns an identifier for the type or vice versa. |
269 | template <typename T> struct TypeToEnum; |
270 | template <Types::Which which> struct EnumToType; |
271 | |
272 | static bool IsDecimal(Types::Which which) { return which >= Types::Decimal32 && which <= Types::Decimal128; } |
273 | |
274 | Field() |
275 | : which(Types::Null) |
276 | { |
277 | } |
278 | |
279 | /** Despite the presence of a template constructor, this constructor is still needed, |
280 | * since, in its absence, the compiler will still generate the default constructor. |
281 | */ |
282 | Field(const Field & rhs) |
283 | { |
284 | create(rhs); |
285 | } |
286 | |
287 | Field(Field && rhs) |
288 | { |
289 | create(std::move(rhs)); |
290 | } |
291 | |
292 | template <typename T> |
293 | Field(T && rhs, std::enable_if_t<!std::is_same_v<std::decay_t<T>, Field>, void *> = nullptr); |
294 | |
295 | /// Create a string inplace. |
296 | Field(const char * data, size_t size) |
297 | { |
298 | create(data, size); |
299 | } |
300 | |
301 | Field(const unsigned char * data, size_t size) |
302 | { |
303 | create(data, size); |
304 | } |
305 | |
306 | /// NOTE In case when field already has string type, more direct assign is possible. |
307 | void assignString(const char * data, size_t size) |
308 | { |
309 | destroy(); |
310 | create(data, size); |
311 | } |
312 | |
313 | void assignString(const unsigned char * data, size_t size) |
314 | { |
315 | destroy(); |
316 | create(data, size); |
317 | } |
318 | |
319 | Field & operator= (const Field & rhs) |
320 | { |
321 | if (this != &rhs) |
322 | { |
323 | if (which != rhs.which) |
324 | { |
325 | destroy(); |
326 | create(rhs); |
327 | } |
328 | else |
329 | assign(rhs); /// This assigns string or vector without deallocation of existing buffer. |
330 | } |
331 | return *this; |
332 | } |
333 | |
334 | Field & operator= (Field && rhs) |
335 | { |
336 | if (this != &rhs) |
337 | { |
338 | if (which != rhs.which) |
339 | { |
340 | destroy(); |
341 | create(std::move(rhs)); |
342 | } |
343 | else |
344 | assign(std::move(rhs)); |
345 | } |
346 | return *this; |
347 | } |
348 | |
349 | template <typename T> |
350 | std::enable_if_t<!std::is_same_v<std::decay_t<T>, Field>, Field &> |
351 | operator= (T && rhs); |
352 | |
353 | ~Field() |
354 | { |
355 | destroy(); |
356 | } |
357 | |
358 | |
359 | Types::Which getType() const { return which; } |
360 | const char * getTypeName() const { return Types::toString(which); } |
361 | |
362 | bool isNull() const { return which == Types::Null; } |
363 | |
364 | |
365 | template <typename T> |
366 | T & get(); |
367 | |
368 | template <typename T> |
369 | const T & get() const |
370 | { |
371 | auto mutable_this = const_cast<std::decay_t<decltype(*this)> *>(this); |
372 | return mutable_this->get<T>(); |
373 | } |
374 | |
375 | template <typename T> |
376 | T & reinterpret(); |
377 | |
378 | template <typename T> |
379 | const T & reinterpret() const |
380 | { |
381 | auto mutable_this = const_cast<std::decay_t<decltype(*this)> *>(this); |
382 | return mutable_this->reinterpret<T>(); |
383 | } |
384 | |
385 | template <typename T> bool tryGet(T & result) |
386 | { |
387 | const Types::Which requested = TypeToEnum<std::decay_t<T>>::value; |
388 | if (which != requested) |
389 | return false; |
390 | result = get<T>(); |
391 | return true; |
392 | } |
393 | |
394 | template <typename T> bool tryGet(T & result) const |
395 | { |
396 | const Types::Which requested = TypeToEnum<std::decay_t<T>>::value; |
397 | if (which != requested) |
398 | return false; |
399 | result = get<T>(); |
400 | return true; |
401 | } |
402 | |
403 | template <typename T> T & safeGet() |
404 | { |
405 | const Types::Which requested = TypeToEnum<std::decay_t<T>>::value; |
406 | if (which != requested) |
407 | throw Exception("Bad get: has " + std::string(getTypeName()) + ", requested " + std::string(Types::toString(requested)), ErrorCodes::BAD_GET); |
408 | return get<T>(); |
409 | } |
410 | |
411 | template <typename T> const T & safeGet() const |
412 | { |
413 | const Types::Which requested = TypeToEnum<std::decay_t<T>>::value; |
414 | if (which != requested) |
415 | throw Exception("Bad get: has " + std::string(getTypeName()) + ", requested " + std::string(Types::toString(requested)), ErrorCodes::BAD_GET); |
416 | return get<T>(); |
417 | } |
418 | |
419 | |
420 | bool operator< (const Field & rhs) const |
421 | { |
422 | if (which < rhs.which) |
423 | return true; |
424 | if (which > rhs.which) |
425 | return false; |
426 | |
427 | switch (which) |
428 | { |
429 | case Types::Null: return false; |
430 | case Types::UInt64: return get<UInt64>() < rhs.get<UInt64>(); |
431 | case Types::UInt128: return get<UInt128>() < rhs.get<UInt128>(); |
432 | case Types::Int64: return get<Int64>() < rhs.get<Int64>(); |
433 | case Types::Int128: return get<Int128>() < rhs.get<Int128>(); |
434 | case Types::Float64: return get<Float64>() < rhs.get<Float64>(); |
435 | case Types::String: return get<String>() < rhs.get<String>(); |
436 | case Types::Array: return get<Array>() < rhs.get<Array>(); |
437 | case Types::Tuple: return get<Tuple>() < rhs.get<Tuple>(); |
438 | case Types::Decimal32: return get<DecimalField<Decimal32>>() < rhs.get<DecimalField<Decimal32>>(); |
439 | case Types::Decimal64: return get<DecimalField<Decimal64>>() < rhs.get<DecimalField<Decimal64>>(); |
440 | case Types::Decimal128: return get<DecimalField<Decimal128>>() < rhs.get<DecimalField<Decimal128>>(); |
441 | case Types::AggregateFunctionState: return get<AggregateFunctionStateData>() < rhs.get<AggregateFunctionStateData>(); |
442 | } |
443 | |
444 | throw Exception("Bad type of Field" , ErrorCodes::BAD_TYPE_OF_FIELD); |
445 | } |
446 | |
447 | bool operator> (const Field & rhs) const |
448 | { |
449 | return rhs < *this; |
450 | } |
451 | |
452 | bool operator<= (const Field & rhs) const |
453 | { |
454 | if (which < rhs.which) |
455 | return true; |
456 | if (which > rhs.which) |
457 | return false; |
458 | |
459 | switch (which) |
460 | { |
461 | case Types::Null: return true; |
462 | case Types::UInt64: return get<UInt64>() <= rhs.get<UInt64>(); |
463 | case Types::UInt128: return get<UInt128>() <= rhs.get<UInt128>(); |
464 | case Types::Int64: return get<Int64>() <= rhs.get<Int64>(); |
465 | case Types::Int128: return get<Int128>() <= rhs.get<Int128>(); |
466 | case Types::Float64: return get<Float64>() <= rhs.get<Float64>(); |
467 | case Types::String: return get<String>() <= rhs.get<String>(); |
468 | case Types::Array: return get<Array>() <= rhs.get<Array>(); |
469 | case Types::Tuple: return get<Tuple>() <= rhs.get<Tuple>(); |
470 | case Types::Decimal32: return get<DecimalField<Decimal32>>() <= rhs.get<DecimalField<Decimal32>>(); |
471 | case Types::Decimal64: return get<DecimalField<Decimal64>>() <= rhs.get<DecimalField<Decimal64>>(); |
472 | case Types::Decimal128: return get<DecimalField<Decimal128>>() <= rhs.get<DecimalField<Decimal128>>(); |
473 | case Types::AggregateFunctionState: return get<AggregateFunctionStateData>() <= rhs.get<AggregateFunctionStateData>(); |
474 | } |
475 | |
476 | throw Exception("Bad type of Field" , ErrorCodes::BAD_TYPE_OF_FIELD); |
477 | } |
478 | |
479 | bool operator>= (const Field & rhs) const |
480 | { |
481 | return rhs <= *this; |
482 | } |
483 | |
484 | // More like bitwise equality as opposed to semantic equality: |
485 | // Null equals Null and NaN equals NaN. |
486 | bool operator== (const Field & rhs) const |
487 | { |
488 | if (which != rhs.which) |
489 | return false; |
490 | |
491 | switch (which) |
492 | { |
493 | case Types::Null: return true; |
494 | case Types::UInt64: return get<UInt64>() == rhs.get<UInt64>(); |
495 | case Types::Int64: return get<Int64>() == rhs.get<Int64>(); |
496 | case Types::Float64: |
497 | { |
498 | // Compare as UInt64 so that NaNs compare as equal. |
499 | return reinterpret<UInt64>() == rhs.reinterpret<UInt64>(); |
500 | } |
501 | case Types::String: return get<String>() == rhs.get<String>(); |
502 | case Types::Array: return get<Array>() == rhs.get<Array>(); |
503 | case Types::Tuple: return get<Tuple>() == rhs.get<Tuple>(); |
504 | case Types::UInt128: return get<UInt128>() == rhs.get<UInt128>(); |
505 | case Types::Int128: return get<Int128>() == rhs.get<Int128>(); |
506 | case Types::Decimal32: return get<DecimalField<Decimal32>>() == rhs.get<DecimalField<Decimal32>>(); |
507 | case Types::Decimal64: return get<DecimalField<Decimal64>>() == rhs.get<DecimalField<Decimal64>>(); |
508 | case Types::Decimal128: return get<DecimalField<Decimal128>>() == rhs.get<DecimalField<Decimal128>>(); |
509 | case Types::AggregateFunctionState: return get<AggregateFunctionStateData>() == rhs.get<AggregateFunctionStateData>(); |
510 | } |
511 | |
512 | throw Exception("Bad type of Field" , ErrorCodes::BAD_TYPE_OF_FIELD); |
513 | } |
514 | |
515 | bool operator!= (const Field & rhs) const |
516 | { |
517 | return !(*this == rhs); |
518 | } |
519 | |
520 | /// Field is template parameter, to allow universal reference for field, |
521 | /// that is useful for const and non-const . |
522 | template <typename F, typename FieldRef> |
523 | static auto dispatch(F && f, FieldRef && field) |
524 | { |
525 | switch (field.which) |
526 | { |
527 | case Types::Null: return f(field.template get<Null>()); |
528 | // gcc 8.2.1 |
529 | #if !__clang__ |
530 | #pragma GCC diagnostic push |
531 | #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" |
532 | #endif |
533 | case Types::UInt64: return f(field.template get<UInt64>()); |
534 | case Types::UInt128: return f(field.template get<UInt128>()); |
535 | case Types::Int64: return f(field.template get<Int64>()); |
536 | case Types::Float64: return f(field.template get<Float64>()); |
537 | case Types::String: return f(field.template get<String>()); |
538 | case Types::Array: return f(field.template get<Array>()); |
539 | case Types::Tuple: return f(field.template get<Tuple>()); |
540 | #if !__clang__ |
541 | #pragma GCC diagnostic pop |
542 | #endif |
543 | case Types::Decimal32: return f(field.template get<DecimalField<Decimal32>>()); |
544 | case Types::Decimal64: return f(field.template get<DecimalField<Decimal64>>()); |
545 | case Types::Decimal128: return f(field.template get<DecimalField<Decimal128>>()); |
546 | case Types::AggregateFunctionState: return f(field.template get<AggregateFunctionStateData>()); |
547 | case Types::Int128: |
548 | // TODO: investigate where we need Int128 Fields. There are no |
549 | // field visitors that support them, and they only arise indirectly |
550 | // in some functions that use Decimal columns: they get the |
551 | // underlying Field value with get<Int128>(). Probably should be |
552 | // switched to DecimalField, but this is a whole endeavor in itself. |
553 | throw Exception("Unexpected Int128 in Field::dispatch()" , ErrorCodes::LOGICAL_ERROR); |
554 | } |
555 | |
556 | // GCC 9 complains that control reaches the end, despite that we handle |
557 | // all the cases above (maybe because of throw?). Return something to |
558 | // silence it. |
559 | Null null{}; |
560 | return f(null); |
561 | } |
562 | |
563 | |
564 | private: |
565 | std::aligned_union_t<DBMS_MIN_FIELD_SIZE - sizeof(Types::Which), |
566 | Null, UInt64, UInt128, Int64, Int128, Float64, String, Array, Tuple, |
567 | DecimalField<Decimal32>, DecimalField<Decimal64>, DecimalField<Decimal128>, AggregateFunctionStateData |
568 | > storage; |
569 | |
570 | Types::Which which; |
571 | |
572 | |
573 | /// Assuming there was no allocated state or it was deallocated (see destroy). |
574 | template <typename T> |
575 | void createConcrete(T && x) |
576 | { |
577 | using UnqualifiedType = std::decay_t<T>; |
578 | |
579 | // In both Field and PODArray, small types may be stored as wider types, |
580 | // e.g. char is stored as UInt64. Field can return this extended value |
581 | // with get<StorageType>(). To avoid uninitialized results from get(), |
582 | // we must initialize the entire wide stored type, and not just the |
583 | // nominal type. |
584 | using StorageType = NearestFieldType<UnqualifiedType>; |
585 | new (&storage) StorageType(std::forward<T>(x)); |
586 | which = TypeToEnum<UnqualifiedType>::value; |
587 | } |
588 | |
589 | /// Assuming same types. |
590 | template <typename T> |
591 | void assignConcrete(T && x) |
592 | { |
593 | using JustT = std::decay_t<T>; |
594 | assert(which == TypeToEnum<JustT>::value); |
595 | JustT * MAY_ALIAS ptr = reinterpret_cast<JustT *>(&storage); |
596 | *ptr = std::forward<T>(x); |
597 | } |
598 | |
599 | |
600 | void create(const Field & x) |
601 | { |
602 | dispatch([this] (auto & value) { createConcrete(value); }, x); |
603 | } |
604 | |
605 | void create(Field && x) |
606 | { |
607 | dispatch([this] (auto & value) { createConcrete(std::move(value)); }, x); |
608 | } |
609 | |
610 | void assign(const Field & x) |
611 | { |
612 | dispatch([this] (auto & value) { assignConcrete(value); }, x); |
613 | } |
614 | |
615 | void assign(Field && x) |
616 | { |
617 | dispatch([this] (auto & value) { assignConcrete(std::move(value)); }, x); |
618 | } |
619 | |
620 | |
621 | void create(const char * data, size_t size) |
622 | { |
623 | new (&storage) String(data, size); |
624 | which = Types::String; |
625 | } |
626 | |
627 | void create(const unsigned char * data, size_t size) |
628 | { |
629 | create(reinterpret_cast<const char *>(data), size); |
630 | } |
631 | |
632 | ALWAYS_INLINE void destroy() |
633 | { |
634 | if (which < Types::MIN_NON_POD) |
635 | return; |
636 | |
637 | switch (which) |
638 | { |
639 | case Types::String: |
640 | destroy<String>(); |
641 | break; |
642 | case Types::Array: |
643 | destroy<Array>(); |
644 | break; |
645 | case Types::Tuple: |
646 | destroy<Tuple>(); |
647 | break; |
648 | case Types::AggregateFunctionState: |
649 | destroy<AggregateFunctionStateData>(); |
650 | break; |
651 | default: |
652 | break; |
653 | } |
654 | |
655 | which = Types::Null; /// for exception safety in subsequent calls to destroy and create, when create fails. |
656 | } |
657 | |
658 | template <typename T> |
659 | void destroy() |
660 | { |
661 | T * MAY_ALIAS ptr = reinterpret_cast<T*>(&storage); |
662 | ptr->~T(); |
663 | } |
664 | }; |
665 | |
666 | #undef DBMS_MIN_FIELD_SIZE |
667 | |
668 | |
669 | template <> struct Field::TypeToEnum<Null> { static const Types::Which value = Types::Null; }; |
670 | template <> struct Field::TypeToEnum<UInt64> { static const Types::Which value = Types::UInt64; }; |
671 | template <> struct Field::TypeToEnum<UInt128> { static const Types::Which value = Types::UInt128; }; |
672 | template <> struct Field::TypeToEnum<Int64> { static const Types::Which value = Types::Int64; }; |
673 | template <> struct Field::TypeToEnum<Int128> { static const Types::Which value = Types::Int128; }; |
674 | template <> struct Field::TypeToEnum<Float64> { static const Types::Which value = Types::Float64; }; |
675 | template <> struct Field::TypeToEnum<String> { static const Types::Which value = Types::String; }; |
676 | template <> struct Field::TypeToEnum<Array> { static const Types::Which value = Types::Array; }; |
677 | template <> struct Field::TypeToEnum<Tuple> { static const Types::Which value = Types::Tuple; }; |
678 | template <> struct Field::TypeToEnum<DecimalField<Decimal32>>{ static const Types::Which value = Types::Decimal32; }; |
679 | template <> struct Field::TypeToEnum<DecimalField<Decimal64>>{ static const Types::Which value = Types::Decimal64; }; |
680 | template <> struct Field::TypeToEnum<DecimalField<Decimal128>>{ static const Types::Which value = Types::Decimal128; }; |
681 | template <> struct Field::TypeToEnum<AggregateFunctionStateData>{ static const Types::Which value = Types::AggregateFunctionState; }; |
682 | |
683 | template <> struct Field::EnumToType<Field::Types::Null> { using Type = Null; }; |
684 | template <> struct Field::EnumToType<Field::Types::UInt64> { using Type = UInt64; }; |
685 | template <> struct Field::EnumToType<Field::Types::UInt128> { using Type = UInt128; }; |
686 | template <> struct Field::EnumToType<Field::Types::Int64> { using Type = Int64; }; |
687 | template <> struct Field::EnumToType<Field::Types::Int128> { using Type = Int128; }; |
688 | template <> struct Field::EnumToType<Field::Types::Float64> { using Type = Float64; }; |
689 | template <> struct Field::EnumToType<Field::Types::String> { using Type = String; }; |
690 | template <> struct Field::EnumToType<Field::Types::Array> { using Type = Array; }; |
691 | template <> struct Field::EnumToType<Field::Types::Tuple> { using Type = Tuple; }; |
692 | template <> struct Field::EnumToType<Field::Types::Decimal32> { using Type = DecimalField<Decimal32>; }; |
693 | template <> struct Field::EnumToType<Field::Types::Decimal64> { using Type = DecimalField<Decimal64>; }; |
694 | template <> struct Field::EnumToType<Field::Types::Decimal128> { using Type = DecimalField<Decimal128>; }; |
695 | template <> struct Field::EnumToType<Field::Types::AggregateFunctionState> { using Type = DecimalField<AggregateFunctionStateData>; }; |
696 | |
697 | inline constexpr bool isInt64FieldType(Field::Types::Which t) |
698 | { |
699 | return t == Field::Types::Int64 |
700 | || t == Field::Types::UInt64; |
701 | } |
702 | |
703 | // Field value getter with type checking in debug builds. |
704 | template <typename T> |
705 | T & Field::get() |
706 | { |
707 | using ValueType = std::decay_t<T>; |
708 | |
709 | #ifndef NDEBUG |
710 | // Disregard signedness when converting between int64 types. |
711 | constexpr Field::Types::Which target = TypeToEnum<NearestFieldType<ValueType>>::value; |
712 | assert(target == which |
713 | || (isInt64FieldType(target) && isInt64FieldType(which))); |
714 | #endif |
715 | |
716 | ValueType * MAY_ALIAS ptr = reinterpret_cast<ValueType *>(&storage); |
717 | return *ptr; |
718 | } |
719 | |
720 | template <typename T> |
721 | T & Field::reinterpret() |
722 | { |
723 | using ValueType = std::decay_t<T>; |
724 | ValueType * MAY_ALIAS ptr = reinterpret_cast<ValueType *>(&storage); |
725 | return *ptr; |
726 | } |
727 | |
728 | template <typename T> |
729 | T get(const Field & field) |
730 | { |
731 | return field.template get<T>(); |
732 | } |
733 | |
734 | template <typename T> |
735 | T get(Field & field) |
736 | { |
737 | return field.template get<T>(); |
738 | } |
739 | |
740 | template <typename T> |
741 | T safeGet(const Field & field) |
742 | { |
743 | return field.template safeGet<T>(); |
744 | } |
745 | |
746 | template <typename T> |
747 | T safeGet(Field & field) |
748 | { |
749 | return field.template safeGet<T>(); |
750 | } |
751 | |
752 | |
753 | template <> struct TypeName<Array> { static std::string get() { return "Array" ; } }; |
754 | template <> struct TypeName<Tuple> { static std::string get() { return "Tuple" ; } }; |
755 | template <> struct TypeName<AggregateFunctionStateData> { static std::string get() { return "AggregateFunctionState" ; } }; |
756 | |
757 | template <typename T> |
758 | decltype(auto) castToNearestFieldType(T && x) |
759 | { |
760 | using U = NearestFieldType<std::decay_t<T>>; |
761 | if constexpr (std::is_same_v<std::decay_t<T>, U>) |
762 | return std::forward<T>(x); |
763 | else |
764 | return U(x); |
765 | } |
766 | |
767 | /// This (rather tricky) code is to avoid ambiguity in expressions like |
768 | /// Field f = 1; |
769 | /// instead of |
770 | /// Field f = Int64(1); |
771 | /// Things to note: |
772 | /// 1. float <--> int needs explicit cast |
773 | /// 2. customized types needs explicit cast |
774 | template <typename T> |
775 | Field::Field(T && rhs, std::enable_if_t<!std::is_same_v<std::decay_t<T>, Field>, void *>) |
776 | { |
777 | auto && val = castToNearestFieldType(std::forward<T>(rhs)); |
778 | createConcrete(std::forward<decltype(val)>(val)); |
779 | } |
780 | |
781 | template <typename T> |
782 | std::enable_if_t<!std::is_same_v<std::decay_t<T>, Field>, Field &> |
783 | Field::operator= (T && rhs) |
784 | { |
785 | auto && val = castToNearestFieldType(std::forward<T>(rhs)); |
786 | using U = decltype(val); |
787 | if (which != TypeToEnum<std::decay_t<U>>::value) |
788 | { |
789 | destroy(); |
790 | createConcrete(std::forward<U>(val)); |
791 | } |
792 | else |
793 | assignConcrete(std::forward<U>(val)); |
794 | |
795 | return *this; |
796 | } |
797 | |
798 | |
799 | class ReadBuffer; |
800 | class WriteBuffer; |
801 | |
802 | /// It is assumed that all elements of the array have the same type. |
803 | void readBinary(Array & x, ReadBuffer & buf); |
804 | |
805 | [[noreturn]] inline void readText(Array &, ReadBuffer &) { throw Exception("Cannot read Array." , ErrorCodes::NOT_IMPLEMENTED); } |
806 | [[noreturn]] inline void readQuoted(Array &, ReadBuffer &) { throw Exception("Cannot read Array." , ErrorCodes::NOT_IMPLEMENTED); } |
807 | |
808 | /// It is assumed that all elements of the array have the same type. |
809 | /// Also write size and type into buf. UInt64 and Int64 is written in variadic size form |
810 | void writeBinary(const Array & x, WriteBuffer & buf); |
811 | |
812 | void writeText(const Array & x, WriteBuffer & buf); |
813 | |
814 | [[noreturn]] inline void writeQuoted(const Array &, WriteBuffer &) { throw Exception("Cannot write Array quoted." , ErrorCodes::NOT_IMPLEMENTED); } |
815 | |
816 | void readBinary(Tuple & x, ReadBuffer & buf); |
817 | |
818 | [[noreturn]] inline void readText(Tuple &, ReadBuffer &) { throw Exception("Cannot read Tuple." , ErrorCodes::NOT_IMPLEMENTED); } |
819 | [[noreturn]] inline void readQuoted(Tuple &, ReadBuffer &) { throw Exception("Cannot read Tuple." , ErrorCodes::NOT_IMPLEMENTED); } |
820 | |
821 | void writeBinary(const Tuple & x, WriteBuffer & buf); |
822 | |
823 | void writeText(const Tuple & x, WriteBuffer & buf); |
824 | |
825 | void writeFieldText(const Field & x, WriteBuffer & buf); |
826 | |
827 | [[noreturn]] inline void writeQuoted(const Tuple &, WriteBuffer &) { throw Exception("Cannot write Tuple quoted." , ErrorCodes::NOT_IMPLEMENTED); } |
828 | } |
829 | |