1 | #pragma once |
2 | #include <cmath> |
3 | |
4 | #include <common/likely.h> |
5 | #include <Columns/ColumnDecimal.h> |
6 | #include <Core/DecimalFunctions.h> |
7 | #include <DataTypes/IDataType.h> |
8 | #include <DataTypes/DataTypesNumber.h> |
9 | #include <DataTypes/DataTypeWithSimpleSerialization.h> |
10 | |
11 | #include <type_traits> |
12 | |
13 | |
14 | namespace DB |
15 | { |
16 | |
17 | namespace ErrorCodes |
18 | { |
19 | extern const int ARGUMENT_OUT_OF_BOUND; |
20 | extern const int CANNOT_CONVERT_TYPE; |
21 | extern const int DECIMAL_OVERFLOW; |
22 | } |
23 | |
24 | class Context; |
25 | bool decimalCheckComparisonOverflow(const Context & context); |
26 | bool decimalCheckArithmeticOverflow(const Context & context); |
27 | |
28 | inline UInt32 leastDecimalPrecisionFor(TypeIndex int_type) |
29 | { |
30 | switch (int_type) |
31 | { |
32 | case TypeIndex::Int8: [[fallthrough]]; |
33 | case TypeIndex::UInt8: |
34 | return 3; |
35 | case TypeIndex::Int16: [[fallthrough]]; |
36 | case TypeIndex::UInt16: |
37 | return 5; |
38 | case TypeIndex::Int32: [[fallthrough]]; |
39 | case TypeIndex::UInt32: |
40 | return 10; |
41 | case TypeIndex::Int64: |
42 | return 19; |
43 | case TypeIndex::UInt64: |
44 | return 20; |
45 | default: |
46 | break; |
47 | } |
48 | return 0; |
49 | } |
50 | |
51 | /// Base class for decimals, like Decimal(P, S), where P is precision, S is scale. |
52 | /// Maximum precisions for underlying types are: |
53 | /// Int32 9 |
54 | /// Int64 18 |
55 | /// Int128 38 |
56 | /// Operation between two decimals leads to Decimal(P, S), where |
57 | /// P is one of (9, 18, 38); equals to the maximum precision for the biggest underlying type of operands. |
58 | /// S is maximum scale of operands. The allowed valuas are [0, precision] |
59 | template <typename T> |
60 | class DataTypeDecimalBase : public DataTypeWithSimpleSerialization |
61 | { |
62 | static_assert(IsDecimalNumber<T>); |
63 | |
64 | public: |
65 | using FieldType = T; |
66 | using ColumnType = ColumnDecimal<T>; |
67 | |
68 | static constexpr bool is_parametric = true; |
69 | |
70 | static constexpr size_t maxPrecision() { return DecimalUtils::maxPrecision<T>(); } |
71 | |
72 | DataTypeDecimalBase(UInt32 precision_, UInt32 scale_) |
73 | : precision(precision_), |
74 | scale(scale_) |
75 | { |
76 | if (unlikely(precision < 1 || precision > maxPrecision())) |
77 | throw Exception("Precision " + std::to_string(precision) + " is out of bounds" , ErrorCodes::ARGUMENT_OUT_OF_BOUND); |
78 | if (unlikely(scale < 0 || static_cast<UInt32>(scale) > maxPrecision())) |
79 | throw Exception("Scale " + std::to_string(scale) + " is out of bounds" , ErrorCodes::ARGUMENT_OUT_OF_BOUND); |
80 | } |
81 | |
82 | TypeIndex getTypeId() const override { return TypeId<T>::value; } |
83 | |
84 | Field getDefault() const override; |
85 | MutableColumnPtr createColumn() const override; |
86 | |
87 | bool isParametric() const override { return true; } |
88 | bool haveSubtypes() const override { return false; } |
89 | bool shouldAlignRightInPrettyFormats() const override { return true; } |
90 | bool textCanContainOnlyValidUTF8() const override { return true; } |
91 | bool isComparable() const override { return true; } |
92 | bool isValueRepresentedByNumber() const override { return true; } |
93 | bool isValueUnambiguouslyRepresentedInContiguousMemoryRegion() const override { return true; } |
94 | bool haveMaximumSizeOfValue() const override { return true; } |
95 | size_t getSizeOfValueInMemory() const override { return sizeof(T); } |
96 | |
97 | bool isSummable() const override { return true; } |
98 | bool canBeUsedInBooleanContext() const override { return true; } |
99 | bool canBeInsideNullable() const override { return true; } |
100 | |
101 | void serializeBinary(const Field & field, WriteBuffer & ostr) const override; |
102 | void serializeBinary(const IColumn & column, size_t row_num, WriteBuffer & ostr) const override; |
103 | void serializeBinaryBulk(const IColumn & column, WriteBuffer & ostr, size_t offset, size_t limit) const override; |
104 | |
105 | void deserializeBinary(Field & field, ReadBuffer & istr) const override; |
106 | void deserializeBinary(IColumn & column, ReadBuffer & istr) const override; |
107 | void deserializeBinaryBulk(IColumn & column, ReadBuffer & istr, size_t limit, double avg_value_size_hint) const override; |
108 | |
109 | /// Decimal specific |
110 | |
111 | UInt32 getPrecision() const { return precision; } |
112 | UInt32 getScale() const { return scale; } |
113 | T getScaleMultiplier() const { return getScaleMultiplier(scale); } |
114 | |
115 | T wholePart(T x) const |
116 | { |
117 | return DecimalUtils::getWholePart(x, scale); |
118 | } |
119 | |
120 | T fractionalPart(T x) const |
121 | { |
122 | return DecimalUtils::getFractionalPart(x, scale); |
123 | } |
124 | |
125 | T maxWholeValue() const { return getScaleMultiplier(maxPrecision() - scale) - T(1); } |
126 | |
127 | bool canStoreWhole(T x) const |
128 | { |
129 | T max = maxWholeValue(); |
130 | if (x > max || x < -max) |
131 | return false; |
132 | return true; |
133 | } |
134 | |
135 | /// @returns multiplier for U to become T with correct scale |
136 | template <typename U> |
137 | T scaleFactorFor(const DataTypeDecimalBase<U> & x, bool) const |
138 | { |
139 | if (getScale() < x.getScale()) |
140 | throw Exception("Decimal result's scale is less than argument's one" , ErrorCodes::ARGUMENT_OUT_OF_BOUND); |
141 | UInt32 scale_delta = getScale() - x.getScale(); /// scale_delta >= 0 |
142 | return getScaleMultiplier(scale_delta); |
143 | } |
144 | |
145 | template <typename U> |
146 | T scaleFactorFor(const DataTypeNumber<U> & , bool is_multiply_or_divisor) const |
147 | { |
148 | if (is_multiply_or_divisor) |
149 | return 1; |
150 | return getScaleMultiplier(); |
151 | } |
152 | |
153 | static T getScaleMultiplier(UInt32 scale); |
154 | |
155 | protected: |
156 | const UInt32 precision; |
157 | const UInt32 scale; |
158 | }; |
159 | |
160 | |
161 | template <typename T, typename U, template <typename> typename DecimalType> |
162 | typename std::enable_if_t<(sizeof(T) >= sizeof(U)), DecimalType<T>> |
163 | decimalResultType(const DecimalType<T> & tx, const DecimalType<U> & ty, bool is_multiply, bool is_divide) |
164 | { |
165 | UInt32 scale = (tx.getScale() > ty.getScale() ? tx.getScale() : ty.getScale()); |
166 | if (is_multiply) |
167 | scale = tx.getScale() + ty.getScale(); |
168 | else if (is_divide) |
169 | scale = tx.getScale(); |
170 | return DecimalType<T>(DecimalUtils::maxPrecision<T>(), scale); |
171 | } |
172 | |
173 | template <typename T, typename U, template <typename> typename DecimalType> |
174 | typename std::enable_if_t<(sizeof(T) < sizeof(U)), const DecimalType<U>> |
175 | decimalResultType(const DecimalType<T> & tx, const DecimalType<U> & ty, bool is_multiply, bool is_divide) |
176 | { |
177 | UInt32 scale = (tx.getScale() > ty.getScale() ? tx.getScale() : ty.getScale()); |
178 | if (is_multiply) |
179 | scale = tx.getScale() * ty.getScale(); |
180 | else if (is_divide) |
181 | scale = tx.getScale(); |
182 | return DecimalType<U>(DecimalUtils::maxPrecision<U>(), scale); |
183 | } |
184 | |
185 | template <typename T, typename U, template <typename> typename DecimalType> |
186 | const DecimalType<T> decimalResultType(const DecimalType<T> & tx, const DataTypeNumber<U> &, bool, bool) |
187 | { |
188 | return DecimalType<T>(DecimalUtils::maxPrecision<T>(), tx.getScale()); |
189 | } |
190 | |
191 | template <typename T, typename U, template <typename> typename DecimalType> |
192 | const DecimalType<U> decimalResultType(const DataTypeNumber<T> &, const DecimalType<U> & ty, bool, bool) |
193 | { |
194 | return DecimalType<U>(DecimalUtils::maxPrecision<U>(), ty.getScale()); |
195 | } |
196 | |
197 | template <template <typename> typename DecimalType> |
198 | DataTypePtr createDecimal(UInt64 precision_value, UInt64 scale_value, const String & type_name = "Decimal" , bool only_scale = false) |
199 | { |
200 | if (precision_value < DecimalUtils::minPrecision() || precision_value > DecimalUtils::maxPrecision<Decimal128>()) |
201 | throw Exception("Wrong precision" , ErrorCodes::ARGUMENT_OUT_OF_BOUND); |
202 | |
203 | if (static_cast<UInt64>(scale_value) > precision_value) |
204 | throw Exception("Negative scales and scales larger than precision are not supported" , ErrorCodes::ARGUMENT_OUT_OF_BOUND); |
205 | |
206 | if (precision_value <= DecimalUtils::maxPrecision<Decimal32>()) |
207 | return std::make_shared<DecimalType<Decimal32>>(precision_value, scale_value, type_name, only_scale); |
208 | else if (precision_value <= DecimalUtils::maxPrecision<Decimal64>()) |
209 | return std::make_shared<DecimalType<Decimal64>>(precision_value, scale_value, type_name, only_scale); |
210 | return std::make_shared<DecimalType<Decimal128>>(precision_value, scale_value, type_name, only_scale); |
211 | } |
212 | |
213 | } |
214 | |