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 | |
10 | namespace DB |
11 | { |
12 | |
13 | /// Data types for representing elementary values from a database in RAM. |
14 | |
15 | struct Null {}; |
16 | |
17 | enum 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 | |
54 | using UInt8 = uint8_t; |
55 | using UInt16 = uint16_t; |
56 | using UInt32 = uint32_t; |
57 | using UInt64 = uint64_t; |
58 | |
59 | using Int8 = int8_t; |
60 | using Int16 = int16_t; |
61 | using Int32 = int32_t; |
62 | using Int64 = int64_t; |
63 | |
64 | using Float32 = float; |
65 | using Float64 = double; |
66 | |
67 | using String = std::string; |
68 | |
69 | |
70 | /** Note that for types not used in DB, IsNumber is false. |
71 | */ |
72 | template <typename T> constexpr bool IsNumber = false; |
73 | |
74 | template <> inline constexpr bool IsNumber<UInt8> = true; |
75 | template <> inline constexpr bool IsNumber<UInt16> = true; |
76 | template <> inline constexpr bool IsNumber<UInt32> = true; |
77 | template <> inline constexpr bool IsNumber<UInt64> = true; |
78 | template <> inline constexpr bool IsNumber<Int8> = true; |
79 | template <> inline constexpr bool IsNumber<Int16> = true; |
80 | template <> inline constexpr bool IsNumber<Int32> = true; |
81 | template <> inline constexpr bool IsNumber<Int64> = true; |
82 | template <> inline constexpr bool IsNumber<Float32> = true; |
83 | template <> inline constexpr bool IsNumber<Float64> = true; |
84 | |
85 | template <typename T> struct TypeName; |
86 | |
87 | template <> struct TypeName<UInt8> { static const char * get() { return "UInt8" ; } }; |
88 | template <> struct TypeName<UInt16> { static const char * get() { return "UInt16" ; } }; |
89 | template <> struct TypeName<UInt32> { static const char * get() { return "UInt32" ; } }; |
90 | template <> struct TypeName<UInt64> { static const char * get() { return "UInt64" ; } }; |
91 | template <> struct TypeName<Int8> { static const char * get() { return "Int8" ; } }; |
92 | template <> struct TypeName<Int16> { static const char * get() { return "Int16" ; } }; |
93 | template <> struct TypeName<Int32> { static const char * get() { return "Int32" ; } }; |
94 | template <> struct TypeName<Int64> { static const char * get() { return "Int64" ; } }; |
95 | template <> struct TypeName<Float32> { static const char * get() { return "Float32" ; } }; |
96 | template <> struct TypeName<Float64> { static const char * get() { return "Float64" ; } }; |
97 | template <> struct TypeName<String> { static const char * get() { return "String" ; } }; |
98 | |
99 | template <typename T> struct TypeId; |
100 | template <> struct TypeId<UInt8> { static constexpr const TypeIndex value = TypeIndex::UInt8; }; |
101 | template <> struct TypeId<UInt16> { static constexpr const TypeIndex value = TypeIndex::UInt16; }; |
102 | template <> struct TypeId<UInt32> { static constexpr const TypeIndex value = TypeIndex::UInt32; }; |
103 | template <> struct TypeId<UInt64> { static constexpr const TypeIndex value = TypeIndex::UInt64; }; |
104 | template <> struct TypeId<Int8> { static constexpr const TypeIndex value = TypeIndex::Int8; }; |
105 | template <> struct TypeId<Int16> { static constexpr const TypeIndex value = TypeIndex::Int16; }; |
106 | template <> struct TypeId<Int32> { static constexpr const TypeIndex value = TypeIndex::Int32; }; |
107 | template <> struct TypeId<Int64> { static constexpr const TypeIndex value = TypeIndex::Int64; }; |
108 | template <> struct TypeId<Float32> { static constexpr const TypeIndex value = TypeIndex::Float32; }; |
109 | template <> struct TypeId<Float64> { static constexpr const TypeIndex value = TypeIndex::Float64; }; |
110 | |
111 | /// Not a data type in database, defined just for convenience. |
112 | using Strings = std::vector<String>; |
113 | |
114 | |
115 | using Int128 = __int128; |
116 | template <> inline constexpr bool IsNumber<Int128> = true; |
117 | template <> struct TypeName<Int128> { static const char * get() { return "Int128" ; } }; |
118 | template <> 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). |
122 | template <typename T> |
123 | struct 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 | |
157 | using Decimal32 = Decimal<Int32>; |
158 | using Decimal64 = Decimal<Int64>; |
159 | using Decimal128 = Decimal<Int128>; |
160 | |
161 | // TODO (nemkov): consider making a strong typedef |
162 | //using DateTime32 = time_t; |
163 | using DateTime64 = Decimal64; |
164 | |
165 | template <> struct TypeName<Decimal32> { static const char * get() { return "Decimal32" ; } }; |
166 | template <> struct TypeName<Decimal64> { static const char * get() { return "Decimal64" ; } }; |
167 | template <> struct TypeName<Decimal128> { static const char * get() { return "Decimal128" ; } }; |
168 | |
169 | template <> struct TypeId<Decimal32> { static constexpr const TypeIndex value = TypeIndex::Decimal32; }; |
170 | template <> struct TypeId<Decimal64> { static constexpr const TypeIndex value = TypeIndex::Decimal64; }; |
171 | template <> struct TypeId<Decimal128> { static constexpr const TypeIndex value = TypeIndex::Decimal128; }; |
172 | |
173 | template <typename T> constexpr bool IsDecimalNumber = false; |
174 | template <> inline constexpr bool IsDecimalNumber<Decimal32> = true; |
175 | template <> inline constexpr bool IsDecimalNumber<Decimal64> = true; |
176 | template <> inline constexpr bool IsDecimalNumber<Decimal128> = true; |
177 | |
178 | template <typename T> struct NativeType { using Type = T; }; |
179 | template <> struct NativeType<Decimal32> { using Type = Int32; }; |
180 | template <> struct NativeType<Decimal64> { using Type = Int64; }; |
181 | template <> struct NativeType<Decimal128> { using Type = Int128; }; |
182 | |
183 | template <> inline Int32 Decimal32::getScaleMultiplier(UInt32 scale) { return common::exp10_i32(scale); } |
184 | template <> inline Int64 Decimal64::getScaleMultiplier(UInt32 scale) { return common::exp10_i64(scale); } |
185 | template <> inline Int128 Decimal128::getScaleMultiplier(UInt32 scale) { return common::exp10_i128(scale); } |
186 | |
187 | inline 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. |
231 | namespace 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 | |