#include #include #include #include #include #include #include #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; extern const int ILLEGAL_TYPE_OF_ARGUMENT; extern const int ILLEGAL_COLUMN; extern const int BAD_ARGUMENTS; } namespace { template struct DataTypeToTimeTypeMap {}; template <> struct DataTypeToTimeTypeMap { using TimeType = UInt16; }; template <> struct DataTypeToTimeTypeMap { using TimeType = UInt32; }; template <> struct DataTypeToTimeTypeMap { using TimeType = Int64; }; template using DateTypeToTimeType = typename DataTypeToTimeTypeMap::TimeType; class FunctionDateNameImpl : public IFunction { public: static constexpr auto name = "dateName"; static FunctionPtr create(ContextPtr) { return std::make_shared(); } String getName() const override { return name; } bool useDefaultImplementationForConstants() const override { return true; } bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; } ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {0, 2}; } bool isVariadic() const override { return true; } size_t getNumberOfArguments() const override { return 0; } DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override { if (arguments.size() != 2 && arguments.size() != 3) throw Exception( ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Number of arguments for function {} doesn't match: passed {}", getName(), toString(arguments.size())); if (!WhichDataType(arguments[0].type).isString()) throw Exception( ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type {} of 1 argument of function {}. Must be string", arguments[0].type->getName(), getName()); WhichDataType first_argument_type(arguments[1].type); if (!(first_argument_type.isDate() || first_argument_type.isDateTime() || first_argument_type.isDateTime64())) throw Exception( ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type {} of 2 argument of function {}. Must be a date or a date with time", arguments[1].type->getName(), getName()); if (arguments.size() == 3 && !WhichDataType(arguments[2].type).isString()) throw Exception( ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type {} of 3 argument of function {}. Must be string", arguments[2].type->getName(), getName()); return std::make_shared(); } ColumnPtr executeImpl( const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, [[maybe_unused]] size_t input_rows_count) const override { ColumnPtr res; if (!((res = executeType(arguments, result_type)) || (res = executeType(arguments, result_type)) || (res = executeType(arguments, result_type)))) throw Exception( ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of function {}, must be Date or DateTime.", arguments[1].column->getName(), getName()); return res; } template ColumnPtr executeType(const ColumnsWithTypeAndName & arguments, const DataTypePtr &) const { auto * times = checkAndGetColumn(arguments[1].column.get()); if (!times) return nullptr; const ColumnConst * date_part_column = checkAndGetColumnConst(arguments[0].column.get()); if (!date_part_column) throw Exception( ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of first ('datepart') argument of function {}. Must be constant string.", arguments[0].column->getName(), getName()); String date_part = date_part_column->getValue(); const DateLUTImpl * time_zone_tmp; if (std::is_same_v || std::is_same_v) time_zone_tmp = &extractTimeZoneFromFunctionArguments(arguments, 2, 1); else time_zone_tmp = &DateLUT::instance(); const auto & times_data = times->getData(); const DateLUTImpl & time_zone = *time_zone_tmp; UInt32 scale [[maybe_unused]] = 0; if constexpr (std::is_same_v) { scale = times->getScale(); } auto result_column = ColumnString::create(); auto & result_column_data = result_column->getChars(); auto & result_column_offsets = result_column->getOffsets(); /* longest possible word 'Wednesday' with zero terminator */ static constexpr size_t longest_word_length = 9 + 1; result_column_data.resize_fill(times_data.size() * longest_word_length); result_column_offsets.resize(times_data.size()); auto * begin = reinterpret_cast(result_column_data.data()); WriteBuffer buffer(begin, result_column_data.size()); using TimeType = DateTypeToTimeType; callOnDatePartWriter(date_part, [&](const auto & writer) { for (size_t i = 0; i < times_data.size(); ++i) { if constexpr (std::is_same_v) { const auto components = DecimalUtils::split(times_data[i], scale); writer.write(buffer, static_cast(components.whole), time_zone); } else { writer.write(buffer, times_data[i], time_zone); } /// Null terminator ++buffer.position(); result_column_offsets[i] = buffer.position() - begin; } }); result_column_data.resize(buffer.position() - begin); return result_column; } private: template struct YearWriter { static void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone) { writeText(ToYearImpl::execute(source, timezone), buffer); } }; template struct QuarterWriter { static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone) { writeText(ToQuarterImpl::execute(source, timezone), buffer); } }; template struct MonthWriter { static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone) { const auto month = ToMonthImpl::execute(source, timezone); static constexpr std::string_view month_names[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; writeText(month_names[month - 1], buffer); } }; template struct WeekWriter { static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone) { writeText(ToISOWeekImpl::execute(source, timezone), buffer); } }; template struct DayOfYearWriter { static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone) { writeText(ToDayOfYearImpl::execute(source, timezone), buffer); } }; template struct DayWriter { static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone) { writeText(ToDayOfMonthImpl::execute(source, timezone), buffer); } }; template struct WeekDayWriter { static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone) { const auto day = ToDayOfWeekImpl::execute(source, timezone); static constexpr std::string_view day_names[] = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" }; writeText(day_names[day - 1], buffer); } }; template struct HourWriter { static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone) { writeText(ToHourImpl::execute(source, timezone), buffer); } }; template struct MinuteWriter { static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone) { writeText(ToMinuteImpl::execute(source, timezone), buffer); } }; template struct SecondWriter { static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone) { writeText(ToSecondImpl::execute(source, timezone), buffer); } }; template void callOnDatePartWriter(const String & date_part, Call && call) const { if (date_part == "year") std::forward(call)(YearWriter