ClickHouse

Форк
0
/
dateName.cpp 
360 строк · 11.6 Кб
1
#include <Common/DateLUTImpl.h>
2

3
#include <Core/DecimalFunctions.h>
4
#include <IO/WriteHelpers.h>
5

6
#include <DataTypes/DataTypeDate.h>
7
#include <DataTypes/DataTypeDate32.h>
8
#include <DataTypes/DataTypeDateTime.h>
9
#include <DataTypes/DataTypeDateTime64.h>
10
#include <DataTypes/DataTypeString.h>
11
#include <Columns/ColumnString.h>
12

13
#include <Functions/DateTimeTransforms.h>
14
#include <Functions/FunctionFactory.h>
15
#include <Functions/FunctionHelpers.h>
16
#include <Functions/extractTimeZoneFromFunctionArguments.h>
17

18
namespace DB
19
{
20
namespace ErrorCodes
21
{
22
    extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
23
    extern const int ILLEGAL_TYPE_OF_ARGUMENT;
24
    extern const int ILLEGAL_COLUMN;
25
    extern const int BAD_ARGUMENTS;
26
}
27

28
namespace
29
{
30

31
template <typename DataType> struct DataTypeToTimeTypeMap {};
32

33
template <> struct DataTypeToTimeTypeMap<DataTypeDate>
34
{
35
    using TimeType = UInt16;
36
};
37

38
template <> struct DataTypeToTimeTypeMap<DataTypeDate32>
39
{
40
    using TimeType = Int32;
41
};
42

43
template <> struct DataTypeToTimeTypeMap<DataTypeDateTime>
44
{
45
    using TimeType = UInt32;
46
};
47

48
template <> struct DataTypeToTimeTypeMap<DataTypeDateTime64>
49
{
50
    using TimeType = Int64;
51
};
52

53
template <typename DataType>
54
using DateTypeToTimeType = typename DataTypeToTimeTypeMap<DataType>::TimeType;
55

56
class FunctionDateNameImpl : public IFunction
57
{
58
public:
59
    static constexpr auto name = "dateName";
60

61
    static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionDateNameImpl>(); }
62

63
    String getName() const override { return name; }
64

65
    bool useDefaultImplementationForConstants() const override { return true; }
66

67
    bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
68

69
    ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {0, 2}; }
70

71
    bool isVariadic() const override { return true; }
72
    size_t getNumberOfArguments() const override { return 0; }
73

74
    DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
75
    {
76
        if (arguments.size() != 2 && arguments.size() != 3)
77
            throw Exception(
78
                ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
79
                "Number of arguments for function {} doesn't match: passed {}",
80
                getName(),
81
                arguments.size());
82

83
        if (!WhichDataType(arguments[0].type).isString())
84
            throw Exception(
85
                ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
86
                "Illegal type {} of 1 argument of function {}. Must be string",
87
                arguments[0].type->getName(),
88
                getName());
89

90
        WhichDataType first_argument_type(arguments[1].type);
91

92
        if (!(first_argument_type.isDate() || first_argument_type.isDateTime() || first_argument_type.isDate32() || first_argument_type.isDateTime64()))
93
            throw Exception(
94
                ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
95
                "Illegal type {} of 2 argument of function {}. Must be a date or a date with time",
96
                arguments[1].type->getName(),
97
                getName());
98

99
        if (arguments.size() == 3 && !WhichDataType(arguments[2].type).isString())
100
            throw Exception(
101
                ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
102
                "Illegal type {} of 3 argument of function {}. Must be string",
103
                arguments[2].type->getName(),
104
                getName());
105

106
        return std::make_shared<DataTypeString>();
107
    }
108

109
    ColumnPtr executeImpl(
110
        const ColumnsWithTypeAndName & arguments,
111
        const DataTypePtr & result_type,
112
        [[maybe_unused]] size_t input_rows_count) const override
113
    {
114
        ColumnPtr res;
115

116
        if (!((res = executeType<DataTypeDate>(arguments, result_type))
117
            || (res = executeType<DataTypeDate32>(arguments, result_type))
118
            || (res = executeType<DataTypeDateTime>(arguments, result_type))
119
            || (res = executeType<DataTypeDateTime64>(arguments, result_type))))
120
            throw Exception(
121
                ErrorCodes::ILLEGAL_COLUMN,
122
                "Illegal column {} of function {}, must be Date or DateTime.",
123
                arguments[1].column->getName(),
124
                getName());
125

126
        return res;
127
    }
128

129
    template <typename DataType>
130
    ColumnPtr executeType(const ColumnsWithTypeAndName & arguments, const DataTypePtr &) const
131
    {
132
        auto * times = checkAndGetColumn<typename DataType::ColumnType>(arguments[1].column.get());
133
        if (!times)
134
            return nullptr;
135

136
        const ColumnConst * date_part_column = checkAndGetColumnConst<ColumnString>(arguments[0].column.get());
137
        if (!date_part_column)
138
            throw Exception(
139
                ErrorCodes::ILLEGAL_COLUMN,
140
                "Illegal column {} of first ('datepart') argument of function {}. Must be constant string.",
141
                arguments[0].column->getName(),
142
                getName());
143

144
        String date_part = date_part_column->getValue<String>();
145

146
        const DateLUTImpl * time_zone_tmp;
147
        if (std::is_same_v<DataType, DataTypeDateTime64> || std::is_same_v<DataType, DataTypeDateTime>)
148
            time_zone_tmp = &extractTimeZoneFromFunctionArguments(arguments, 2, 1);
149
        else
150
            time_zone_tmp = &DateLUT::instance();
151

152
        const auto & times_data = times->getData();
153
        const DateLUTImpl & time_zone = *time_zone_tmp;
154

155
        UInt32 scale [[maybe_unused]] = 0;
156
        if constexpr (std::is_same_v<DataType, DataTypeDateTime64>)
157
        {
158
            scale = times->getScale();
159
        }
160

161
        auto result_column = ColumnString::create();
162
        auto & result_column_data = result_column->getChars();
163
        auto & result_column_offsets = result_column->getOffsets();
164

165
        /* longest possible word 'Wednesday' with zero terminator */
166
        static constexpr size_t longest_word_length = 9 + 1;
167

168
        result_column_data.resize_fill(times_data.size() * longest_word_length);
169
        result_column_offsets.resize(times_data.size());
170

171
        auto * begin = reinterpret_cast<char *>(result_column_data.data());
172

173
        WriteBufferFromPointer buffer(begin, result_column_data.size());
174

175
        using TimeType = DateTypeToTimeType<DataType>;
176
        callOnDatePartWriter<TimeType>(date_part, [&](const auto & writer)
177
        {
178
            for (size_t i = 0; i < times_data.size(); ++i)
179
            {
180
                if constexpr (std::is_same_v<DataType, DataTypeDateTime64>)
181
                {
182
                    const auto components = DecimalUtils::split(times_data[i], scale);
183
                    writer.write(buffer, static_cast<Int64>(components.whole), time_zone);
184
                }
185
                else
186
                {
187
                    writer.write(buffer, times_data[i], time_zone);
188
                }
189

190
                /// Null terminator
191
                ++buffer.position();
192
                result_column_offsets[i] = buffer.position() - begin;
193
            }
194
        });
195

196
        result_column_data.resize(buffer.position() - begin);
197

198
        buffer.finalize();
199

200
        return result_column;
201
    }
202

203
private:
204

205
    template <typename Time>
206
    struct YearWriter
207
    {
208
        static void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone)
209
        {
210
            writeText(ToYearImpl::execute(source, timezone), buffer);
211
        }
212
    };
213

214
    template <typename Time>
215
    struct QuarterWriter
216
    {
217
        static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone)
218
        {
219
            writeText(ToQuarterImpl::execute(source, timezone), buffer);
220
        }
221
    };
222

223
    template <typename Time>
224
    struct MonthWriter
225
    {
226
        static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone)
227
        {
228
            const auto month = ToMonthImpl::execute(source, timezone);
229
            static constexpr std::string_view month_names[] =
230
            {
231
                "January",
232
                "February",
233
                "March",
234
                "April",
235
                "May",
236
                "June",
237
                "July",
238
                "August",
239
                "September",
240
                "October",
241
                "November",
242
                "December"
243
            };
244

245
            writeText(month_names[month - 1], buffer);
246
        }
247
    };
248

249
    template <typename Time>
250
    struct WeekWriter
251
    {
252
        static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone)
253
        {
254
            writeText(ToISOWeekImpl::execute(source, timezone), buffer);
255
        }
256
    };
257

258
    template <typename Time>
259
    struct DayOfYearWriter
260
    {
261
        static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone)
262
        {
263
            writeText(ToDayOfYearImpl::execute(source, timezone), buffer);
264
        }
265
    };
266

267
    template <typename Time>
268
    struct DayWriter
269
    {
270
        static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone)
271
        {
272
            writeText(ToDayOfMonthImpl::execute(source, timezone), buffer);
273
        }
274
    };
275

276
    template <typename Time>
277
    struct WeekDayWriter
278
    {
279
        static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone)
280
        {
281
            const auto day = ToDayOfWeekImpl::execute(source, 0, timezone);
282
            static constexpr std::string_view day_names[] =
283
            {
284
                "Monday",
285
                "Tuesday",
286
                "Wednesday",
287
                "Thursday",
288
                "Friday",
289
                "Saturday",
290
                "Sunday"
291
            };
292

293
            writeText(day_names[day - 1], buffer);
294
        }
295
    };
296

297
    template <typename Time>
298
    struct HourWriter
299
    {
300
        static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone)
301
        {
302
            writeText(ToHourImpl::execute(source, timezone), buffer);
303
        }
304
    };
305

306
    template <typename Time>
307
    struct MinuteWriter
308
    {
309
        static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone)
310
        {
311
            writeText(ToMinuteImpl::execute(source, timezone), buffer);
312
        }
313
    };
314

315
    template <typename Time>
316
    struct SecondWriter
317
    {
318
        static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone)
319
        {
320
            writeText(ToSecondImpl::execute(source, timezone), buffer);
321
        }
322
    };
323

324
    template <typename Time, typename Call>
325
    void callOnDatePartWriter(const String & date_part, Call && call) const
326
    {
327
        if (date_part == "year")
328
            std::forward<Call>(call)(YearWriter<Time>());
329
        else if (date_part == "quarter")
330
            std::forward<Call>(call)(QuarterWriter<Time>());
331
        else if (date_part == "month")
332
            std::forward<Call>(call)(MonthWriter<Time>());
333
        else if (date_part == "week")
334
            std::forward<Call>(call)(WeekWriter<Time>());
335
        else if (date_part == "dayofyear")
336
            std::forward<Call>(call)(DayOfYearWriter<Time>());
337
        else if (date_part == "day")
338
            std::forward<Call>(call)(DayWriter<Time>());
339
        else if (date_part == "weekday")
340
            std::forward<Call>(call)(WeekDayWriter<Time>());
341
        else if (date_part == "hour")
342
            std::forward<Call>(call)(HourWriter<Time>());
343
        else if (date_part == "minute")
344
            std::forward<Call>(call)(MinuteWriter<Time>());
345
        else if (date_part == "second")
346
            std::forward<Call>(call)(SecondWriter<Time>());
347
        else
348
            throw Exception(ErrorCodes::BAD_ARGUMENTS, "Invalid date part {} for function {}", date_part, getName());
349
    }
350

351
};
352

353
}
354

355
REGISTER_FUNCTION(DateName)
356
{
357
    factory.registerFunction<FunctionDateNameImpl>({}, FunctionFactory::CaseInsensitive);
358
}
359

360
}
361

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.