ClickHouse
131 строка · 4.8 Кб
1#include <Functions/IFunction.h>
2#include <Columns/ColumnConst.h>
3#include <Columns/ColumnDecimal.h>
4#include <DataTypes/DataTypeDate.h>
5#include <DataTypes/DataTypeDate32.h>
6#include <Functions/DateTimeTransforms.h>
7#include <Functions/FunctionFactory.h>
8#include <Functions/FunctionHelpers.h>
9#include <Interpreters/castColumn.h>
10
11#include <Common/DateLUT.h>
12
13#include <array>
14#include <cmath>
15
16namespace DB
17{
18namespace ErrorCodes
19{
20extern const int ILLEGAL_TYPE_OF_ARGUMENT;
21extern const int ARGUMENT_OUT_OF_BOUND;
22}
23
24namespace
25{
26
27struct DateTraits
28{
29static constexpr auto name = "fromDaysSinceYearZero";
30using ReturnDataType = DataTypeDate;
31};
32
33struct DateTraits32
34{
35static constexpr auto name = "fromDaysSinceYearZero32";
36using ReturnDataType = DataTypeDate32;
37};
38
39template <typename Traits>
40class FunctionFromDaysSinceYearZero : public IFunction
41{
42public:
43static constexpr auto name = Traits::name;
44using RawReturnType = typename Traits::ReturnDataType::FieldType;
45
46static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionFromDaysSinceYearZero>(); }
47
48String getName() const override { return name; }
49bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; }
50bool useDefaultImplementationForConstants() const override { return true; }
51size_t getNumberOfArguments() const override { return 1; }
52
53DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
54{
55FunctionArgumentDescriptors args{{"days", static_cast<FunctionArgumentDescriptor::TypeValidator>(&isNativeInteger), nullptr, "Integer"}};
56
57validateFunctionArgumentTypes(*this, arguments, args);
58
59return std::make_shared<typename Traits::ReturnDataType>();
60}
61
62ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
63{
64auto res_column = Traits::ReturnDataType::ColumnType::create(input_rows_count);
65const auto & src_column = arguments[0];
66
67auto try_type = [&]<typename T>(T)
68{
69using ColVecType = ColumnVector<T>;
70
71if (const ColVecType * col_vec = checkAndGetColumn<ColVecType>(src_column.column.get()))
72{
73execute<T>(*col_vec, *res_column, input_rows_count);
74return true;
75}
76return false;
77};
78
79const bool success = try_type(UInt8{}) || try_type(UInt16{}) || try_type(UInt32{}) || try_type(UInt64{})
80|| try_type(Int8{}) || try_type(Int16{}) || try_type(Int32{}) || try_type(Int64{});
81
82if (!success)
83throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal column while execute function {}", getName());
84
85return res_column;
86}
87
88template <typename T, typename ColVecType, typename ResCol>
89void execute(const ColVecType & col, ResCol & result_column, size_t rows_count) const
90{
91const auto & src_data = col.getData();
92auto & dst_data = result_column.getData();
93dst_data.resize(rows_count);
94
95for (size_t i = 0; i < rows_count; ++i)
96{
97auto value = src_data[i];
98if (value < 0)
99throw Exception(ErrorCodes::ARGUMENT_OUT_OF_BOUND, "Expected a non-negative integer, got: {}", std::to_string(value));
100/// prevent potential signed integer overflows (aka. undefined behavior) with Date32 results
101auto value_uint64 = static_cast<UInt64>(value); /// NOLINT(bugprone-signed-char-misuse,cert-str34-c)
102dst_data[i] = static_cast<RawReturnType>(value_uint64 - ToDaysSinceYearZeroImpl::DAYS_BETWEEN_YEARS_0_AND_1970);
103}
104}
105};
106
107
108}
109
110REGISTER_FUNCTION(FromDaysSinceYearZero)
111{
112factory.registerFunction<FunctionFromDaysSinceYearZero<DateTraits>>(FunctionDocumentation{
113.description = R"(
114Given the number of days passed since 1 January 0000 in the proleptic Gregorian calendar defined by ISO 8601 return a corresponding date.
115The calculation is the same as in MySQL's FROM_DAYS() function.
116)",
117.examples{{"typical", "SELECT fromDaysSinceYearZero(713569)", "2023-09-08"}},
118.categories{"Dates and Times"}});
119
120factory.registerFunction<FunctionFromDaysSinceYearZero<DateTraits32>>(FunctionDocumentation{
121.description = R"(
122Given the number of days passed since 1 January 0000 in the proleptic Gregorian calendar defined by ISO 8601 return a corresponding date.
123The calculation is the same as in MySQL's FROM_DAYS() function.
124)",
125.examples{{"typical", "SELECT fromDaysSinceYearZero32(713569)", "2023-09-08"}},
126.categories{"Dates and Times"}});
127
128factory.registerAlias("FROM_DAYS", FunctionFromDaysSinceYearZero<DateTraits>::name, FunctionFactory::CaseInsensitive);
129}
130
131}
132