ClickHouse
139 строк · 4.7 Кб
1#include <DataTypes/DataTypeDateTime.h>
2#include <DataTypes/DataTypeDateTime64.h>
3
4#include <Functions/IFunction.h>
5#include <Functions/FunctionFactory.h>
6#include <Functions/extractTimeZoneFromFunctionArguments.h>
7
8#include <Interpreters/Context.h>
9
10#include <IO/WriteHelpers.h>
11#include <Common/assert_cast.h>
12
13namespace DB
14{
15namespace ErrorCodes
16{
17extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
18extern const int ILLEGAL_TYPE_OF_ARGUMENT;
19}
20
21namespace
22{
23class ExecutableFunctionToTimeZone : public IExecutableFunction
24{
25public:
26explicit ExecutableFunctionToTimeZone() = default;
27
28String getName() const override { return "toTimezone"; }
29
30ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t /*input_rows_count*/) const override
31{
32return arguments[0].column;
33}
34};
35
36class FunctionBaseToTimeZone : public IFunctionBase
37{
38public:
39FunctionBaseToTimeZone(
40bool is_constant_timezone_,
41DataTypes argument_types_,
42DataTypePtr return_type_)
43: is_constant_timezone(is_constant_timezone_)
44, argument_types(std::move(argument_types_))
45, return_type(std::move(return_type_)) {}
46
47String getName() const override { return "toTimezone"; }
48
49bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
50
51const DataTypes & getArgumentTypes() const override
52{
53return argument_types;
54}
55
56const DataTypePtr & getResultType() const override
57{
58return return_type;
59}
60
61ExecutableFunctionPtr prepare(const ColumnsWithTypeAndName & /*arguments*/) const override
62{
63return std::make_unique<ExecutableFunctionToTimeZone>();
64}
65
66bool hasInformationAboutMonotonicity() const override { return is_constant_timezone; }
67
68Monotonicity getMonotonicityForRange(const IDataType & /*type*/, const Field & /*left*/, const Field & /*right*/) const override
69{
70const bool b = is_constant_timezone;
71return { .is_monotonic = b, .is_positive = b, .is_always_monotonic = b, .is_strict = b };
72}
73
74private:
75bool is_constant_timezone;
76DataTypes argument_types;
77DataTypePtr return_type;
78};
79
80/// Just changes time zone information for data type. The calculation is free.
81class ToTimeZoneOverloadResolver : public IFunctionOverloadResolver
82{
83public:
84static constexpr auto name = "toTimezone";
85
86String getName() const override { return name; }
87
88size_t getNumberOfArguments() const override { return 2; }
89static FunctionOverloadResolverPtr create(ContextPtr context) { return std::make_unique<ToTimeZoneOverloadResolver>(context); }
90explicit ToTimeZoneOverloadResolver(ContextPtr context)
91: allow_nonconst_timezone_arguments(context->getSettings().allow_nonconst_timezone_arguments)
92{}
93
94DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
95{
96if (arguments.size() != 2)
97throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
98"Number of arguments for function {} doesn't match: passed {}, should be 2",
99getName(), arguments.size());
100
101const auto which_type = WhichDataType(arguments[0].type);
102if (!which_type.isDateTime() && !which_type.isDateTime64())
103throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type {} of argument of function {}. "
104"Should be DateTime or DateTime64", arguments[0].type->getName(), getName());
105
106String time_zone_name = extractTimeZoneNameFromFunctionArguments(arguments, 1, 0, allow_nonconst_timezone_arguments);
107
108if (which_type.isDateTime())
109return std::make_shared<DataTypeDateTime>(time_zone_name);
110
111const auto * date_time64 = assert_cast<const DataTypeDateTime64 *>(arguments[0].type.get());
112return std::make_shared<DataTypeDateTime64>(date_time64->getScale(), time_zone_name);
113}
114
115FunctionBasePtr buildImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type) const override
116{
117bool is_constant_timezone = false;
118if (arguments[1].column)
119is_constant_timezone = isColumnConst(*arguments[1].column);
120
121DataTypes data_types(arguments.size());
122for (size_t i = 0; i < arguments.size(); ++i)
123data_types[i] = arguments[i].type;
124
125return std::make_unique<FunctionBaseToTimeZone>(is_constant_timezone, data_types, result_type);
126}
127private:
128const bool allow_nonconst_timezone_arguments;
129};
130
131}
132
133REGISTER_FUNCTION(ToTimeZone)
134{
135factory.registerFunction<ToTimeZoneOverloadResolver>();
136factory.registerAlias("toTimeZone", "toTimezone");
137}
138
139}
140