ClickHouse
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
18namespace DB19{
20namespace ErrorCodes21{
22extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;23extern const int ILLEGAL_TYPE_OF_ARGUMENT;24extern const int ILLEGAL_COLUMN;25extern const int BAD_ARGUMENTS;26}
27
28namespace
29{
30
31template <typename DataType> struct DataTypeToTimeTypeMap {};32
33template <> struct DataTypeToTimeTypeMap<DataTypeDate>34{
35using TimeType = UInt16;36};37
38template <> struct DataTypeToTimeTypeMap<DataTypeDate32>39{
40using TimeType = Int32;41};42
43template <> struct DataTypeToTimeTypeMap<DataTypeDateTime>44{
45using TimeType = UInt32;46};47
48template <> struct DataTypeToTimeTypeMap<DataTypeDateTime64>49{
50using TimeType = Int64;51};52
53template <typename DataType>54using DateTypeToTimeType = typename DataTypeToTimeTypeMap<DataType>::TimeType;55
56class FunctionDateNameImpl : public IFunction57{
58public:59static constexpr auto name = "dateName";60
61static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionDateNameImpl>(); }62
63String getName() const override { return name; }64
65bool useDefaultImplementationForConstants() const override { return true; }66
67bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }68
69ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {0, 2}; }70
71bool isVariadic() const override { return true; }72size_t getNumberOfArguments() const override { return 0; }73
74DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override75{76if (arguments.size() != 2 && arguments.size() != 3)77throw Exception(78ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,79"Number of arguments for function {} doesn't match: passed {}",80getName(),81arguments.size());82
83if (!WhichDataType(arguments[0].type).isString())84throw Exception(85ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,86"Illegal type {} of 1 argument of function {}. Must be string",87arguments[0].type->getName(),88getName());89
90WhichDataType first_argument_type(arguments[1].type);91
92if (!(first_argument_type.isDate() || first_argument_type.isDateTime() || first_argument_type.isDate32() || first_argument_type.isDateTime64()))93throw Exception(94ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,95"Illegal type {} of 2 argument of function {}. Must be a date or a date with time",96arguments[1].type->getName(),97getName());98
99if (arguments.size() == 3 && !WhichDataType(arguments[2].type).isString())100throw Exception(101ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,102"Illegal type {} of 3 argument of function {}. Must be string",103arguments[2].type->getName(),104getName());105
106return std::make_shared<DataTypeString>();107}108
109ColumnPtr executeImpl(110const ColumnsWithTypeAndName & arguments,111const DataTypePtr & result_type,112[[maybe_unused]] size_t input_rows_count) const override113{114ColumnPtr res;115
116if (!((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))))120throw Exception(121ErrorCodes::ILLEGAL_COLUMN,122"Illegal column {} of function {}, must be Date or DateTime.",123arguments[1].column->getName(),124getName());125
126return res;127}128
129template <typename DataType>130ColumnPtr executeType(const ColumnsWithTypeAndName & arguments, const DataTypePtr &) const131{132auto * times = checkAndGetColumn<typename DataType::ColumnType>(arguments[1].column.get());133if (!times)134return nullptr;135
136const ColumnConst * date_part_column = checkAndGetColumnConst<ColumnString>(arguments[0].column.get());137if (!date_part_column)138throw Exception(139ErrorCodes::ILLEGAL_COLUMN,140"Illegal column {} of first ('datepart') argument of function {}. Must be constant string.",141arguments[0].column->getName(),142getName());143
144String date_part = date_part_column->getValue<String>();145
146const DateLUTImpl * time_zone_tmp;147if (std::is_same_v<DataType, DataTypeDateTime64> || std::is_same_v<DataType, DataTypeDateTime>)148time_zone_tmp = &extractTimeZoneFromFunctionArguments(arguments, 2, 1);149else150time_zone_tmp = &DateLUT::instance();151
152const auto & times_data = times->getData();153const DateLUTImpl & time_zone = *time_zone_tmp;154
155UInt32 scale [[maybe_unused]] = 0;156if constexpr (std::is_same_v<DataType, DataTypeDateTime64>)157{158scale = times->getScale();159}160
161auto result_column = ColumnString::create();162auto & result_column_data = result_column->getChars();163auto & result_column_offsets = result_column->getOffsets();164
165/* longest possible word 'Wednesday' with zero terminator */166static constexpr size_t longest_word_length = 9 + 1;167
168result_column_data.resize_fill(times_data.size() * longest_word_length);169result_column_offsets.resize(times_data.size());170
171auto * begin = reinterpret_cast<char *>(result_column_data.data());172
173WriteBufferFromPointer buffer(begin, result_column_data.size());174
175using TimeType = DateTypeToTimeType<DataType>;176callOnDatePartWriter<TimeType>(date_part, [&](const auto & writer)177{178for (size_t i = 0; i < times_data.size(); ++i)179{180if constexpr (std::is_same_v<DataType, DataTypeDateTime64>)181{182const auto components = DecimalUtils::split(times_data[i], scale);183writer.write(buffer, static_cast<Int64>(components.whole), time_zone);184}185else186{187writer.write(buffer, times_data[i], time_zone);188}189
190/// Null terminator191++buffer.position();192result_column_offsets[i] = buffer.position() - begin;193}194});195
196result_column_data.resize(buffer.position() - begin);197
198buffer.finalize();199
200return result_column;201}202
203private:204
205template <typename Time>206struct YearWriter207{208static void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone)209{210writeText(ToYearImpl::execute(source, timezone), buffer);211}212};213
214template <typename Time>215struct QuarterWriter216{217static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone)218{219writeText(ToQuarterImpl::execute(source, timezone), buffer);220}221};222
223template <typename Time>224struct MonthWriter225{226static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone)227{228const auto month = ToMonthImpl::execute(source, timezone);229static 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
245writeText(month_names[month - 1], buffer);246}247};248
249template <typename Time>250struct WeekWriter251{252static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone)253{254writeText(ToISOWeekImpl::execute(source, timezone), buffer);255}256};257
258template <typename Time>259struct DayOfYearWriter260{261static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone)262{263writeText(ToDayOfYearImpl::execute(source, timezone), buffer);264}265};266
267template <typename Time>268struct DayWriter269{270static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone)271{272writeText(ToDayOfMonthImpl::execute(source, timezone), buffer);273}274};275
276template <typename Time>277struct WeekDayWriter278{279static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone)280{281const auto day = ToDayOfWeekImpl::execute(source, 0, timezone);282static constexpr std::string_view day_names[] =283{284"Monday",285"Tuesday",286"Wednesday",287"Thursday",288"Friday",289"Saturday",290"Sunday"291};292
293writeText(day_names[day - 1], buffer);294}295};296
297template <typename Time>298struct HourWriter299{300static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone)301{302writeText(ToHourImpl::execute(source, timezone), buffer);303}304};305
306template <typename Time>307struct MinuteWriter308{309static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone)310{311writeText(ToMinuteImpl::execute(source, timezone), buffer);312}313};314
315template <typename Time>316struct SecondWriter317{318static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone)319{320writeText(ToSecondImpl::execute(source, timezone), buffer);321}322};323
324template <typename Time, typename Call>325void callOnDatePartWriter(const String & date_part, Call && call) const326{327if (date_part == "year")328std::forward<Call>(call)(YearWriter<Time>());329else if (date_part == "quarter")330std::forward<Call>(call)(QuarterWriter<Time>());331else if (date_part == "month")332std::forward<Call>(call)(MonthWriter<Time>());333else if (date_part == "week")334std::forward<Call>(call)(WeekWriter<Time>());335else if (date_part == "dayofyear")336std::forward<Call>(call)(DayOfYearWriter<Time>());337else if (date_part == "day")338std::forward<Call>(call)(DayWriter<Time>());339else if (date_part == "weekday")340std::forward<Call>(call)(WeekDayWriter<Time>());341else if (date_part == "hour")342std::forward<Call>(call)(HourWriter<Time>());343else if (date_part == "minute")344std::forward<Call>(call)(MinuteWriter<Time>());345else if (date_part == "second")346std::forward<Call>(call)(SecondWriter<Time>());347else348throw Exception(ErrorCodes::BAD_ARGUMENTS, "Invalid date part {} for function {}", date_part, getName());349}350
351};352
353}
354
355REGISTER_FUNCTION(DateName)356{
357factory.registerFunction<FunctionDateNameImpl>({}, FunctionFactory::CaseInsensitive);358}
359
360}
361