ClickHouse
141 строка · 6.6 Кб
1#include <Columns/ColumnConst.h>
2#include <Columns/ColumnsDateTime.h>
3#include <Columns/ColumnString.h>
4#include <Columns/ColumnsNumber.h>
5#include <Columns/IColumn.h>
6#include <Common/DateLUT.h>
7#include <Common/LocalDateTime.h>
8#include <Common/logger_useful.h>
9#include <Core/DecimalFunctions.h>
10#include <DataTypes/DataTypeDateTime.h>
11#include <DataTypes/DataTypeDateTime64.h>
12#include <DataTypes/DataTypeNullable.h>
13#include <DataTypes/TimezoneMixin.h>
14#include <Functions/FunctionFactory.h>
15#include <Functions/IFunction.h>
16#include <Functions/FunctionHelpers.h>
17#include <Interpreters/Context.h>
18
19namespace DB
20{
21namespace ErrorCodes
22{
23extern const int ILLEGAL_COLUMN;
24extern const int ILLEGAL_TYPE_OF_ARGUMENT;
25extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
26}
27
28namespace
29{
30template <typename Name>
31class UTCTimestampTransform : public IFunction
32{
33public:
34static FunctionPtr create(ContextPtr) { return std::make_shared<UTCTimestampTransform>(); }
35static constexpr auto name = Name::name;
36
37String getName() const override { return name; }
38
39size_t getNumberOfArguments() const override { return 2; }
40
41bool useDefaultImplementationForConstants() const override { return true; }
42
43bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; }
44
45ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1}; }
46
47DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
48{
49if (arguments.size() != 2)
50throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Function {}'s arguments number must be 2.", name);
51WhichDataType which_type_first(arguments[0]);
52WhichDataType which_type_second(arguments[1]);
53if (!which_type_first.isDateTime() && !which_type_first.isDateTime64())
54throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Function {}'s 1st argument type must be datetime.", name);
55if (dynamic_cast<const TimezoneMixin *>(arguments[0].get())->hasExplicitTimeZone())
56throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Function {}'s 1st argument should not have explicit time zone.", name);
57if (!which_type_second.isString())
58throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Function {}'s 2nd argument type must be string.", name);
59DataTypePtr date_time_type;
60if (which_type_first.isDateTime())
61date_time_type = std::make_shared<DataTypeDateTime>();
62else
63{
64const DataTypeDateTime64 * date_time_64 = static_cast<const DataTypeDateTime64 *>(arguments[0].get());
65date_time_type = std::make_shared<DataTypeDateTime64>(date_time_64->getScale());
66}
67return date_time_type;
68}
69
70ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t) const override
71{
72if (arguments.size() != 2)
73throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Function {}'s arguments number must be 2.", name);
74const ColumnWithTypeAndName & arg1 = arguments[0];
75const ColumnWithTypeAndName & arg2 = arguments[1];
76const auto * time_zone_const_col = checkAndGetColumnConstData<ColumnString>(arg2.column.get());
77if (!time_zone_const_col)
78throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of 2nd argument of function {}. Excepted const(String).", arg2.column->getName(), name);
79String time_zone_val = time_zone_const_col->getDataAt(0).toString();
80auto column = result_type->createColumn();
81if (WhichDataType(arg1.type).isDateTime())
82{
83const auto * date_time_col = checkAndGetColumn<ColumnDateTime>(arg1.column.get());
84for (size_t i = 0; i < date_time_col->size(); ++i)
85{
86UInt32 date_time_val = date_time_col->getElement(i);
87LocalDateTime date_time(date_time_val, Name::to ? DateLUT::instance("UTC") : DateLUT::instance(time_zone_val));
88time_t time_val = date_time.to_time_t(Name::from ? DateLUT::instance("UTC") : DateLUT::instance(time_zone_val));
89column->insert(time_val);
90}
91}
92else if (WhichDataType(arg1.type).isDateTime64())
93{
94const auto * date_time_col = checkAndGetColumn<ColumnDateTime64>(arg1.column.get());
95const DataTypeDateTime64 * date_time_type = static_cast<const DataTypeDateTime64 *>(arg1.type.get());
96Int64 scale_multiplier = DecimalUtils::scaleMultiplier<Int64>(date_time_type->getScale());
97for (size_t i = 0; i < date_time_col->size(); ++i)
98{
99DateTime64 date_time_val = date_time_col->getElement(i);
100Int64 seconds = date_time_val.value / scale_multiplier;
101Int64 micros = date_time_val.value % scale_multiplier;
102LocalDateTime date_time(seconds, Name::to ? DateLUT::instance("UTC") : DateLUT::instance(time_zone_val));
103time_t time_val = date_time.to_time_t(Name::from ? DateLUT::instance("UTC") : DateLUT::instance(time_zone_val));
104DateTime64 date_time_64(time_val * scale_multiplier + micros);
105column->insert(date_time_64);
106}
107}
108else
109throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Function {}'s 1st argument can only be datetime/datatime64. ", name);
110return column;
111}
112
113};
114
115struct NameToUTCTimestamp
116{
117static constexpr auto name = "toUTCTimestamp";
118static constexpr auto from = false;
119static constexpr auto to = true;
120};
121
122struct NameFromUTCTimestamp
123{
124static constexpr auto name = "fromUTCTimestamp";
125static constexpr auto from = true;
126static constexpr auto to = false;
127};
128
129using ToUTCTimestampFunction = UTCTimestampTransform<NameToUTCTimestamp>;
130using FromUTCTimestampFunction = UTCTimestampTransform<NameFromUTCTimestamp>;
131}
132
133REGISTER_FUNCTION(UTCTimestampTransform)
134{
135factory.registerFunction<ToUTCTimestampFunction>();
136factory.registerFunction<FromUTCTimestampFunction>();
137factory.registerAlias("to_utc_timestamp", NameToUTCTimestamp::name, FunctionFactory::CaseInsensitive);
138factory.registerAlias("from_utc_timestamp", NameFromUTCTimestamp::name, FunctionFactory::CaseInsensitive);
139}
140
141}
142