1 | #include <DataTypes/DataTypesDecimal.h> |
2 | |
3 | #include <Common/assert_cast.h> |
4 | #include <Common/typeid_cast.h> |
5 | #include <Core/DecimalFunctions.h> |
6 | #include <DataTypes/DataTypeFactory.h> |
7 | #include <Formats/ProtobufReader.h> |
8 | #include <Formats/ProtobufWriter.h> |
9 | #include <IO/ReadHelpers.h> |
10 | #include <IO/WriteHelpers.h> |
11 | #include <IO/readDecimalText.h> |
12 | #include <Interpreters/Context.h> |
13 | #include <Parsers/ASTLiteral.h> |
14 | #include <Parsers/IAST.h> |
15 | |
16 | #include <type_traits> |
17 | #include "DataTypesDecimal.h" |
18 | |
19 | |
20 | namespace DB |
21 | { |
22 | |
23 | namespace ErrorCodes |
24 | { |
25 | extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; |
26 | extern const int ILLEGAL_TYPE_OF_ARGUMENT; |
27 | extern const int ARGUMENT_OUT_OF_BOUND; |
28 | } |
29 | |
30 | // |
31 | |
32 | template <typename T> |
33 | std::string DataTypeDecimal<T>::doGetName() const |
34 | { |
35 | std::stringstream ss; |
36 | ss << type_name << "(" ; |
37 | |
38 | if (!only_scale) |
39 | ss << this->precision << ", " ; |
40 | |
41 | ss << this->scale << ")" ; |
42 | return ss.str(); |
43 | } |
44 | |
45 | |
46 | |
47 | template <typename T> |
48 | bool DataTypeDecimal<T>::equals(const IDataType & rhs) const |
49 | { |
50 | if (auto * ptype = typeid_cast<const DataTypeDecimal<T> *>(&rhs)) |
51 | return this->scale == ptype->getScale(); |
52 | return false; |
53 | } |
54 | |
55 | template <typename T> |
56 | DataTypePtr DataTypeDecimal<T>::promoteNumericType() const |
57 | { |
58 | using PromotedType = DataTypeDecimal<Decimal128>; |
59 | return std::make_shared<PromotedType>(PromotedType::maxPrecision(), this->scale); |
60 | } |
61 | |
62 | template <typename T> |
63 | void DataTypeDecimal<T>::serializeText(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings &) const |
64 | { |
65 | T value = assert_cast<const ColumnType &>(column).getData()[row_num]; |
66 | writeText(value, this->scale, ostr); |
67 | } |
68 | |
69 | template <typename T> |
70 | bool DataTypeDecimal<T>::tryReadText(T & x, ReadBuffer & istr, UInt32 precision, UInt32 scale) |
71 | { |
72 | UInt32 unread_scale = scale; |
73 | bool done = tryReadDecimalText(istr, x, precision, unread_scale); |
74 | |
75 | x *= T::getScaleMultiplier(unread_scale); |
76 | return done; |
77 | } |
78 | |
79 | template <typename T> |
80 | void DataTypeDecimal<T>::readText(T & x, ReadBuffer & istr, UInt32 precision, UInt32 scale, bool csv) |
81 | { |
82 | UInt32 unread_scale = scale; |
83 | if (csv) |
84 | readCSVDecimalText(istr, x, precision, unread_scale); |
85 | else |
86 | readDecimalText(istr, x, precision, unread_scale); |
87 | x *= T::getScaleMultiplier(unread_scale); |
88 | } |
89 | |
90 | template <typename T> |
91 | void DataTypeDecimal<T>::deserializeText(IColumn & column, ReadBuffer & istr, const FormatSettings &) const |
92 | { |
93 | T x; |
94 | readText(x, istr); |
95 | assert_cast<ColumnType &>(column).getData().push_back(x); |
96 | } |
97 | |
98 | template <typename T> |
99 | void DataTypeDecimal<T>::deserializeTextCSV(IColumn & column, ReadBuffer & istr, const FormatSettings &) const |
100 | { |
101 | T x; |
102 | readText(x, istr, true); |
103 | assert_cast<ColumnType &>(column).getData().push_back(x); |
104 | } |
105 | |
106 | template <typename T> |
107 | T DataTypeDecimal<T>::parseFromString(const String & str) const |
108 | { |
109 | ReadBufferFromMemory buf(str.data(), str.size()); |
110 | T x; |
111 | UInt32 unread_scale = this->scale; |
112 | readDecimalText(buf, x, this->precision, unread_scale, true); |
113 | x *= T::getScaleMultiplier(unread_scale); |
114 | |
115 | return x; |
116 | } |
117 | |
118 | template <typename T> |
119 | void DataTypeDecimal<T>::serializeProtobuf(const IColumn & column, size_t row_num, ProtobufWriter & protobuf, size_t & value_index) const |
120 | { |
121 | if (value_index) |
122 | return; |
123 | value_index = static_cast<bool>(protobuf.writeDecimal(assert_cast<const ColumnType &>(column).getData()[row_num], this->scale)); |
124 | } |
125 | |
126 | |
127 | template <typename T> |
128 | void DataTypeDecimal<T>::deserializeProtobuf(IColumn & column, ProtobufReader & protobuf, bool allow_add_row, bool & row_added) const |
129 | { |
130 | row_added = false; |
131 | T decimal; |
132 | if (!protobuf.readDecimal(decimal, this->precision, this->scale)) |
133 | return; |
134 | |
135 | auto & container = assert_cast<ColumnType &>(column).getData(); |
136 | if (allow_add_row) |
137 | { |
138 | container.emplace_back(decimal); |
139 | row_added = true; |
140 | } |
141 | else |
142 | container.back() = decimal; |
143 | } |
144 | |
145 | template<typename T> |
146 | DataTypeDecimal<T>::DataTypeDecimal(UInt32 precision_, UInt32 scale_, const String & type_name_, bool only_scale_) |
147 | : Base(precision_, scale_), type_name(type_name_), only_scale(only_scale_) |
148 | { |
149 | } |
150 | |
151 | |
152 | static DataTypePtr create(const String & type_name, const ASTPtr & arguments) |
153 | { |
154 | if (!arguments || arguments->children.size() != 2) |
155 | throw Exception("Decimal data type family must have exactly two arguments: precision and scale" , |
156 | ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); |
157 | |
158 | const auto * precision = arguments->children[0]->as<ASTLiteral>(); |
159 | const auto * scale = arguments->children[1]->as<ASTLiteral>(); |
160 | |
161 | if (!precision || precision->value.getType() != Field::Types::UInt64 || |
162 | !scale || !(scale->value.getType() == Field::Types::Int64 || scale->value.getType() == Field::Types::UInt64)) |
163 | throw Exception("Decimal data type family must have two numbers as its arguments" , ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); |
164 | |
165 | UInt64 precision_value = precision->value.get<UInt64>(); |
166 | UInt64 scale_value = scale->value.get<UInt64>(); |
167 | |
168 | return createDecimal<DataTypeDecimal>(precision_value, scale_value, type_name); |
169 | } |
170 | |
171 | template <typename T> |
172 | static DataTypePtr createExact(const String & type_name, const ASTPtr & arguments) |
173 | { |
174 | if (!arguments || arguments->children.size() != 1) |
175 | throw Exception("Decimal data type family must have exactly two arguments: precision and scale" , |
176 | ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); |
177 | |
178 | const auto * scale_arg = arguments->children[0]->as<ASTLiteral>(); |
179 | |
180 | if (!scale_arg || !(scale_arg->value.getType() == Field::Types::Int64 || scale_arg->value.getType() == Field::Types::UInt64)) |
181 | throw Exception("Decimal data type family must have a two numbers as its arguments" , ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); |
182 | |
183 | UInt64 precision = DecimalUtils::maxPrecision<T>(); |
184 | UInt64 scale = scale_arg->value.get<UInt64>(); |
185 | |
186 | return createDecimal<DataTypeDecimal>(precision, scale, type_name, true); |
187 | } |
188 | |
189 | void registerDataTypeDecimal(DataTypeFactory & factory) |
190 | { |
191 | factory.registerDataType("Decimal32" , createExact<Decimal32>, DataTypeFactory::CaseInsensitive); |
192 | factory.registerDataType("Decimal64" , createExact<Decimal64>, DataTypeFactory::CaseInsensitive); |
193 | factory.registerDataType("Decimal128" , createExact<Decimal128>, DataTypeFactory::CaseInsensitive); |
194 | |
195 | factory.registerDataType("Decimal" , create, DataTypeFactory::CaseInsensitive); |
196 | factory.registerAlias("DEC" , "Decimal" , DataTypeFactory::CaseInsensitive); |
197 | } |
198 | |
199 | /// Explicit template instantiations. |
200 | template class DataTypeDecimal<Decimal32>; |
201 | template class DataTypeDecimal<Decimal64>; |
202 | template class DataTypeDecimal<Decimal128>; |
203 | |
204 | } |
205 | |