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
20namespace DB
21{
22
23namespace 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
32template <typename T>
33std::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
47template <typename T>
48bool 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
55template <typename T>
56DataTypePtr DataTypeDecimal<T>::promoteNumericType() const
57{
58 using PromotedType = DataTypeDecimal<Decimal128>;
59 return std::make_shared<PromotedType>(PromotedType::maxPrecision(), this->scale);
60}
61
62template <typename T>
63void 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
69template <typename T>
70bool 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
79template <typename T>
80void 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
90template <typename T>
91void 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
98template <typename T>
99void 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
106template <typename T>
107T 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
118template <typename T>
119void 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
127template <typename T>
128void 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
145template<typename T>
146DataTypeDecimal<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
152static 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
171template <typename T>
172static 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
189void 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.
200template class DataTypeDecimal<Decimal32>;
201template class DataTypeDecimal<Decimal64>;
202template class DataTypeDecimal<Decimal128>;
203
204}
205