ClickHouse
272 строки · 10.5 Кб
1#include <Functions/FunctionFactory.h>
2#include <Functions/extractTimeZoneFromFunctionArguments.h>
3#include <Functions/IFunction.h>
4#include <Functions/FunctionHelpers.h>
5#include <DataTypes/DataTypeDateTime64.h>
6#include <DataTypes/DataTypesDecimal.h>
7#include <DataTypes/DataTypesNumber.h>
8#include <Columns/ColumnConst.h>
9#include <Columns/ColumnsNumber.h>
10#include <Core/DecimalFunctions.h>
11#include <Interpreters/Context.h>
12
13
14namespace DB
15{
16
17namespace ErrorCodes
18{
19extern const int ILLEGAL_TYPE_OF_ARGUMENT;
20}
21
22namespace
23{
24
25/** According to Twitter's post on Snowflake, we can extract the timestamp for a snowflake ID by right shifting
26* the snowflake ID by 22 bits(10 bits machine ID and 12 bits sequence ID) and adding the Twitter epoch time of 1288834974657.
27* https://en.wikipedia.org/wiki/Snowflake_ID
28* https://blog.twitter.com/engineering/en_us/a/2010/announcing-snowflake
29* https://ws-dl.blogspot.com/2019/08/2019-08-03-tweetedat-finding-tweet.html
30*/
31constexpr size_t snowflake_epoch = 1288834974657L;
32constexpr int time_shift = 22;
33
34class FunctionDateTimeToSnowflake : public IFunction
35{
36private:
37const char * name;
38
39public:
40explicit FunctionDateTimeToSnowflake(const char * name_) : name(name_) { }
41
42String getName() const override { return name; }
43size_t getNumberOfArguments() const override { return 1; }
44bool useDefaultImplementationForConstants() const override { return true; }
45bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; }
46
47DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
48{
49FunctionArgumentDescriptors args{
50{"value", static_cast<FunctionArgumentDescriptor::TypeValidator>(&isDateTime), nullptr, "DateTime"}
51};
52validateFunctionArgumentTypes(*this, arguments, args);
53
54return std::make_shared<DataTypeInt64>();
55}
56
57ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
58{
59const auto & src = arguments[0];
60const auto & src_column = *src.column;
61
62auto res_column = ColumnInt64::create(input_rows_count);
63auto & res_data = res_column->getData();
64
65const auto & src_data = typeid_cast<const ColumnUInt32 &>(src_column).getData();
66for (size_t i = 0; i < input_rows_count; ++i)
67res_data[i] = (Int64(src_data[i]) * 1000 - snowflake_epoch) << time_shift;
68
69return res_column;
70}
71};
72
73class FunctionSnowflakeToDateTime : public IFunction
74{
75private:
76const char * name;
77const bool allow_nonconst_timezone_arguments;
78
79public:
80explicit FunctionSnowflakeToDateTime(const char * name_, ContextPtr context)
81: name(name_)
82, allow_nonconst_timezone_arguments(context->getSettings().allow_nonconst_timezone_arguments)
83{}
84
85String getName() const override { return name; }
86size_t getNumberOfArguments() const override { return 0; }
87bool isVariadic() const override { return true; }
88bool useDefaultImplementationForConstants() const override { return true; }
89bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; }
90
91DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
92{
93FunctionArgumentDescriptors mandatory_args{
94{"value", static_cast<FunctionArgumentDescriptor::TypeValidator>(&isInt64), nullptr, "Int64"}
95};
96FunctionArgumentDescriptors optional_args{
97{"time_zone", static_cast<FunctionArgumentDescriptor::TypeValidator>(&isString), nullptr, "String"}
98};
99validateFunctionArgumentTypes(*this, arguments, mandatory_args, optional_args);
100
101String timezone;
102if (arguments.size() == 2)
103timezone = extractTimeZoneNameFromFunctionArguments(arguments, 1, 0, allow_nonconst_timezone_arguments);
104
105return std::make_shared<DataTypeDateTime>(timezone);
106}
107
108ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
109{
110const auto & src = arguments[0];
111const auto & src_column = *src.column;
112
113auto res_column = ColumnUInt32::create(input_rows_count);
114auto & res_data = res_column->getData();
115
116if (const auto * src_column_non_const = typeid_cast<const ColumnInt64 *>(&src_column))
117{
118const auto & src_data = src_column_non_const->getData();
119for (size_t i = 0; i < input_rows_count; ++i)
120res_data[i] = static_cast<UInt32>(
121((src_data[i] >> time_shift) + snowflake_epoch) / 1000);
122}
123else if (const auto * src_column_const = typeid_cast<const ColumnConst *>(&src_column))
124{
125Int64 src_val = src_column_const->getValue<Int64>();
126for (size_t i = 0; i < input_rows_count; ++i)
127res_data[i] = static_cast<UInt32>(
128((src_val >> time_shift) + snowflake_epoch) / 1000);
129}
130else
131throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal argument for function {}", name);
132
133return res_column;
134}
135};
136
137
138class FunctionDateTime64ToSnowflake : public IFunction
139{
140private:
141const char * name;
142
143public:
144explicit FunctionDateTime64ToSnowflake(const char * name_) : name(name_) { }
145
146String getName() const override { return name; }
147size_t getNumberOfArguments() const override { return 1; }
148bool useDefaultImplementationForConstants() const override { return true; }
149bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; }
150
151DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
152{
153FunctionArgumentDescriptors args{
154{"value", static_cast<FunctionArgumentDescriptor::TypeValidator>(&isDateTime64), nullptr, "DateTime64"}
155};
156validateFunctionArgumentTypes(*this, arguments, args);
157
158return std::make_shared<DataTypeInt64>();
159}
160
161ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
162{
163const auto & src = arguments[0];
164
165const auto & src_column = *src.column;
166auto res_column = ColumnInt64::create(input_rows_count);
167auto & res_data = res_column->getData();
168
169const auto & src_data = typeid_cast<const ColumnDecimal<DateTime64> &>(src_column).getData();
170
171/// timestamps in snowflake-ids are millisecond-based, convert input to milliseconds
172UInt32 src_scale = getDecimalScale(*arguments[0].type);
173Int64 multiplier_msec = DecimalUtils::scaleMultiplier<DateTime64>(3);
174Int64 multiplier_src = DecimalUtils::scaleMultiplier<DateTime64>(src_scale);
175auto factor = multiplier_msec / static_cast<double>(multiplier_src);
176
177for (size_t i = 0; i < input_rows_count; ++i)
178res_data[i] = static_cast<Int64>(src_data[i] * factor - snowflake_epoch) << time_shift;
179
180return res_column;
181}
182};
183
184
185class FunctionSnowflakeToDateTime64 : public IFunction
186{
187private:
188const char * name;
189const bool allow_nonconst_timezone_arguments;
190
191public:
192explicit FunctionSnowflakeToDateTime64(const char * name_, ContextPtr context)
193: name(name_)
194, allow_nonconst_timezone_arguments(context->getSettings().allow_nonconst_timezone_arguments)
195{}
196
197String getName() const override { return name; }
198size_t getNumberOfArguments() const override { return 0; }
199bool isVariadic() const override { return true; }
200bool useDefaultImplementationForConstants() const override { return true; }
201bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; }
202
203DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
204{
205FunctionArgumentDescriptors mandatory_args{
206{"value", static_cast<FunctionArgumentDescriptor::TypeValidator>(&isInt64), nullptr, "Int64"}
207};
208FunctionArgumentDescriptors optional_args{
209{"time_zone", static_cast<FunctionArgumentDescriptor::TypeValidator>(&isString), nullptr, "String"}
210};
211validateFunctionArgumentTypes(*this, arguments, mandatory_args, optional_args);
212
213String timezone;
214if (arguments.size() == 2)
215timezone = extractTimeZoneNameFromFunctionArguments(arguments, 1, 0, allow_nonconst_timezone_arguments);
216
217return std::make_shared<DataTypeDateTime64>(3, timezone);
218}
219
220ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
221{
222const auto & src = arguments[0];
223const auto & src_column = *src.column;
224
225auto res_column = ColumnDecimal<DateTime64>::create(input_rows_count, 3);
226auto & res_data = res_column->getData();
227
228if (const auto * src_column_non_const = typeid_cast<const ColumnInt64 *>(&src_column))
229{
230const auto & src_data = src_column_non_const->getData();
231for (size_t i = 0; i < input_rows_count; ++i)
232res_data[i] = (src_data[i] >> time_shift) + snowflake_epoch;
233}
234else if (const auto * src_column_const = typeid_cast<const ColumnConst *>(&src_column))
235{
236Int64 src_val = src_column_const->getValue<Int64>();
237for (size_t i = 0; i < input_rows_count; ++i)
238res_data[i] = (src_val >> time_shift) + snowflake_epoch;
239}
240else
241throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal argument for function {}", name);
242
243return res_column;
244}
245};
246
247}
248
249REGISTER_FUNCTION(DateTimeToSnowflake)
250{
251factory.registerFunction("dateTimeToSnowflake",
252[](ContextPtr){ return std::make_shared<FunctionDateTimeToSnowflake>("dateTimeToSnowflake"); });
253}
254
255REGISTER_FUNCTION(DateTime64ToSnowflake)
256{
257factory.registerFunction("dateTime64ToSnowflake",
258[](ContextPtr){ return std::make_shared<FunctionDateTime64ToSnowflake>("dateTime64ToSnowflake"); });
259}
260
261REGISTER_FUNCTION(SnowflakeToDateTime)
262{
263factory.registerFunction("snowflakeToDateTime",
264[](ContextPtr context){ return std::make_shared<FunctionSnowflakeToDateTime>("snowflakeToDateTime", context); });
265}
266REGISTER_FUNCTION(SnowflakeToDateTime64)
267{
268factory.registerFunction("snowflakeToDateTime64",
269[](ContextPtr context){ return std::make_shared<FunctionSnowflakeToDateTime64>("snowflakeToDateTime64", context); });
270}
271
272}
273