1#pragma once
2
3#include <cstdint>
4#include <string>
5#include <vector>
6#include <common/Types.h>
7#include <Common/intExp.h>
8
9
10namespace DB
11{
12
13/// Data types for representing elementary values from a database in RAM.
14
15struct Null {};
16
17enum class TypeIndex
18{
19 Nothing = 0,
20 UInt8,
21 UInt16,
22 UInt32,
23 UInt64,
24 UInt128,
25 Int8,
26 Int16,
27 Int32,
28 Int64,
29 Int128,
30 Float32,
31 Float64,
32 Date,
33 DateTime,
34 DateTime32 = DateTime,
35 DateTime64,
36 String,
37 FixedString,
38 Enum8,
39 Enum16,
40 Decimal32,
41 Decimal64,
42 Decimal128,
43 UUID,
44 Array,
45 Tuple,
46 Set,
47 Interval,
48 Nullable,
49 Function,
50 AggregateFunction,
51 LowCardinality,
52};
53
54using UInt8 = uint8_t;
55using UInt16 = uint16_t;
56using UInt32 = uint32_t;
57using UInt64 = uint64_t;
58
59using Int8 = int8_t;
60using Int16 = int16_t;
61using Int32 = int32_t;
62using Int64 = int64_t;
63
64using Float32 = float;
65using Float64 = double;
66
67using String = std::string;
68
69
70/** Note that for types not used in DB, IsNumber is false.
71 */
72template <typename T> constexpr bool IsNumber = false;
73
74template <> inline constexpr bool IsNumber<UInt8> = true;
75template <> inline constexpr bool IsNumber<UInt16> = true;
76template <> inline constexpr bool IsNumber<UInt32> = true;
77template <> inline constexpr bool IsNumber<UInt64> = true;
78template <> inline constexpr bool IsNumber<Int8> = true;
79template <> inline constexpr bool IsNumber<Int16> = true;
80template <> inline constexpr bool IsNumber<Int32> = true;
81template <> inline constexpr bool IsNumber<Int64> = true;
82template <> inline constexpr bool IsNumber<Float32> = true;
83template <> inline constexpr bool IsNumber<Float64> = true;
84
85template <typename T> struct TypeName;
86
87template <> struct TypeName<UInt8> { static const char * get() { return "UInt8"; } };
88template <> struct TypeName<UInt16> { static const char * get() { return "UInt16"; } };
89template <> struct TypeName<UInt32> { static const char * get() { return "UInt32"; } };
90template <> struct TypeName<UInt64> { static const char * get() { return "UInt64"; } };
91template <> struct TypeName<Int8> { static const char * get() { return "Int8"; } };
92template <> struct TypeName<Int16> { static const char * get() { return "Int16"; } };
93template <> struct TypeName<Int32> { static const char * get() { return "Int32"; } };
94template <> struct TypeName<Int64> { static const char * get() { return "Int64"; } };
95template <> struct TypeName<Float32> { static const char * get() { return "Float32"; } };
96template <> struct TypeName<Float64> { static const char * get() { return "Float64"; } };
97template <> struct TypeName<String> { static const char * get() { return "String"; } };
98
99template <typename T> struct TypeId;
100template <> struct TypeId<UInt8> { static constexpr const TypeIndex value = TypeIndex::UInt8; };
101template <> struct TypeId<UInt16> { static constexpr const TypeIndex value = TypeIndex::UInt16; };
102template <> struct TypeId<UInt32> { static constexpr const TypeIndex value = TypeIndex::UInt32; };
103template <> struct TypeId<UInt64> { static constexpr const TypeIndex value = TypeIndex::UInt64; };
104template <> struct TypeId<Int8> { static constexpr const TypeIndex value = TypeIndex::Int8; };
105template <> struct TypeId<Int16> { static constexpr const TypeIndex value = TypeIndex::Int16; };
106template <> struct TypeId<Int32> { static constexpr const TypeIndex value = TypeIndex::Int32; };
107template <> struct TypeId<Int64> { static constexpr const TypeIndex value = TypeIndex::Int64; };
108template <> struct TypeId<Float32> { static constexpr const TypeIndex value = TypeIndex::Float32; };
109template <> struct TypeId<Float64> { static constexpr const TypeIndex value = TypeIndex::Float64; };
110
111/// Not a data type in database, defined just for convenience.
112using Strings = std::vector<String>;
113
114
115using Int128 = __int128;
116template <> inline constexpr bool IsNumber<Int128> = true;
117template <> struct TypeName<Int128> { static const char * get() { return "Int128"; } };
118template <> struct TypeId<Int128> { static constexpr const TypeIndex value = TypeIndex::Int128; };
119
120/// Own FieldType for Decimal.
121/// It is only a "storage" for decimal. To perform operations, you also have to provide a scale (number of digits after point).
122template <typename T>
123struct Decimal
124{
125 using NativeType = T;
126
127 Decimal() = default;
128 Decimal(Decimal<T> &&) = default;
129 Decimal(const Decimal<T> &) = default;
130
131 Decimal(const T & value_)
132 : value(value_)
133 {}
134
135 template <typename U>
136 Decimal(const Decimal<U> & x)
137 : value(x)
138 {}
139
140 constexpr Decimal<T> & operator = (Decimal<T> &&) = default;
141 constexpr Decimal<T> & operator = (const Decimal<T> &) = default;
142
143 operator T () const { return value; }
144
145 const Decimal<T> & operator += (const T & x) { value += x; return *this; }
146 const Decimal<T> & operator -= (const T & x) { value -= x; return *this; }
147 const Decimal<T> & operator *= (const T & x) { value *= x; return *this; }
148 const Decimal<T> & operator /= (const T & x) { value /= x; return *this; }
149 const Decimal<T> & operator %= (const T & x) { value %= x; return *this; }
150
151 static T getScaleMultiplier(UInt32 scale);
152
153 T value;
154};
155
156
157using Decimal32 = Decimal<Int32>;
158using Decimal64 = Decimal<Int64>;
159using Decimal128 = Decimal<Int128>;
160
161// TODO (nemkov): consider making a strong typedef
162//using DateTime32 = time_t;
163using DateTime64 = Decimal64;
164
165template <> struct TypeName<Decimal32> { static const char * get() { return "Decimal32"; } };
166template <> struct TypeName<Decimal64> { static const char * get() { return "Decimal64"; } };
167template <> struct TypeName<Decimal128> { static const char * get() { return "Decimal128"; } };
168
169template <> struct TypeId<Decimal32> { static constexpr const TypeIndex value = TypeIndex::Decimal32; };
170template <> struct TypeId<Decimal64> { static constexpr const TypeIndex value = TypeIndex::Decimal64; };
171template <> struct TypeId<Decimal128> { static constexpr const TypeIndex value = TypeIndex::Decimal128; };
172
173template <typename T> constexpr bool IsDecimalNumber = false;
174template <> inline constexpr bool IsDecimalNumber<Decimal32> = true;
175template <> inline constexpr bool IsDecimalNumber<Decimal64> = true;
176template <> inline constexpr bool IsDecimalNumber<Decimal128> = true;
177
178template <typename T> struct NativeType { using Type = T; };
179template <> struct NativeType<Decimal32> { using Type = Int32; };
180template <> struct NativeType<Decimal64> { using Type = Int64; };
181template <> struct NativeType<Decimal128> { using Type = Int128; };
182
183template <> inline Int32 Decimal32::getScaleMultiplier(UInt32 scale) { return common::exp10_i32(scale); }
184template <> inline Int64 Decimal64::getScaleMultiplier(UInt32 scale) { return common::exp10_i64(scale); }
185template <> inline Int128 Decimal128::getScaleMultiplier(UInt32 scale) { return common::exp10_i128(scale); }
186
187inline const char * getTypeName(TypeIndex idx)
188{
189 switch (idx)
190 {
191 case TypeIndex::Nothing: return "Nothing";
192 case TypeIndex::UInt8: return TypeName<UInt8>::get();
193 case TypeIndex::UInt16: return TypeName<UInt16>::get();
194 case TypeIndex::UInt32: return TypeName<UInt32>::get();
195 case TypeIndex::UInt64: return TypeName<UInt64>::get();
196 case TypeIndex::UInt128: return "UInt128";
197 case TypeIndex::Int8: return TypeName<Int8>::get();
198 case TypeIndex::Int16: return TypeName<Int16>::get();
199 case TypeIndex::Int32: return TypeName<Int32>::get();
200 case TypeIndex::Int64: return TypeName<Int64>::get();
201 case TypeIndex::Int128: return TypeName<Int128>::get();
202 case TypeIndex::Float32: return TypeName<Float32>::get();
203 case TypeIndex::Float64: return TypeName<Float64>::get();
204 case TypeIndex::Date: return "Date";
205 case TypeIndex::DateTime: return "DateTime";
206 case TypeIndex::DateTime64: return "DateTime64";
207 case TypeIndex::String: return TypeName<String>::get();
208 case TypeIndex::FixedString: return "FixedString";
209 case TypeIndex::Enum8: return "Enum8";
210 case TypeIndex::Enum16: return "Enum16";
211 case TypeIndex::Decimal32: return TypeName<Decimal32>::get();
212 case TypeIndex::Decimal64: return TypeName<Decimal64>::get();
213 case TypeIndex::Decimal128: return TypeName<Decimal128>::get();
214 case TypeIndex::UUID: return "UUID";
215 case TypeIndex::Array: return "Array";
216 case TypeIndex::Tuple: return "Tuple";
217 case TypeIndex::Set: return "Set";
218 case TypeIndex::Interval: return "Interval";
219 case TypeIndex::Nullable: return "Nullable";
220 case TypeIndex::Function: return "Function";
221 case TypeIndex::AggregateFunction: return "AggregateFunction";
222 case TypeIndex::LowCardinality: return "LowCardinality";
223 }
224
225 __builtin_unreachable();
226}
227
228}
229
230/// Specialization of `std::hash` for the Decimal<T> types.
231namespace std
232{
233 template <typename T>
234 struct hash<DB::Decimal<T>> { size_t operator()(const DB::Decimal<T> & x) const { return hash<T>()(x.value); } };
235
236 template <>
237 struct hash<DB::Decimal128>
238 {
239 size_t operator()(const DB::Decimal128 & x) const
240 {
241 return std::hash<DB::Int64>()(x.value >> 64)
242 ^ std::hash<DB::Int64>()(x.value & std::numeric_limits<DB::UInt64>::max());
243 }
244 };
245}
246