ClickHouse
224 строки · 7.6 Кб
1#include <Columns/ColumnNullable.h>
2#include <Columns/ColumnString.h>
3#include <Columns/ColumnFixedString.h>
4#include <Columns/ColumnVector.h>
5#include <Columns/ColumnsNumber.h>
6#include <DataTypes/IDataType.h>
7#include <DataTypes/DataTypesNumber.h>
8#include <DataTypes/DataTypeNullable.h>
9#include <Functions/IFunction.h>
10#include <Functions/FunctionFactory.h>
11#include <Functions/GregorianDate.h>
12#include <IO/ReadBufferFromMemory.h>
13
14namespace DB
15{
16namespace ErrorCodes
17{
18extern const int ILLEGAL_COLUMN;
19extern const int ILLEGAL_TYPE_OF_ARGUMENT;
20}
21
22template <typename Name, typename ToDataType, bool nullOnErrors>
23class ExecutableFunctionToModifiedJulianDay : public IExecutableFunction
24{
25public:
26String getName() const override
27{
28return Name::name;
29}
30
31ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
32{
33const IColumn * col_from = arguments[0].column.get();
34const ColumnString * col_from_string = checkAndGetColumn<ColumnString>(col_from);
35const ColumnFixedString * col_from_fixed_string = checkAndGetColumn<ColumnFixedString>(col_from);
36
37const ColumnString::Chars * chars = nullptr;
38const IColumn::Offsets * offsets = nullptr;
39size_t fixed_string_size = 0;
40
41if (col_from_string)
42{
43chars = &col_from_string->getChars();
44offsets = &col_from_string->getOffsets();
45}
46else if (col_from_fixed_string)
47{
48chars = &col_from_fixed_string->getChars();
49fixed_string_size = col_from_fixed_string->getN();
50}
51else
52{
53throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of first argument of function {}",
54col_from->getName(), Name::name);
55}
56
57using ColVecTo = typename ToDataType::ColumnType;
58typename ColVecTo::MutablePtr col_to = ColVecTo::create(input_rows_count);
59typename ColVecTo::Container & vec_to = col_to->getData();
60
61ColumnUInt8::MutablePtr col_null_map_to;
62UInt8 * vec_null_map_to [[maybe_unused]] = nullptr;
63if constexpr (nullOnErrors)
64{
65col_null_map_to = ColumnUInt8::create(input_rows_count);
66vec_null_map_to = col_null_map_to->getData().data();
67}
68
69size_t current_offset = 0;
70for (size_t i = 0; i < input_rows_count; ++i)
71{
72const size_t next_offset = offsets ? (*offsets)[i] : current_offset + fixed_string_size;
73const size_t string_size = offsets ? next_offset - current_offset - 1 : fixed_string_size;
74ReadBufferFromMemory read_buffer(&(*chars)[current_offset], string_size);
75current_offset = next_offset;
76
77if constexpr (nullOnErrors)
78{
79GregorianDate date;
80
81int64_t res = 0;
82bool success = date.tryInit(read_buffer) && date.tryToModifiedJulianDay(res);
83
84vec_to[i] = static_cast<typename ToDataType::FieldType>(res);
85vec_null_map_to[i] = !success;
86}
87else
88{
89const GregorianDate date(read_buffer);
90vec_to[i] = static_cast<typename ToDataType::FieldType>(date.toModifiedJulianDay());
91}
92}
93
94if constexpr (nullOnErrors)
95return ColumnNullable::create(std::move(col_to), std::move(col_null_map_to));
96else
97return col_to;
98}
99
100bool useDefaultImplementationForConstants() const override
101{
102return true;
103}
104};
105
106template <typename Name, typename ToDataType, bool nullOnErrors>
107class FunctionBaseToModifiedJulianDay : public IFunctionBase
108{
109public:
110explicit FunctionBaseToModifiedJulianDay(DataTypes argument_types_, DataTypePtr return_type_)
111: argument_types(std::move(argument_types_))
112, return_type(std::move(return_type_)) {}
113
114String getName() const override
115{
116return Name::name;
117}
118
119const DataTypes & getArgumentTypes() const override
120{
121return argument_types;
122}
123
124const DataTypePtr & getResultType() const override
125{
126return return_type;
127}
128
129bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
130
131ExecutableFunctionPtr prepare(const ColumnsWithTypeAndName &) const override
132{
133return std::make_unique<ExecutableFunctionToModifiedJulianDay<Name, ToDataType, nullOnErrors>>();
134}
135
136bool isInjective(const ColumnsWithTypeAndName &) const override
137{
138return true;
139}
140
141bool hasInformationAboutMonotonicity() const override
142{
143return true;
144}
145
146Monotonicity getMonotonicityForRange(const IDataType &, const Field &, const Field &) const override
147{
148return { .is_monotonic = true, .is_always_monotonic = true, .is_strict = true };
149}
150
151private:
152DataTypes argument_types;
153DataTypePtr return_type;
154};
155
156template <typename Name, typename ToDataType, bool nullOnErrors>
157class ToModifiedJulianDayOverloadResolver : public IFunctionOverloadResolver
158{
159public:
160static constexpr auto name = Name::name;
161
162static FunctionOverloadResolverPtr create(ContextPtr)
163{
164return std::make_unique<ToModifiedJulianDayOverloadResolver<Name, ToDataType, nullOnErrors>>();
165}
166
167String getName() const override
168{
169return Name::name;
170}
171
172FunctionBasePtr buildImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & return_type) const override
173{
174DataTypes argument_types = { arguments[0].type };
175
176return std::make_unique<FunctionBaseToModifiedJulianDay<Name, ToDataType, nullOnErrors>>(argument_types, return_type);
177}
178
179DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
180{
181if (!isStringOrFixedString(arguments[0]))
182{
183throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "The argument of function {} must be String or FixedString",
184getName());
185}
186
187DataTypePtr base_type = std::make_shared<ToDataType>();
188if constexpr (nullOnErrors)
189{
190return std::make_shared<DataTypeNullable>(base_type);
191}
192else
193{
194return base_type;
195}
196}
197
198size_t getNumberOfArguments() const override
199{
200return 1;
201}
202
203bool isInjective(const ColumnsWithTypeAndName &) const override
204{
205return true;
206}
207};
208
209struct NameToModifiedJulianDay
210{
211static constexpr auto name = "toModifiedJulianDay";
212};
213
214struct NameToModifiedJulianDayOrNull
215{
216static constexpr auto name = "toModifiedJulianDayOrNull";
217};
218
219REGISTER_FUNCTION(ToModifiedJulianDay)
220{
221factory.registerFunction<ToModifiedJulianDayOverloadResolver<NameToModifiedJulianDay, DataTypeInt32, false>>();
222factory.registerFunction<ToModifiedJulianDayOverloadResolver<NameToModifiedJulianDayOrNull, DataTypeInt32, true>>();
223}
224}
225