forked from ClickHouse/ClickHouse
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDataTypeDecimalBase.h
More file actions
197 lines (163 loc) · 7.14 KB
/
DataTypeDecimalBase.h
File metadata and controls
197 lines (163 loc) · 7.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#pragma once
#include <cmath>
#include <type_traits>
#include <Columns/ColumnDecimal.h>
#include <Core/TypeId.h>
#include <DataTypes/DataTypesNumber.h>
#include <DataTypes/IDataType.h>
#include <Interpreters/Context_fwd.h>
#include <Common/SipHash.h>
namespace DB
{
namespace ErrorCodes
{
extern const int ARGUMENT_OUT_OF_BOUND;
}
bool decimalCheckComparisonOverflow(ContextPtr context);
bool decimalCheckArithmeticOverflow(ContextPtr context);
inline UInt32 leastDecimalPrecisionFor(TypeIndex int_type)
{
switch (int_type)
{
case TypeIndex::Int8: [[fallthrough]];
case TypeIndex::UInt8:
return 3;
case TypeIndex::Int16: [[fallthrough]];
case TypeIndex::UInt16:
return 5;
case TypeIndex::Int32: [[fallthrough]];
case TypeIndex::UInt32:
return 10;
case TypeIndex::Int64:
return 19;
case TypeIndex::UInt64:
return 20;
default:
break;
}
return 0;
}
/// Base class for decimals, like Decimal(P, S), where P is precision, S is scale.
/// Maximum precisions for underlying types are:
/// Int32 9
/// Int64 18
/// Int128 38
/// Int256 76
/// Operation between two decimals leads to Decimal(P, S), where
/// P is one of (9, 18, 38, 76); equals to the maximum precision for the biggest underlying type of operands.
/// S is maximum scale of operands. The allowed valuas are [0, precision]
template <is_decimal T>
class DataTypeDecimalBase : public IDataType
{
public:
using FieldType = T;
using ColumnType = ColumnDecimal<T>;
static constexpr auto type_id = TypeToTypeIndex<T>;
static constexpr bool is_parametric = true;
static constexpr size_t maxPrecision();
DataTypeDecimalBase(UInt32 precision_, UInt32 scale_)
: precision(precision_),
scale(scale_)
{
if (unlikely(precision < 1 || precision > maxPrecision()))
throw Exception(ErrorCodes::ARGUMENT_OUT_OF_BOUND,
"Precision {} is out of bounds (precision range: [1, {}])",
std::to_string(precision), maxPrecision());
if (unlikely(scale > maxPrecision()))
throw Exception(ErrorCodes::ARGUMENT_OUT_OF_BOUND, "Scale {} is out of bounds (max scale: {})",
std::to_string(scale), maxPrecision());
}
TypeIndex getTypeId() const override { return TypeToTypeIndex<T>; }
Field getDefault() const override;
MutableColumnPtr createColumn() const override;
bool isParametric() const override { return true; }
bool haveSubtypes() const override { return false; }
bool shouldAlignRightInPrettyFormats() const override { return true; }
bool textCanContainOnlyValidUTF8() const override { return true; }
bool isComparable() const override { return true; }
bool isValueRepresentedByNumber() const override { return true; }
bool isValueUnambiguouslyRepresentedInContiguousMemoryRegion() const override { return true; }
bool haveMaximumSizeOfValue() const override { return true; }
size_t getSizeOfValueInMemory() const override { return sizeof(T); }
bool isSummable() const override { return true; }
bool canBeUsedInBooleanContext() const override { return true; }
bool canBeInsideNullable() const override { return true; }
/// Decimal specific
UInt32 getPrecision() const { return precision; }
UInt32 getScale() const { return scale; }
T getScaleMultiplier() const { return getScaleMultiplier(scale); }
T wholePart(T x) const;
T fractionalPart(T x) const;
T maxWholeValue() const { return getScaleMultiplier(precision - scale) - T(1); }
template <typename U>
bool canStoreWhole(U x) const
{
static_assert(is_signed_v<typename T::NativeType>);
T max = maxWholeValue();
if constexpr (is_signed_v<U>)
return -max.value <= x && x <= max.value;
else
return x <= static_cast<make_unsigned_t<typename T::NativeType>>(max.value);
}
/// @returns multiplier for U to become T with correct scale
template <typename U>
T scaleFactorFor(const DataTypeDecimalBase<U> & x, bool) const
{
if (getScale() < x.getScale())
throw Exception(ErrorCodes::ARGUMENT_OUT_OF_BOUND, "Decimal result's scale is less than argument's one");
UInt32 scale_delta = getScale() - x.getScale(); /// scale_delta >= 0
return getScaleMultiplier(scale_delta);
}
template <typename U>
T scaleFactorFor(const DataTypeNumber<U> & , bool is_multiply_or_divisor) const
{
if (is_multiply_or_divisor)
return T(1);
return getScaleMultiplier();
}
static T getScaleMultiplier(UInt32 scale);
void updateHashImpl(SipHash & hash) const override
{
hash.update(precision);
hash.update(scale);
}
protected:
const UInt32 precision;
const UInt32 scale;
};
template <typename T>
inline const DataTypeDecimalBase<T> * checkDecimalBase(const IDataType & data_type)
{
if (isColumnedAsDecimalT<T>(data_type))
return static_cast<const DataTypeDecimalBase<T> *>(&data_type);
return nullptr;
}
template <> constexpr size_t DataTypeDecimalBase<Decimal32>::maxPrecision() { return 9; };
template <> constexpr size_t DataTypeDecimalBase<Decimal64>::maxPrecision() { return 18; };
template <> constexpr size_t DataTypeDecimalBase<DateTime64>::maxPrecision() { return 18; };
template <> constexpr size_t DataTypeDecimalBase<Time64>::maxPrecision() { return 18; };
template <> constexpr size_t DataTypeDecimalBase<Decimal128>::maxPrecision() { return 38; };
template <> constexpr size_t DataTypeDecimalBase<Decimal256>::maxPrecision() { return 76; };
extern template class DataTypeDecimalBase<Decimal32>;
extern template class DataTypeDecimalBase<Decimal64>;
extern template class DataTypeDecimalBase<DateTime64>;
extern template class DataTypeDecimalBase<Time64>;
extern template class DataTypeDecimalBase<Decimal128>;
extern template class DataTypeDecimalBase<Decimal256>;
template <template <typename> typename DecimalType>
inline DataTypePtr createDecimal(UInt64 precision_value, UInt64 scale_value)
{
if (precision_value < 1 || precision_value > DataTypeDecimalBase<Decimal256>::maxPrecision())
throw Exception(ErrorCodes::ARGUMENT_OUT_OF_BOUND, "Wrong precision: it must be between {} and {}, got {}",
1, DataTypeDecimalBase<Decimal256>::maxPrecision(), precision_value);
if (scale_value > precision_value)
throw Exception(ErrorCodes::ARGUMENT_OUT_OF_BOUND, "Negative scales and scales larger than precision are not supported");
if (precision_value <= DataTypeDecimalBase<Decimal32>::maxPrecision())
return std::make_shared<DecimalType<Decimal32>>(precision_value, scale_value);
if (precision_value <= DataTypeDecimalBase<Decimal64>::maxPrecision())
return std::make_shared<DecimalType<Decimal64>>(precision_value, scale_value);
if (precision_value <= DataTypeDecimalBase<Decimal128>::maxPrecision())
return std::make_shared<DecimalType<Decimal128>>(precision_value, scale_value);
return std::make_shared<DecimalType<Decimal256>>(precision_value, scale_value);
}
}