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
18namespace DB
19{
20
21namespace 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
30template <typename T, typename SFINAE = void>
31struct NearestFieldTypeImpl;
32
33template <typename T>
34using NearestFieldType = typename NearestFieldTypeImpl<T>::Type;
35
36class Field;
37using 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) \
45struct X : public FieldVector \
46{ \
47 using FieldVector::FieldVector; \
48}
49
50DEFINE_FIELD_VECTOR(Array);
51DEFINE_FIELD_VECTOR(Tuple);
52
53#undef DEFINE_FIELD_VECTOR
54
55struct 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
90template <typename T> bool decimalEqual(T x, T y, UInt32 x_scale, UInt32 y_scale);
91template <typename T> bool decimalLess(T x, T y, UInt32 x_scale, UInt32 y_scale);
92template <typename T> bool decimalLessOrEqual(T x, T y, UInt32 x_scale, UInt32 y_scale);
93
94template <typename T>
95class DecimalField
96{
97public:
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
149private:
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.
157template <> struct NearestFieldTypeImpl<char> { using Type = std::conditional_t<is_signed_v<char>, Int64, UInt64>; };
158template <> struct NearestFieldTypeImpl<signed char> { using Type = Int64; };
159template <> struct NearestFieldTypeImpl<unsigned char> { using Type = UInt64; };
160
161template <> struct NearestFieldTypeImpl<UInt16> { using Type = UInt64; };
162template <> struct NearestFieldTypeImpl<UInt32> { using Type = UInt64; };
163
164template <> struct NearestFieldTypeImpl<DayNum> { using Type = UInt64; };
165template <> struct NearestFieldTypeImpl<UInt128> { using Type = UInt128; };
166template <> struct NearestFieldTypeImpl<UUID> { using Type = UInt128; };
167template <> struct NearestFieldTypeImpl<Int16> { using Type = Int64; };
168template <> 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.
172template <> struct NearestFieldTypeImpl<long> { using Type = Int64; };
173template <> struct NearestFieldTypeImpl<long long> { using Type = Int64; };
174template <> struct NearestFieldTypeImpl<unsigned long> { using Type = UInt64; };
175template <> struct NearestFieldTypeImpl<unsigned long long> { using Type = UInt64; };
176
177template <> struct NearestFieldTypeImpl<Int128> { using Type = Int128; };
178template <> struct NearestFieldTypeImpl<Decimal32> { using Type = DecimalField<Decimal32>; };
179template <> struct NearestFieldTypeImpl<Decimal64> { using Type = DecimalField<Decimal64>; };
180template <> struct NearestFieldTypeImpl<Decimal128> { using Type = DecimalField<Decimal128>; };
181template <> struct NearestFieldTypeImpl<DecimalField<Decimal32>> { using Type = DecimalField<Decimal32>; };
182template <> struct NearestFieldTypeImpl<DecimalField<Decimal64>> { using Type = DecimalField<Decimal64>; };
183template <> struct NearestFieldTypeImpl<DecimalField<Decimal128>> { using Type = DecimalField<Decimal128>; };
184template <> struct NearestFieldTypeImpl<Float32> { using Type = Float64; };
185template <> struct NearestFieldTypeImpl<Float64> { using Type = Float64; };
186template <> struct NearestFieldTypeImpl<const char *> { using Type = String; };
187template <> struct NearestFieldTypeImpl<String> { using Type = String; };
188template <> struct NearestFieldTypeImpl<Array> { using Type = Array; };
189template <> struct NearestFieldTypeImpl<Tuple> { using Type = Tuple; };
190template <> struct NearestFieldTypeImpl<bool> { using Type = UInt64; };
191template <> struct NearestFieldTypeImpl<Null> { using Type = Null; };
192
193template <> struct NearestFieldTypeImpl<AggregateFunctionStateData> { using Type = AggregateFunctionStateData; };
194
195// For enum types, use the field type that corresponds to their underlying type.
196template <typename T>
197struct 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 */
216class Field
217{
218public:
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
564private:
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
669template <> struct Field::TypeToEnum<Null> { static const Types::Which value = Types::Null; };
670template <> struct Field::TypeToEnum<UInt64> { static const Types::Which value = Types::UInt64; };
671template <> struct Field::TypeToEnum<UInt128> { static const Types::Which value = Types::UInt128; };
672template <> struct Field::TypeToEnum<Int64> { static const Types::Which value = Types::Int64; };
673template <> struct Field::TypeToEnum<Int128> { static const Types::Which value = Types::Int128; };
674template <> struct Field::TypeToEnum<Float64> { static const Types::Which value = Types::Float64; };
675template <> struct Field::TypeToEnum<String> { static const Types::Which value = Types::String; };
676template <> struct Field::TypeToEnum<Array> { static const Types::Which value = Types::Array; };
677template <> struct Field::TypeToEnum<Tuple> { static const Types::Which value = Types::Tuple; };
678template <> struct Field::TypeToEnum<DecimalField<Decimal32>>{ static const Types::Which value = Types::Decimal32; };
679template <> struct Field::TypeToEnum<DecimalField<Decimal64>>{ static const Types::Which value = Types::Decimal64; };
680template <> struct Field::TypeToEnum<DecimalField<Decimal128>>{ static const Types::Which value = Types::Decimal128; };
681template <> struct Field::TypeToEnum<AggregateFunctionStateData>{ static const Types::Which value = Types::AggregateFunctionState; };
682
683template <> struct Field::EnumToType<Field::Types::Null> { using Type = Null; };
684template <> struct Field::EnumToType<Field::Types::UInt64> { using Type = UInt64; };
685template <> struct Field::EnumToType<Field::Types::UInt128> { using Type = UInt128; };
686template <> struct Field::EnumToType<Field::Types::Int64> { using Type = Int64; };
687template <> struct Field::EnumToType<Field::Types::Int128> { using Type = Int128; };
688template <> struct Field::EnumToType<Field::Types::Float64> { using Type = Float64; };
689template <> struct Field::EnumToType<Field::Types::String> { using Type = String; };
690template <> struct Field::EnumToType<Field::Types::Array> { using Type = Array; };
691template <> struct Field::EnumToType<Field::Types::Tuple> { using Type = Tuple; };
692template <> struct Field::EnumToType<Field::Types::Decimal32> { using Type = DecimalField<Decimal32>; };
693template <> struct Field::EnumToType<Field::Types::Decimal64> { using Type = DecimalField<Decimal64>; };
694template <> struct Field::EnumToType<Field::Types::Decimal128> { using Type = DecimalField<Decimal128>; };
695template <> struct Field::EnumToType<Field::Types::AggregateFunctionState> { using Type = DecimalField<AggregateFunctionStateData>; };
696
697inline 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.
704template <typename T>
705T & 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
720template <typename T>
721T & Field::reinterpret()
722{
723 using ValueType = std::decay_t<T>;
724 ValueType * MAY_ALIAS ptr = reinterpret_cast<ValueType *>(&storage);
725 return *ptr;
726}
727
728template <typename T>
729T get(const Field & field)
730{
731 return field.template get<T>();
732}
733
734template <typename T>
735T get(Field & field)
736{
737 return field.template get<T>();
738}
739
740template <typename T>
741T safeGet(const Field & field)
742{
743 return field.template safeGet<T>();
744}
745
746template <typename T>
747T safeGet(Field & field)
748{
749 return field.template safeGet<T>();
750}
751
752
753template <> struct TypeName<Array> { static std::string get() { return "Array"; } };
754template <> struct TypeName<Tuple> { static std::string get() { return "Tuple"; } };
755template <> struct TypeName<AggregateFunctionStateData> { static std::string get() { return "AggregateFunctionState"; } };
756
757template <typename T>
758decltype(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
774template <typename T>
775Field::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
781template <typename T>
782std::enable_if_t<!std::is_same_v<std::decay_t<T>, Field>, Field &>
783Field::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
799class ReadBuffer;
800class WriteBuffer;
801
802/// It is assumed that all elements of the array have the same type.
803void 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
810void writeBinary(const Array & x, WriteBuffer & buf);
811
812void 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
816void 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
821void writeBinary(const Tuple & x, WriteBuffer & buf);
822
823void writeText(const Tuple & x, WriteBuffer & buf);
824
825void 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