#pragma once #include #include #include #include #include namespace DB { /// Data types for representing elementary values from a database in RAM. struct Null {}; /// @warning Append only enum! Ids in this enum could be serialized in data. /// You MUST NOT change the order, insert or remove ids in the middle. enum class TypeIndex { Nothing = 0, UInt8 = 1, UInt16 = 2, UInt32 = 3, UInt64 = 4, UInt128 = 5, Int8 = 6, Int16 = 7, Int32 = 8, Int64 = 9, Int128 = 10, Float32 = 11, Float64 = 12, Date = 13, DateTime = 14, String = 15, FixedString = 16, Enum8 = 17, Enum16 = 18, Decimal32 = 19, Decimal64 = 20, Decimal128 = 21, UUID = 22, Array = 23, Tuple = 24, Set = 25, Interval = 26, Nullable = 27, Function = 28, AggregateFunction = 29, LowCardinality = 30, DateTime64 = 31, }; using UInt8 = uint8_t; using UInt16 = uint16_t; using UInt32 = uint32_t; using UInt64 = uint64_t; using Int8 = int8_t; using Int16 = int16_t; using Int32 = int32_t; using Int64 = int64_t; using Float32 = float; using Float64 = double; using String = std::string; /** Note that for types not used in DB, IsNumber is false. */ template constexpr bool IsNumber = false; template <> inline constexpr bool IsNumber = true; template <> inline constexpr bool IsNumber = true; template <> inline constexpr bool IsNumber = true; template <> inline constexpr bool IsNumber = true; template <> inline constexpr bool IsNumber = true; template <> inline constexpr bool IsNumber = true; template <> inline constexpr bool IsNumber = true; template <> inline constexpr bool IsNumber = true; template <> inline constexpr bool IsNumber = true; template <> inline constexpr bool IsNumber = true; template struct TypeName; template <> struct TypeName { static const char * get() { return "UInt8"; } }; template <> struct TypeName { static const char * get() { return "UInt16"; } }; template <> struct TypeName { static const char * get() { return "UInt32"; } }; template <> struct TypeName { static const char * get() { return "UInt64"; } }; template <> struct TypeName { static const char * get() { return "Int8"; } }; template <> struct TypeName { static const char * get() { return "Int16"; } }; template <> struct TypeName { static const char * get() { return "Int32"; } }; template <> struct TypeName { static const char * get() { return "Int64"; } }; template <> struct TypeName { static const char * get() { return "Float32"; } }; template <> struct TypeName { static const char * get() { return "Float64"; } }; template <> struct TypeName { static const char * get() { return "String"; } }; template struct TypeId; template <> struct TypeId { static constexpr const TypeIndex value = TypeIndex::UInt8; }; template <> struct TypeId { static constexpr const TypeIndex value = TypeIndex::UInt16; }; template <> struct TypeId { static constexpr const TypeIndex value = TypeIndex::UInt32; }; template <> struct TypeId { static constexpr const TypeIndex value = TypeIndex::UInt64; }; template <> struct TypeId { static constexpr const TypeIndex value = TypeIndex::Int8; }; template <> struct TypeId { static constexpr const TypeIndex value = TypeIndex::Int16; }; template <> struct TypeId { static constexpr const TypeIndex value = TypeIndex::Int32; }; template <> struct TypeId { static constexpr const TypeIndex value = TypeIndex::Int64; }; template <> struct TypeId { static constexpr const TypeIndex value = TypeIndex::Float32; }; template <> struct TypeId { static constexpr const TypeIndex value = TypeIndex::Float64; }; /// Not a data type in database, defined just for convenience. using Strings = std::vector; using Int128 = __int128; template <> inline constexpr bool IsNumber = true; template <> struct TypeName { static const char * get() { return "Int128"; } }; template <> struct TypeId { static constexpr const TypeIndex value = TypeIndex::Int128; }; /// Own FieldType for Decimal. /// It is only a "storage" for decimal. To perform operations, you also have to provide a scale (number of digits after point). template struct Decimal { using NativeType = T; Decimal() = default; Decimal(Decimal &&) = default; Decimal(const Decimal &) = default; Decimal(const T & value_) : value(value_) {} template Decimal(const Decimal & x) : value(x) {} constexpr Decimal & operator = (Decimal &&) = default; constexpr Decimal & operator = (const Decimal &) = default; operator T () const { return value; } const Decimal & operator += (const T & x) { value += x; return *this; } const Decimal & operator -= (const T & x) { value -= x; return *this; } const Decimal & operator *= (const T & x) { value *= x; return *this; } const Decimal & operator /= (const T & x) { value /= x; return *this; } const Decimal & operator %= (const T & x) { value %= x; return *this; } static T getScaleMultiplier(UInt32 scale); T value; }; using Decimal32 = Decimal; using Decimal64 = Decimal; using Decimal128 = Decimal; using DateTime64 = Decimal64; template <> struct TypeName { static const char * get() { return "Decimal32"; } }; template <> struct TypeName { static const char * get() { return "Decimal64"; } }; template <> struct TypeName { static const char * get() { return "Decimal128"; } }; template <> struct TypeId { static constexpr const TypeIndex value = TypeIndex::Decimal32; }; template <> struct TypeId { static constexpr const TypeIndex value = TypeIndex::Decimal64; }; template <> struct TypeId { static constexpr const TypeIndex value = TypeIndex::Decimal128; }; template constexpr bool IsDecimalNumber = false; template <> inline constexpr bool IsDecimalNumber = true; template <> inline constexpr bool IsDecimalNumber = true; template <> inline constexpr bool IsDecimalNumber = true; template struct NativeType { using Type = T; }; template <> struct NativeType { using Type = Int32; }; template <> struct NativeType { using Type = Int64; }; template <> struct NativeType { using Type = Int128; }; template <> inline Int32 Decimal32::getScaleMultiplier(UInt32 scale) { return common::exp10_i32(scale); } template <> inline Int64 Decimal64::getScaleMultiplier(UInt32 scale) { return common::exp10_i64(scale); } template <> inline Int128 Decimal128::getScaleMultiplier(UInt32 scale) { return common::exp10_i128(scale); } inline const char * getTypeName(TypeIndex idx) { switch (idx) { case TypeIndex::Nothing: return "Nothing"; case TypeIndex::UInt8: return TypeName::get(); case TypeIndex::UInt16: return TypeName::get(); case TypeIndex::UInt32: return TypeName::get(); case TypeIndex::UInt64: return TypeName::get(); case TypeIndex::UInt128: return "UInt128"; case TypeIndex::Int8: return TypeName::get(); case TypeIndex::Int16: return TypeName::get(); case TypeIndex::Int32: return TypeName::get(); case TypeIndex::Int64: return TypeName::get(); case TypeIndex::Int128: return TypeName::get(); case TypeIndex::Float32: return TypeName::get(); case TypeIndex::Float64: return TypeName::get(); case TypeIndex::Date: return "Date"; case TypeIndex::DateTime: return "DateTime"; case TypeIndex::DateTime64: return "DateTime64"; case TypeIndex::String: return TypeName::get(); case TypeIndex::FixedString: return "FixedString"; case TypeIndex::Enum8: return "Enum8"; case TypeIndex::Enum16: return "Enum16"; case TypeIndex::Decimal32: return TypeName::get(); case TypeIndex::Decimal64: return TypeName::get(); case TypeIndex::Decimal128: return TypeName::get(); case TypeIndex::UUID: return "UUID"; case TypeIndex::Array: return "Array"; case TypeIndex::Tuple: return "Tuple"; case TypeIndex::Set: return "Set"; case TypeIndex::Interval: return "Interval"; case TypeIndex::Nullable: return "Nullable"; case TypeIndex::Function: return "Function"; case TypeIndex::AggregateFunction: return "AggregateFunction"; case TypeIndex::LowCardinality: return "LowCardinality"; } __builtin_unreachable(); } } /// Specialization of `std::hash` for the Decimal types. namespace std { template struct hash> { size_t operator()(const DB::Decimal & x) const { return hash()(x.value); } }; template <> struct hash { size_t operator()(const DB::Decimal128 & x) const { return std::hash()(x.value >> 64) ^ std::hash()(x.value & std::numeric_limits::max()); } }; }