From 27b7654abc9d9ade0c91cbc352cd6205dc97d588 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 26 Sep 2018 03:31:40 +0300 Subject: [PATCH] Every function in its own file, part 5 [#CLICKHOUSE-2] --- dbms/src/Functions/DateTimeTransforms.h | 651 ++++++++++++++++++ .../FunctionDateOrDateTimeAddInterval.h | 308 +++++++++ .../FunctionDateOrDateTimeToSomething.h | 125 ++++ dbms/src/Functions/FunctionsConversion.h | 2 +- dbms/src/Functions/addDays.cpp | 18 + dbms/src/Functions/addHours.cpp | 18 + dbms/src/Functions/addMinutes.cpp | 18 + dbms/src/Functions/addMonths.cpp | 18 + dbms/src/Functions/addSeconds.cpp | 18 + dbms/src/Functions/addWeeks.cpp | 18 + dbms/src/Functions/addYears.cpp | 18 + dbms/src/Functions/dateDiff.cpp | 220 ++++++ .../extractTimeZoneFromFunctionArguments.cpp | 69 ++ .../extractTimeZoneFromFunctionArguments.h | 17 + dbms/src/Functions/formatDateTime.cpp | 571 +++++++++++++++ dbms/src/Functions/now.cpp | 44 ++ dbms/src/Functions/subtractDays.cpp | 18 + dbms/src/Functions/subtractHours.cpp | 18 + dbms/src/Functions/subtractMinutes.cpp | 18 + dbms/src/Functions/subtractMonths.cpp | 18 + dbms/src/Functions/subtractSeconds.cpp | 18 + dbms/src/Functions/subtractWeeks.cpp | 18 + dbms/src/Functions/subtractYears.cpp | 18 + dbms/src/Functions/timeSlot.cpp | 21 + dbms/src/Functions/timeSlots.cpp | 182 +++++ dbms/src/Functions/toDayOfMonth.cpp | 20 + dbms/src/Functions/toDayOfWeek.cpp | 20 + dbms/src/Functions/toDayOfYear.cpp | 20 + dbms/src/Functions/toHour.cpp | 20 + dbms/src/Functions/toISOWeek.cpp | 20 + dbms/src/Functions/toISOYear.cpp | 20 + dbms/src/Functions/toMinute.cpp | 20 + dbms/src/Functions/toMonday.cpp | 20 + dbms/src/Functions/toMonth.cpp | 20 + dbms/src/Functions/toQuarter.cpp | 20 + dbms/src/Functions/toRelativeDayNum.cpp | 20 + dbms/src/Functions/toRelativeHourNum.cpp | 20 + dbms/src/Functions/toRelativeMinuteNum.cpp | 20 + dbms/src/Functions/toRelativeMonthNum.cpp | 20 + dbms/src/Functions/toRelativeQuarterNum.cpp | 20 + dbms/src/Functions/toRelativeSecondNum.cpp | 20 + dbms/src/Functions/toRelativeWeekNum.cpp | 20 + dbms/src/Functions/toRelativeYearNum.cpp | 20 + dbms/src/Functions/toSecond.cpp | 20 + dbms/src/Functions/toStartOfDay.cpp | 20 + .../src/Functions/toStartOfFifteenMinutes.cpp | 20 + dbms/src/Functions/toStartOfFiveMinute.cpp | 20 + dbms/src/Functions/toStartOfHour.cpp | 20 + dbms/src/Functions/toStartOfISOYear.cpp | 20 + dbms/src/Functions/toStartOfMinute.cpp | 20 + dbms/src/Functions/toStartOfMonth.cpp | 20 + dbms/src/Functions/toStartOfQuarter.cpp | 20 + dbms/src/Functions/toStartOfYear.cpp | 20 + dbms/src/Functions/toTime.cpp | 20 + dbms/src/Functions/toTimeZone.cpp | 59 ++ dbms/src/Functions/toYYYYMM.cpp | 20 + dbms/src/Functions/toYYYYMMDD.cpp | 20 + dbms/src/Functions/toYYYYMMDDhhmmss.cpp | 20 + dbms/src/Functions/toYear.cpp | 20 + dbms/src/Functions/today.cpp | 45 ++ dbms/src/Functions/yesterday.cpp | 45 ++ 61 files changed, 3270 insertions(+), 1 deletion(-) create mode 100644 dbms/src/Functions/DateTimeTransforms.h create mode 100644 dbms/src/Functions/FunctionDateOrDateTimeAddInterval.h create mode 100644 dbms/src/Functions/FunctionDateOrDateTimeToSomething.h create mode 100644 dbms/src/Functions/addDays.cpp create mode 100644 dbms/src/Functions/addHours.cpp create mode 100644 dbms/src/Functions/addMinutes.cpp create mode 100644 dbms/src/Functions/addMonths.cpp create mode 100644 dbms/src/Functions/addSeconds.cpp create mode 100644 dbms/src/Functions/addWeeks.cpp create mode 100644 dbms/src/Functions/addYears.cpp create mode 100644 dbms/src/Functions/dateDiff.cpp create mode 100644 dbms/src/Functions/extractTimeZoneFromFunctionArguments.cpp create mode 100644 dbms/src/Functions/extractTimeZoneFromFunctionArguments.h create mode 100644 dbms/src/Functions/formatDateTime.cpp create mode 100644 dbms/src/Functions/now.cpp create mode 100644 dbms/src/Functions/subtractDays.cpp create mode 100644 dbms/src/Functions/subtractHours.cpp create mode 100644 dbms/src/Functions/subtractMinutes.cpp create mode 100644 dbms/src/Functions/subtractMonths.cpp create mode 100644 dbms/src/Functions/subtractSeconds.cpp create mode 100644 dbms/src/Functions/subtractWeeks.cpp create mode 100644 dbms/src/Functions/subtractYears.cpp create mode 100644 dbms/src/Functions/timeSlot.cpp create mode 100644 dbms/src/Functions/timeSlots.cpp create mode 100644 dbms/src/Functions/toDayOfMonth.cpp create mode 100644 dbms/src/Functions/toDayOfWeek.cpp create mode 100644 dbms/src/Functions/toDayOfYear.cpp create mode 100644 dbms/src/Functions/toHour.cpp create mode 100644 dbms/src/Functions/toISOWeek.cpp create mode 100644 dbms/src/Functions/toISOYear.cpp create mode 100644 dbms/src/Functions/toMinute.cpp create mode 100644 dbms/src/Functions/toMonday.cpp create mode 100644 dbms/src/Functions/toMonth.cpp create mode 100644 dbms/src/Functions/toQuarter.cpp create mode 100644 dbms/src/Functions/toRelativeDayNum.cpp create mode 100644 dbms/src/Functions/toRelativeHourNum.cpp create mode 100644 dbms/src/Functions/toRelativeMinuteNum.cpp create mode 100644 dbms/src/Functions/toRelativeMonthNum.cpp create mode 100644 dbms/src/Functions/toRelativeQuarterNum.cpp create mode 100644 dbms/src/Functions/toRelativeSecondNum.cpp create mode 100644 dbms/src/Functions/toRelativeWeekNum.cpp create mode 100644 dbms/src/Functions/toRelativeYearNum.cpp create mode 100644 dbms/src/Functions/toSecond.cpp create mode 100644 dbms/src/Functions/toStartOfDay.cpp create mode 100644 dbms/src/Functions/toStartOfFifteenMinutes.cpp create mode 100644 dbms/src/Functions/toStartOfFiveMinute.cpp create mode 100644 dbms/src/Functions/toStartOfHour.cpp create mode 100644 dbms/src/Functions/toStartOfISOYear.cpp create mode 100644 dbms/src/Functions/toStartOfMinute.cpp create mode 100644 dbms/src/Functions/toStartOfMonth.cpp create mode 100644 dbms/src/Functions/toStartOfQuarter.cpp create mode 100644 dbms/src/Functions/toStartOfYear.cpp create mode 100644 dbms/src/Functions/toTime.cpp create mode 100644 dbms/src/Functions/toTimeZone.cpp create mode 100644 dbms/src/Functions/toYYYYMM.cpp create mode 100644 dbms/src/Functions/toYYYYMMDD.cpp create mode 100644 dbms/src/Functions/toYYYYMMDDhhmmss.cpp create mode 100644 dbms/src/Functions/toYear.cpp create mode 100644 dbms/src/Functions/today.cpp create mode 100644 dbms/src/Functions/yesterday.cpp diff --git a/dbms/src/Functions/DateTimeTransforms.h b/dbms/src/Functions/DateTimeTransforms.h new file mode 100644 index 00000000000..9be0597698e --- /dev/null +++ b/dbms/src/Functions/DateTimeTransforms.h @@ -0,0 +1,651 @@ +#include +#include +#include +#include +#include +#include + + +namespace DB +{ + +namespace ErrorCodes +{ + extern const int ILLEGAL_TYPE_OF_ARGUMENT; + extern const int ILLEGAL_COLUMN; +} + +/** Transformations. + * Represents two functions - from datetime (UInt32) and from date (UInt16). + * + * Also, the "factor transformation" F is defined for the T transformation. + * This is a transformation of F such that its value identifies the region of monotonicity for T + * (for a fixed value of F, the transformation T is monotonic). + * + * Or, figuratively, if T is similar to taking the remainder of division, then F is similar to division. + * + * Example: for transformation T "get the day number in the month" (2015-02-03 -> 3), + * factor-transformation F is "round to the nearest month" (2015-02-03 -> 2015-02-01). + */ + +static inline UInt32 dateIsNotSupported(const char * name) +{ + throw Exception("Illegal type Date of argument for function " + std::string(name), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); +} + +/// This factor transformation will say that the function is monotone everywhere. +struct ZeroTransform +{ + static inline UInt16 execute(UInt32, const DateLUTImpl &) { return 0; } + static inline UInt16 execute(UInt16, const DateLUTImpl &) { return 0; } +}; + +struct ToDateImpl +{ + static constexpr auto name = "toDate"; + + static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return UInt16(time_zone.toDayNum(t)); + } + static inline UInt16 execute(UInt16 d, const DateLUTImpl &) + { + return d; + } + + using FactorTransform = ZeroTransform; +}; + +struct ToStartOfDayImpl +{ + static constexpr auto name = "toStartOfDay"; + + static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toDate(t); + } + static inline UInt32 execute(UInt16, const DateLUTImpl &) + { + return dateIsNotSupported(name); + } + + using FactorTransform = ZeroTransform; +}; + +struct ToMondayImpl +{ + static constexpr auto name = "toMonday"; + + static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toFirstDayNumOfWeek(time_zone.toDayNum(t)); + } + static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.toFirstDayNumOfWeek(DayNum(d)); + } + + using FactorTransform = ZeroTransform; +}; + +struct ToStartOfMonthImpl +{ + static constexpr auto name = "toStartOfMonth"; + + static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toFirstDayNumOfMonth(time_zone.toDayNum(t)); + } + static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.toFirstDayNumOfMonth(DayNum(d)); + } + + using FactorTransform = ZeroTransform; +}; + +struct ToStartOfQuarterImpl +{ + static constexpr auto name = "toStartOfQuarter"; + + static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toFirstDayNumOfQuarter(time_zone.toDayNum(t)); + } + static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.toFirstDayNumOfQuarter(DayNum(d)); + } + + using FactorTransform = ZeroTransform; +}; + +struct ToStartOfYearImpl +{ + static constexpr auto name = "toStartOfYear"; + + static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toFirstDayNumOfYear(time_zone.toDayNum(t)); + } + static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.toFirstDayNumOfYear(DayNum(d)); + } + + using FactorTransform = ZeroTransform; +}; + + +struct ToTimeImpl +{ + static constexpr auto name = "toTime"; + + /// When transforming to time, the date will be equated to 1970-01-02. + static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toTime(t) + 86400; + } + + static inline UInt32 execute(UInt16, const DateLUTImpl &) + { + return dateIsNotSupported(name); + } + + using FactorTransform = ToDateImpl; +}; + +struct ToStartOfMinuteImpl +{ + static constexpr auto name = "toStartOfMinute"; + + static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toStartOfMinute(t); + } + static inline UInt32 execute(UInt16, const DateLUTImpl &) + { + return dateIsNotSupported(name); + } + + using FactorTransform = ZeroTransform; +}; + +struct ToStartOfFiveMinuteImpl +{ + static constexpr auto name = "toStartOfFiveMinute"; + + static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toStartOfFiveMinute(t); + } + static inline UInt32 execute(UInt16, const DateLUTImpl &) + { + return dateIsNotSupported(name); + } + + using FactorTransform = ZeroTransform; +}; + +struct ToStartOfFifteenMinutesImpl +{ + static constexpr auto name = "toStartOfFifteenMinutes"; + + static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toStartOfFifteenMinutes(t); + } + static inline UInt32 execute(UInt16, const DateLUTImpl &) + { + return dateIsNotSupported(name); + } + + using FactorTransform = ZeroTransform; +}; + +/// Round to start of half-an-hour length interval with unspecified offset. This transform is specific for Yandex.Metrica. +struct TimeSlotImpl +{ + static constexpr auto name = "timeSlot"; + + static inline UInt32 execute(UInt32 t, const DateLUTImpl &) + { + return t / 1800 * 1800; + } + + static inline UInt32 execute(UInt16, const DateLUTImpl &) + { + return dateIsNotSupported(name); + } + + using FactorTransform = ZeroTransform; +}; + +struct ToStartOfHourImpl +{ + static constexpr auto name = "toStartOfHour"; + + static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toStartOfHour(t); + } + + static inline UInt32 execute(UInt16, const DateLUTImpl &) + { + return dateIsNotSupported(name); + } + + using FactorTransform = ZeroTransform; +}; + +struct ToYearImpl +{ + static constexpr auto name = "toYear"; + + static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toYear(t); + } + static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.toYear(DayNum(d)); + } + + using FactorTransform = ZeroTransform; +}; + +struct ToQuarterImpl +{ + static constexpr auto name = "toQuarter"; + + static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toQuarter(t); + } + static inline UInt8 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.toQuarter(DayNum(d)); + } + + using FactorTransform = ToStartOfYearImpl; +}; + +struct ToMonthImpl +{ + static constexpr auto name = "toMonth"; + + static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toMonth(t); + } + static inline UInt8 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.toMonth(DayNum(d)); + } + + using FactorTransform = ToStartOfYearImpl; +}; + +struct ToDayOfMonthImpl +{ + static constexpr auto name = "toDayOfMonth"; + + static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toDayOfMonth(t); + } + static inline UInt8 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.toDayOfMonth(DayNum(d)); + } + + using FactorTransform = ToStartOfMonthImpl; +}; + +struct ToDayOfWeekImpl +{ + static constexpr auto name = "toDayOfWeek"; + + static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toDayOfWeek(t); + } + static inline UInt8 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.toDayOfWeek(DayNum(d)); + } + + using FactorTransform = ToMondayImpl; +}; + +struct ToDayOfYearImpl +{ + static constexpr auto name = "toDayOfYear"; + + static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toDayOfYear(t); + } + static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.toDayOfYear(DayNum(d)); + } + + using FactorTransform = ToStartOfYearImpl; +}; + +struct ToHourImpl +{ + static constexpr auto name = "toHour"; + + static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toHour(t); + } + + static inline UInt8 execute(UInt16, const DateLUTImpl &) + { + return dateIsNotSupported(name); + } + + using FactorTransform = ToDateImpl; +}; + +struct ToMinuteImpl +{ + static constexpr auto name = "toMinute"; + + static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toMinute(t); + } + static inline UInt8 execute(UInt16, const DateLUTImpl &) + { + return dateIsNotSupported(name); + } + + using FactorTransform = ToStartOfHourImpl; +}; + +struct ToSecondImpl +{ + static constexpr auto name = "toSecond"; + + static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toSecond(t); + } + static inline UInt8 execute(UInt16, const DateLUTImpl &) + { + return dateIsNotSupported(name); + } + + using FactorTransform = ToStartOfMinuteImpl; +}; + +struct ToISOYearImpl +{ + static constexpr auto name = "toISOYear"; + + static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toISOYear(time_zone.toDayNum(t)); + } + static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.toISOYear(DayNum(d)); + } + + using FactorTransform = ZeroTransform; +}; + +struct ToStartOfISOYearImpl +{ + static constexpr auto name = "toStartOfISOYear"; + + static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toFirstDayNumOfISOYear(time_zone.toDayNum(t)); + } + static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.toFirstDayNumOfISOYear(DayNum(d)); + } + + using FactorTransform = ZeroTransform; +}; + +struct ToISOWeekImpl +{ + static constexpr auto name = "toISOWeek"; + + static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toISOWeek(time_zone.toDayNum(t)); + } + static inline UInt8 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.toISOWeek(DayNum(d)); + } + + using FactorTransform = ToISOYearImpl; +}; + +struct ToRelativeYearNumImpl +{ + static constexpr auto name = "toRelativeYearNum"; + + static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toYear(t); + } + static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.toYear(DayNum(d)); + } + + using FactorTransform = ZeroTransform; +}; + +struct ToRelativeQuarterNumImpl +{ + static constexpr auto name = "toRelativeQuarterNum"; + + static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toRelativeQuarterNum(t); + } + static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.toRelativeQuarterNum(DayNum(d)); + } + + using FactorTransform = ZeroTransform; +}; + +struct ToRelativeMonthNumImpl +{ + static constexpr auto name = "toRelativeMonthNum"; + + static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toRelativeMonthNum(t); + } + static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.toRelativeMonthNum(DayNum(d)); + } + + using FactorTransform = ZeroTransform; +}; + +struct ToRelativeWeekNumImpl +{ + static constexpr auto name = "toRelativeWeekNum"; + + static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toRelativeWeekNum(t); + } + static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.toRelativeWeekNum(DayNum(d)); + } + + using FactorTransform = ZeroTransform; +}; + +struct ToRelativeDayNumImpl +{ + static constexpr auto name = "toRelativeDayNum"; + + static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toDayNum(t); + } + static inline UInt16 execute(UInt16 d, const DateLUTImpl &) + { + return static_cast(d); + } + + using FactorTransform = ZeroTransform; +}; + + +struct ToRelativeHourNumImpl +{ + static constexpr auto name = "toRelativeHourNum"; + + static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toRelativeHourNum(t); + } + static inline UInt32 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.toRelativeHourNum(DayNum(d)); + } + + using FactorTransform = ZeroTransform; +}; + +struct ToRelativeMinuteNumImpl +{ + static constexpr auto name = "toRelativeMinuteNum"; + + static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toRelativeMinuteNum(t); + } + static inline UInt32 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.toRelativeMinuteNum(DayNum(d)); + } + + using FactorTransform = ZeroTransform; +}; + +struct ToRelativeSecondNumImpl +{ + static constexpr auto name = "toRelativeSecondNum"; + + static inline UInt32 execute(UInt32 t, const DateLUTImpl &) + { + return t; + } + static inline UInt32 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.fromDayNum(DayNum(d)); + } + + using FactorTransform = ZeroTransform; +}; + +struct ToYYYYMMImpl +{ + static constexpr auto name = "toYYYYMM"; + + static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toNumYYYYMM(t); + } + static inline UInt32 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.toNumYYYYMM(static_cast(d)); + } + + using FactorTransform = ZeroTransform; +}; + +struct ToYYYYMMDDImpl +{ + static constexpr auto name = "toYYYYMMDD"; + + static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toNumYYYYMMDD(t); + } + static inline UInt32 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.toNumYYYYMMDD(static_cast(d)); + } + + using FactorTransform = ZeroTransform; +}; + +struct ToYYYYMMDDhhmmssImpl +{ + static constexpr auto name = "toYYYYMMDDhhmmss"; + + static inline UInt64 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toNumYYYYMMDDhhmmss(t); + } + static inline UInt64 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.toNumYYYYMMDDhhmmss(time_zone.toDate(static_cast(d))); + } + + using FactorTransform = ZeroTransform; +}; + + +template +struct Transformer +{ + static void vector(const PaddedPODArray & vec_from, PaddedPODArray & vec_to, const DateLUTImpl & time_zone) + { + size_t size = vec_from.size(); + vec_to.resize(size); + + for (size_t i = 0; i < size; ++i) + vec_to[i] = Transform::execute(vec_from[i], time_zone); + } +}; + + +template +struct DateTimeTransformImpl +{ + static void execute(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/) + { + using Op = Transformer; + + const DateLUTImpl & time_zone = extractTimeZoneFromFunctionArguments(block, arguments, 1, 0); + + const ColumnPtr source_col = block.getByPosition(arguments[0]).column; + if (const auto * sources = checkAndGetColumn>(source_col.get())) + { + auto col_to = ColumnVector::create(); + Op::vector(sources->getData(), col_to->getData(), time_zone); + block.getByPosition(result).column = std::move(col_to); + } + else + { + throw Exception("Illegal column " + block.getByPosition(arguments[0]).column->getName() + + " of first argument of function " + Transform::name, + ErrorCodes::ILLEGAL_COLUMN); + } + } +}; + +} diff --git a/dbms/src/Functions/FunctionDateOrDateTimeAddInterval.h b/dbms/src/Functions/FunctionDateOrDateTimeAddInterval.h new file mode 100644 index 00000000000..c4b7639908f --- /dev/null +++ b/dbms/src/Functions/FunctionDateOrDateTimeAddInterval.h @@ -0,0 +1,308 @@ +#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; +} + + +struct AddSecondsImpl +{ + static constexpr auto name = "addSeconds"; + + static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl &) + { + return t + delta; + } + + static inline UInt32 execute(UInt16 d, Int64 delta, const DateLUTImpl & time_zone) + { + return time_zone.fromDayNum(DayNum(d)) + delta; + } +}; + +struct AddMinutesImpl +{ + static constexpr auto name = "addMinutes"; + + static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl &) + { + return t + delta * 60; + } + + static inline UInt32 execute(UInt16 d, Int64 delta, const DateLUTImpl & time_zone) + { + return time_zone.fromDayNum(DayNum(d)) + delta * 60; + } +}; + +struct AddHoursImpl +{ + static constexpr auto name = "addHours"; + + static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl &) + { + return t + delta * 3600; + } + + static inline UInt32 execute(UInt16 d, Int64 delta, const DateLUTImpl & time_zone) + { + return time_zone.fromDayNum(DayNum(d)) + delta * 3600; + } +}; + +struct AddDaysImpl +{ + static constexpr auto name = "addDays"; + + static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl & time_zone) + { + return time_zone.addDays(t, delta); + } + + static inline UInt16 execute(UInt16 d, Int64 delta, const DateLUTImpl &) + { + return d + delta; + } +}; + +struct AddWeeksImpl +{ + static constexpr auto name = "addWeeks"; + + static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl & time_zone) + { + return time_zone.addWeeks(t, delta); + } + + static inline UInt16 execute(UInt16 d, Int64 delta, const DateLUTImpl &) + { + return d + delta * 7; + } +}; + +struct AddMonthsImpl +{ + static constexpr auto name = "addMonths"; + + static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl & time_zone) + { + return time_zone.addMonths(t, delta); + } + + static inline UInt16 execute(UInt16 d, Int64 delta, const DateLUTImpl & time_zone) + { + return time_zone.addMonths(DayNum(d), delta); + } +}; + +struct AddYearsImpl +{ + static constexpr auto name = "addYears"; + + static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl & time_zone) + { + return time_zone.addYears(t, delta); + } + + static inline UInt16 execute(UInt16 d, Int64 delta, const DateLUTImpl & time_zone) + { + return time_zone.addYears(DayNum(d), delta); + } +}; + + +template +struct SubtractIntervalImpl +{ + static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl & time_zone) + { + return Transform::execute(t, -delta, time_zone); + } + + static inline UInt16 execute(UInt16 d, Int64 delta, const DateLUTImpl & time_zone) + { + return Transform::execute(d, -delta, time_zone); + } +}; + +struct SubtractSecondsImpl : SubtractIntervalImpl { static constexpr auto name = "subtractSeconds"; }; +struct SubtractMinutesImpl : SubtractIntervalImpl { static constexpr auto name = "subtractMinutes"; }; +struct SubtractHoursImpl : SubtractIntervalImpl { static constexpr auto name = "subtractHours"; }; +struct SubtractDaysImpl : SubtractIntervalImpl { static constexpr auto name = "subtractDays"; }; +struct SubtractWeeksImpl : SubtractIntervalImpl { static constexpr auto name = "subtractWeeks"; }; +struct SubtractMonthsImpl : SubtractIntervalImpl { static constexpr auto name = "subtractMonths"; }; +struct SubtractYearsImpl : SubtractIntervalImpl { static constexpr auto name = "subtractYears"; }; + + +template +struct Adder +{ + static void vector_vector(const PaddedPODArray & vec_from, PaddedPODArray & vec_to, const IColumn & delta, const DateLUTImpl & time_zone) + { + size_t size = vec_from.size(); + vec_to.resize(size); + + for (size_t i = 0; i < size; ++i) + vec_to[i] = Transform::execute(vec_from[i], delta.getInt(i), time_zone); + } + + static void vector_constant(const PaddedPODArray & vec_from, PaddedPODArray & vec_to, Int64 delta, const DateLUTImpl & time_zone) + { + size_t size = vec_from.size(); + vec_to.resize(size); + + for (size_t i = 0; i < size; ++i) + vec_to[i] = Transform::execute(vec_from[i], delta, time_zone); + } + + static void constant_vector(const FromType & from, PaddedPODArray & vec_to, const IColumn & delta, const DateLUTImpl & time_zone) + { + size_t size = delta.size(); + vec_to.resize(size); + + for (size_t i = 0; i < size; ++i) + vec_to[i] = Transform::execute(from, delta.getInt(i), time_zone); + } +}; + + +template +struct DateTimeAddIntervalImpl +{ + static void execute(Block & block, const ColumnNumbers & arguments, size_t result) + { + using ToType = decltype(Transform::execute(FromType(), 0, std::declval())); + using Op = Adder; + + const DateLUTImpl & time_zone = extractTimeZoneFromFunctionArguments(block, arguments, 2, 0); + + const ColumnPtr source_col = block.getByPosition(arguments[0]).column; + + if (const auto * sources = checkAndGetColumn>(source_col.get())) + { + auto col_to = ColumnVector::create(); + + const IColumn & delta_column = *block.getByPosition(arguments[1]).column; + + if (const auto * delta_const_column = typeid_cast(&delta_column)) + Op::vector_constant(sources->getData(), col_to->getData(), delta_const_column->getField().get(), time_zone); + else + Op::vector_vector(sources->getData(), col_to->getData(), delta_column, time_zone); + + block.getByPosition(result).column = std::move(col_to); + } + else if (const auto * sources = checkAndGetColumnConst>(source_col.get())) + { + auto col_to = ColumnVector::create(); + Op::constant_vector(sources->template getValue(), col_to->getData(), *block.getByPosition(arguments[1]).column, time_zone); + block.getByPosition(result).column = std::move(col_to); + } + else + { + throw Exception("Illegal column " + block.getByPosition(arguments[0]).column->getName() + + " of first argument of function " + Transform::name, + ErrorCodes::ILLEGAL_COLUMN); + } + } +}; + + +template +class FunctionDateOrDateTimeAddInterval : public IFunction +{ +public: + static constexpr auto name = Transform::name; + static FunctionPtr create(const Context &) { return std::make_shared(); } + + String getName() const override + { + return name; + } + + 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("Number of arguments for function " + getName() + " doesn't match: passed " + + toString(arguments.size()) + ", should be 2 or 3", + ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); + + if (!isNumber(arguments[1].type)) + throw Exception("Second argument for function " + getName() + " (delta) must be number", + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + + if (arguments.size() == 2) + { + if (!isDateOrDateTime(arguments[0].type)) + throw Exception{"Illegal type " + arguments[0].type->getName() + " of argument of function " + getName() + + ". Should be a date or a date with time", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; + } + else + { + if (!WhichDataType(arguments[0].type).isDateTime() + || !WhichDataType(arguments[2].type).isString()) + throw Exception( + "Function " + getName() + " supports 2 or 3 arguments. The 1st argument " + "must be of type Date or DateTime. The 2nd argument must be number. " + "The 3rd argument (optional) must be " + "a constant string with timezone name. The timezone argument is allowed " + "only when the 1st argument has the type DateTime", + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + } + + if (WhichDataType(arguments[0].type).isDate()) + { + if (std::is_same_v())), UInt16>) + return std::make_shared(); + else + return std::make_shared(extractTimeZoneNameFromFunctionArguments(arguments, 2, 0)); + } + else + { + if (std::is_same_v())), UInt16>) + return std::make_shared(); + else + return std::make_shared(extractTimeZoneNameFromFunctionArguments(arguments, 2, 0)); + } + } + + bool useDefaultImplementationForConstants() const override { return true; } + ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {2}; } + + void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/) override + { + const IDataType * from_type = block.getByPosition(arguments[0]).type.get(); + WhichDataType which(from_type); + + if (which.isDate()) + DateTimeAddIntervalImpl::execute(block, arguments, result); + else if (which.isDateTime()) + DateTimeAddIntervalImpl::execute(block, arguments, result); + else + throw Exception("Illegal type " + block.getByPosition(arguments[0]).type->getName() + " of argument of function " + getName(), + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + } +}; + +} + diff --git a/dbms/src/Functions/FunctionDateOrDateTimeToSomething.h b/dbms/src/Functions/FunctionDateOrDateTimeToSomething.h new file mode 100644 index 00000000000..b5345f197ee --- /dev/null +++ b/dbms/src/Functions/FunctionDateOrDateTimeToSomething.h @@ -0,0 +1,125 @@ +#include +#include + +#include +#include + +#include + + +namespace DB +{ + +namespace ErrorCodes +{ + extern const int ILLEGAL_TYPE_OF_ARGUMENT; + extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; +} + + +/// See DateTimeTransforms.h +template +class FunctionDateOrDateTimeToSomething : public IFunction +{ +public: + static constexpr auto name = Transform::name; + static FunctionPtr create(const Context &) { return std::make_shared(); } + + String getName() const override + { + return name; + } + + bool isVariadic() const override { return true; } + size_t getNumberOfArguments() const override { return 0; } + + DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override + { + if (arguments.size() == 1) + { + if (!isDateOrDateTime(arguments[0].type)) + throw Exception("Illegal type " + arguments[0].type->getName() + " of argument of function " + getName() + + ". Should be a date or a date with time", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + } + else if (arguments.size() == 2) + { + if (!WhichDataType(arguments[0].type).isDateTime() + || !WhichDataType(arguments[1].type).isString()) + throw Exception( + "Function " + getName() + " supports 1 or 2 arguments. The 1st argument " + "must be of type Date or DateTime. The 2nd argument (optional) must be " + "a constant string with timezone name. The timezone argument is allowed " + "only when the 1st argument has the type DateTime", + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + } + else + throw Exception("Number of arguments for function " + getName() + " doesn't match: passed " + + toString(arguments.size()) + ", should be 1 or 2", + ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); + + /// For DateTime, if time zone is specified, attach it to type. + if (std::is_same_v) + return std::make_shared(extractTimeZoneNameFromFunctionArguments(arguments, 1, 0)); + else + return std::make_shared(); + } + + bool useDefaultImplementationForConstants() const override { return true; } + ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1}; } + + void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override + { + const IDataType * from_type = block.getByPosition(arguments[0]).type.get(); + WhichDataType which(from_type); + + if (which.isDate()) + DateTimeTransformImpl::execute(block, arguments, result, input_rows_count); + else if (which.isDateTime()) + DateTimeTransformImpl::execute(block, arguments, result, input_rows_count); + else + throw Exception("Illegal type " + block.getByPosition(arguments[0]).type->getName() + " of argument of function " + getName(), + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + } + + + bool hasInformationAboutMonotonicity() const override + { + return true; + } + + Monotonicity getMonotonicityForRange(const IDataType & type, const Field & left, const Field & right) const override + { + IFunction::Monotonicity is_monotonic { true }; + IFunction::Monotonicity is_not_monotonic; + + if (std::is_same_v) + { + is_monotonic.is_always_monotonic = true; + return is_monotonic; + } + + /// This method is called only if the function has one argument. Therefore, we do not care about the non-local time zone. + const DateLUTImpl & date_lut = DateLUT::instance(); + + if (left.isNull() || right.isNull()) + return is_not_monotonic; + + /// The function is monotonous on the [left, right] segment, if the factor transformation returns the same values for them. + + if (checkAndGetDataType(&type)) + { + return Transform::FactorTransform::execute(UInt16(left.get()), date_lut) + == Transform::FactorTransform::execute(UInt16(right.get()), date_lut) + ? is_monotonic : is_not_monotonic; + } + else + { + return Transform::FactorTransform::execute(UInt32(left.get()), date_lut) + == Transform::FactorTransform::execute(UInt32(right.get()), date_lut) + ? is_monotonic : is_not_monotonic; + } + } +}; + +} + diff --git a/dbms/src/Functions/FunctionsConversion.h b/dbms/src/Functions/FunctionsConversion.h index 283da2a99e7..c7e5843212c 100644 --- a/dbms/src/Functions/FunctionsConversion.h +++ b/dbms/src/Functions/FunctionsConversion.h @@ -35,8 +35,8 @@ #include #include #include -#include #include +#include #include #include diff --git a/dbms/src/Functions/addDays.cpp b/dbms/src/Functions/addDays.cpp new file mode 100644 index 00000000000..84849974494 --- /dev/null +++ b/dbms/src/Functions/addDays.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + + +namespace DB +{ + +using FunctionAddDays = FunctionDateOrDateTimeAddInterval; + +void registerFunctionAddDays(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/addHours.cpp b/dbms/src/Functions/addHours.cpp new file mode 100644 index 00000000000..0ed644c89d7 --- /dev/null +++ b/dbms/src/Functions/addHours.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + + +namespace DB +{ + +using FunctionAddHours = FunctionDateOrDateTimeAddInterval; + +void registerFunctionAddHours(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/addMinutes.cpp b/dbms/src/Functions/addMinutes.cpp new file mode 100644 index 00000000000..ba7b78f1a98 --- /dev/null +++ b/dbms/src/Functions/addMinutes.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + + +namespace DB +{ + +using FunctionAddMinutes = FunctionDateOrDateTimeAddInterval; + +void registerFunctionAddMinutes(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/addMonths.cpp b/dbms/src/Functions/addMonths.cpp new file mode 100644 index 00000000000..0f8d97081d2 --- /dev/null +++ b/dbms/src/Functions/addMonths.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + + +namespace DB +{ + +using FunctionAddMonths = FunctionDateOrDateTimeAddInterval; + +void registerFunctionAddMonths(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/addSeconds.cpp b/dbms/src/Functions/addSeconds.cpp new file mode 100644 index 00000000000..1602d01de85 --- /dev/null +++ b/dbms/src/Functions/addSeconds.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + + +namespace DB +{ + +using FunctionAddSeconds = FunctionDateOrDateTimeAddInterval; + +void registerFunctionAddSeconds(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/addWeeks.cpp b/dbms/src/Functions/addWeeks.cpp new file mode 100644 index 00000000000..b87c40bd813 --- /dev/null +++ b/dbms/src/Functions/addWeeks.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + + +namespace DB +{ + +using FunctionAddWeeks = FunctionDateOrDateTimeAddInterval; + +void registerFunctionAddWeeks(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/addYears.cpp b/dbms/src/Functions/addYears.cpp new file mode 100644 index 00000000000..044860abb22 --- /dev/null +++ b/dbms/src/Functions/addYears.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + + +namespace DB +{ + +using FunctionAddYears = FunctionDateOrDateTimeAddInterval; + +void registerFunctionAddYears(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/dateDiff.cpp b/dbms/src/Functions/dateDiff.cpp new file mode 100644 index 00000000000..859896ad863 --- /dev/null +++ b/dbms/src/Functions/dateDiff.cpp @@ -0,0 +1,220 @@ +#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; +} + +/** dateDiff('unit', t1, t2, [timezone]) + * t1 and t2 can be Date or DateTime + * + * If timezone is specified, it applied to both arguments. + * If not, timezones from datatypes t1 and t2 are used. + * If that timezones are not the same, the result is unspecified. + * + * Timezone matters because days can have different length. + */ +class FunctionDateDiff : public IFunction +{ +public: + static constexpr auto name = "dateDiff"; + static FunctionPtr create(const Context &) { return std::make_shared(); } + + String getName() const override + { + return name; + } + + bool isVariadic() const override { return true; } + size_t getNumberOfArguments() const override { return 0; } + + DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override + { + if (arguments.size() != 3 && arguments.size() != 4) + throw Exception("Number of arguments for function " + getName() + " doesn't match: passed " + + toString(arguments.size()) + ", should be 3 or 4", + ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); + + if (!isString(arguments[0])) + throw Exception("First argument for function " + getName() + " (unit) must be String", + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + + if (!isDateOrDateTime(arguments[1])) + throw Exception("Second argument for function " + getName() + " must be Date or DateTime", + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + + if (!isDateOrDateTime(arguments[2])) + throw Exception("Third argument for function " + getName() + " must be Date or DateTime", + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + + if (arguments.size() == 4 && !isString(arguments[3])) + throw Exception("Fourth argument for function " + getName() + " (timezone) must be String", + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + + return std::make_shared(); + } + + bool useDefaultImplementationForConstants() const override { return true; } + ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {0, 3}; } + + void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override + { + auto * unit_column = checkAndGetColumnConst(block.getByPosition(arguments[0]).column.get()); + if (!unit_column) + throw Exception("First argument for function " + getName() + " must be constant String", ErrorCodes::ILLEGAL_COLUMN); + + String unit = Poco::toLower(unit_column->getValue()); + + const IColumn & x = *block.getByPosition(arguments[1]).column; + const IColumn & y = *block.getByPosition(arguments[2]).column; + + size_t rows = input_rows_count; + auto res = ColumnInt64::create(rows); + + const DateLUTImpl & timezone_x = extractTimeZoneFromFunctionArguments(block, arguments, 3, 1); + const DateLUTImpl & timezone_y = extractTimeZoneFromFunctionArguments(block, arguments, 3, 2); + + if (unit == "year" || unit == "yy" || unit == "yyyy") + dispatchForColumns(x, y, timezone_x, timezone_y, res->getData()); + else if (unit == "quarter" || unit == "qq" || unit == "q") + dispatchForColumns(x, y, timezone_x, timezone_y, res->getData()); + else if (unit == "month" || unit == "mm" || unit == "m") + dispatchForColumns(x, y, timezone_x, timezone_y, res->getData()); + else if (unit == "week" || unit == "wk" || unit == "ww") + dispatchForColumns(x, y, timezone_x, timezone_y, res->getData()); + else if (unit == "day" || unit == "dd" || unit == "d") + dispatchForColumns(x, y, timezone_x, timezone_y, res->getData()); + else if (unit == "hour" || unit == "hh") + dispatchForColumns(x, y, timezone_x, timezone_y, res->getData()); + else if (unit == "minute" || unit == "mi" || unit == "n") + dispatchForColumns(x, y, timezone_x, timezone_y, res->getData()); + else if (unit == "second" || unit == "ss" || unit == "s") + dispatchForColumns(x, y, timezone_x, timezone_y, res->getData()); + else + throw Exception("Function " + getName() + " does not support '" + unit + "' unit", ErrorCodes::BAD_ARGUMENTS); + + block.getByPosition(result).column = std::move(res); + } + +private: + template + void dispatchForColumns( + const IColumn & x, const IColumn & y, + const DateLUTImpl & timezone_x, const DateLUTImpl & timezone_y, + ColumnInt64::Container & result) + { + if (auto * x_vec = checkAndGetColumn(&x)) + dispatchForSecondColumn(*x_vec, y, timezone_x, timezone_y, result); + else if (auto * x_vec = checkAndGetColumn(&x)) + dispatchForSecondColumn(*x_vec, y, timezone_x, timezone_y, result); + else if (auto * x_const = checkAndGetColumnConst(&x)) + dispatchConstForSecondColumn(x_const->getValue(), y, timezone_x, timezone_y, result); + else if (auto * x_const = checkAndGetColumnConst(&x)) + dispatchConstForSecondColumn(x_const->getValue(), y, timezone_x, timezone_y, result); + else + throw Exception("Illegal column for first argument of function " + getName() + ", must be Date or DateTime", ErrorCodes::ILLEGAL_COLUMN); + } + + template + void dispatchForSecondColumn( + const ColumnVector & x, const IColumn & y, + const DateLUTImpl & timezone_x, const DateLUTImpl & timezone_y, + ColumnInt64::Container & result) + { + if (auto * y_vec = checkAndGetColumn(&y)) + vector_vector(x, *y_vec, timezone_x, timezone_y, result); + else if (auto * y_vec = checkAndGetColumn(&y)) + vector_vector(x, *y_vec, timezone_x, timezone_y, result); + else if (auto * y_const = checkAndGetColumnConst(&y)) + vector_constant(x, y_const->getValue(), timezone_x, timezone_y, result); + else if (auto * y_const = checkAndGetColumnConst(&y)) + vector_constant(x, y_const->getValue(), timezone_x, timezone_y, result); + else + throw Exception("Illegal column for second argument of function " + getName() + ", must be Date or DateTime", ErrorCodes::ILLEGAL_COLUMN); + } + + template + void dispatchConstForSecondColumn( + T1 x, const IColumn & y, + const DateLUTImpl & timezone_x, const DateLUTImpl & timezone_y, + ColumnInt64::Container & result) + { + if (auto * y_vec = checkAndGetColumn(&y)) + constant_vector(x, *y_vec, timezone_x, timezone_y, result); + else if (auto * y_vec = checkAndGetColumn(&y)) + constant_vector(x, *y_vec, timezone_x, timezone_y, result); + else + throw Exception("Illegal column for second argument of function " + getName() + ", must be Date or DateTime", ErrorCodes::ILLEGAL_COLUMN); + } + + template + void vector_vector( + const ColumnVector & x, const ColumnVector & y, + const DateLUTImpl & timezone_x, const DateLUTImpl & timezone_y, + ColumnInt64::Container & result) + { + const auto & x_data = x.getData(); + const auto & y_data = y.getData(); + for (size_t i = 0, size = x.size(); i < size; ++i) + result[i] = calculate(x_data[i], y_data[i], timezone_x, timezone_y); + } + + template + void vector_constant( + const ColumnVector & x, T2 y, + const DateLUTImpl & timezone_x, const DateLUTImpl & timezone_y, + ColumnInt64::Container & result) + { + const auto & x_data = x.getData(); + for (size_t i = 0, size = x.size(); i < size; ++i) + result[i] = calculate(x_data[i], y, timezone_x, timezone_y); + } + + template + void constant_vector( + T1 x, const ColumnVector & y, + const DateLUTImpl & timezone_x, const DateLUTImpl & timezone_y, + ColumnInt64::Container & result) + { + const auto & y_data = y.getData(); + for (size_t i = 0, size = y.size(); i < size; ++i) + result[i] = calculate(x, y_data[i], timezone_x, timezone_y); + } + + template + Int64 calculate(T1 x, T2 y, const DateLUTImpl & timezone_x, const DateLUTImpl & timezone_y) + { + return Int64(Transform::execute(y, timezone_y)) + - Int64(Transform::execute(x, timezone_x)); + } +}; + +void registerFunctionDateDiff(FunctionFactory & factory) +{ + factory.registerFunction(FunctionFactory::CaseInsensitive); +} + +} + diff --git a/dbms/src/Functions/extractTimeZoneFromFunctionArguments.cpp b/dbms/src/Functions/extractTimeZoneFromFunctionArguments.cpp new file mode 100644 index 00000000000..4190cfe797f --- /dev/null +++ b/dbms/src/Functions/extractTimeZoneFromFunctionArguments.cpp @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include +#include + + +namespace DB +{ + +namespace ErrorCodes +{ + extern const int ILLEGAL_COLUMN; +} + + +static std::string extractTimeZoneNameFromColumn(const IColumn & column) +{ + const ColumnConst * time_zone_column = checkAndGetColumnConst(&column); + + if (!time_zone_column) + throw Exception("Illegal column " + column.getName() + + " of time zone argument of function, must be constant string", + ErrorCodes::ILLEGAL_COLUMN); + + return time_zone_column->getValue(); +} + + +std::string extractTimeZoneNameFromFunctionArguments(const ColumnsWithTypeAndName & arguments, size_t time_zone_arg_num, size_t datetime_arg_num) +{ + /// Explicit time zone may be passed in last argument. + if (arguments.size() == time_zone_arg_num + 1 && arguments[time_zone_arg_num].column) + { + return extractTimeZoneNameFromColumn(*arguments[time_zone_arg_num].column); + } + else + { + if (!arguments.size()) + return {}; + + /// If time zone is attached to an argument of type DateTime. + if (const DataTypeDateTime * type = checkAndGetDataType(arguments[datetime_arg_num].type.get())) + return type->getTimeZone().getTimeZone(); + + return {}; + } +} + +const DateLUTImpl & extractTimeZoneFromFunctionArguments(Block & block, const ColumnNumbers & arguments, size_t time_zone_arg_num, size_t datetime_arg_num) +{ + if (arguments.size() == time_zone_arg_num + 1) + return DateLUT::instance(extractTimeZoneNameFromColumn(*block.getByPosition(arguments[time_zone_arg_num]).column)); + else + { + if (!arguments.size()) + return DateLUT::instance(); + + /// If time zone is attached to an argument of type DateTime. + if (const DataTypeDateTime * type = checkAndGetDataType(block.getByPosition(arguments[datetime_arg_num]).type.get())) + return type->getTimeZone(); + + return DateLUT::instance(); + } +} + +} + diff --git a/dbms/src/Functions/extractTimeZoneFromFunctionArguments.h b/dbms/src/Functions/extractTimeZoneFromFunctionArguments.h new file mode 100644 index 00000000000..7c90feb7da2 --- /dev/null +++ b/dbms/src/Functions/extractTimeZoneFromFunctionArguments.h @@ -0,0 +1,17 @@ +#include +#include +#include + + +class DateLUTImpl; + +namespace DB +{ + +class Block; + +/// Determine working timezone either from optional argument with time zone name or from time zone in DateTime type of argument. +std::string extractTimeZoneNameFromFunctionArguments(const ColumnsWithTypeAndName & arguments, size_t time_zone_arg_num, size_t datetime_arg_num); +const DateLUTImpl & extractTimeZoneFromFunctionArguments(Block & block, const ColumnNumbers & arguments, size_t time_zone_arg_num, size_t datetime_arg_num); + +} diff --git a/dbms/src/Functions/formatDateTime.cpp b/dbms/src/Functions/formatDateTime.cpp new file mode 100644 index 00000000000..874cfcfcd5e --- /dev/null +++ b/dbms/src/Functions/formatDateTime.cpp @@ -0,0 +1,571 @@ +#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 NOT_IMPLEMENTED; + extern const int ILLEGAL_COLUMN; + extern const int BAD_ARGUMENTS; +} + + +/** formatDateTime(time, 'pattern') + * Performs formatting of time, according to provided pattern. + * + * This function is optimized with an assumption, that the resulting strings are fixed width. + * (This assumption is fulfilled for currently supported formatting options). + * + * It is implemented in two steps. + * At first step, it creates a pattern of zeros, literal characters, whitespaces, etc. + * and quickly fills resulting charater array (string column) with this pattern. + * At second step, it walks across the resulting character array and modifies/replaces specific charaters, + * by calling some functions by pointers and shifting cursor by specified amount. + * + * Advantages: + * - memcpy is mostly unrolled; + * - low number of arithmetic ops due to pre-filled pattern; + * - for somewhat reason, function by pointer call is faster than switch/case. + * + * Possible further optimization options: + * - slightly interleave first and second step for better cache locality + * (but it has no sense when character array fits in L1d cache); + * - avoid indirect function calls and inline functions with JIT compilation. + * + * Performance on Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz: + * + * WITH formatDateTime(now() + number, '%H:%M:%S') AS x SELECT count() FROM system.numbers WHERE NOT ignore(x); + * - 97 million rows per second per core; + * + * WITH formatDateTime(toDateTime('2018-01-01 00:00:00') + number, '%F %T') AS x SELECT count() FROM system.numbers WHERE NOT ignore(x) + * - 71 million rows per second per core; + * + * select count() from (select formatDateTime(t, '%m/%d/%Y %H:%M:%S') from (select toDateTime('2018-01-01 00:00:00')+number as t from numbers(100000000))); + * - 53 million rows per second per core; + * + * select count() from (select formatDateTime(t, 'Hello %Y World') from (select toDateTime('2018-01-01 00:00:00')+number as t from numbers(100000000))); + * - 138 million rows per second per core; + * + * PS. We can make this function to return FixedString. Currently it returns String. + */ +class FunctionFormatDateTime : public IFunction +{ +private: + /// Time is either UInt32 for DateTime or UInt16 for Date. + template + class Action + { + public: + using Func = void (*)(char *, Time, const DateLUTImpl &); + + Func func; + size_t shift; + + Action(Func func, size_t shift = 0) : func(func), shift(shift) {} + + void perform(char *& target, Time source, const DateLUTImpl & timezone) + { + func(target, source, timezone); + target += shift; + } + + private: + template + static inline void writeNumber2(char * p, T v) + { + static const char digits[201] = + "00010203040506070809" + "10111213141516171819" + "20212223242526272829" + "30313233343536373839" + "40414243444546474849" + "50515253545556575859" + "60616263646566676869" + "70717273747576777879" + "80818283848586878889" + "90919293949596979899"; + + memcpy(p, &digits[v * 2], 2); + } + + template + static inline void writeNumber3(char * p, T v) + { + writeNumber2(p, v / 10); + p[2] += v % 10; + } + + template + static inline void writeNumber4(char * p, T v) + { + writeNumber2(p, v / 100); + writeNumber2(p + 2, v % 100); + } + + public: + static void noop(char *, Time, const DateLUTImpl &) + { + } + + static void century(char * target, Time source, const DateLUTImpl & timezone) + { + auto year = ToYearImpl::execute(source, timezone); + auto century = year / 100; + writeNumber2(target, century); + } + + static void dayOfMonth(char * target, Time source, const DateLUTImpl & timezone) + { + writeNumber2(target, ToDayOfMonthImpl::execute(source, timezone)); + } + + static void americanDate(char * target, Time source, const DateLUTImpl & timezone) + { + writeNumber2(target, ToMonthImpl::execute(source, timezone)); + writeNumber2(target + 3, ToDayOfMonthImpl::execute(source, timezone)); + writeNumber2(target + 6, ToYearImpl::execute(source, timezone) % 100); + } + + static void dayOfMonthSpacePadded(char * target, Time source, const DateLUTImpl & timezone) + { + auto day = ToDayOfMonthImpl::execute(source, timezone); + if (day < 10) + target[1] += day; + else + writeNumber2(target, day); + } + + static void ISO8601Date(char * target, Time source, const DateLUTImpl & timezone) + { + writeNumber4(target, ToYearImpl::execute(source, timezone)); + writeNumber2(target + 5, ToMonthImpl::execute(source, timezone)); + writeNumber2(target + 8, ToDayOfMonthImpl::execute(source, timezone)); + } + + static void dayOfYear(char * target, Time source, const DateLUTImpl & timezone) + { + writeNumber3(target, ToDayOfYearImpl::execute(source, timezone)); + } + + static void month(char * target, Time source, const DateLUTImpl & timezone) + { + writeNumber2(target, ToMonthImpl::execute(source, timezone)); + } + + static void dayOfWeek(char * target, Time source, const DateLUTImpl & timezone) + { + *target += ToDayOfWeekImpl::execute(source, timezone); + } + + static void dayOfWeek0To6(char * target, Time source, const DateLUTImpl & timezone) + { + auto day = ToDayOfWeekImpl::execute(source, timezone); + *target += (day == 7 ? 0 : day); + } + + static void ISO8601Week(char * target, Time source, const DateLUTImpl & timezone) + { + writeNumber2(target, ToISOWeekImpl::execute(source, timezone)); + } + + static void year2(char * target, Time source, const DateLUTImpl & timezone) + { + writeNumber2(target, ToYearImpl::execute(source, timezone) % 100); + } + + static void year4(char * target, Time source, const DateLUTImpl & timezone) + { + writeNumber4(target, ToYearImpl::execute(source, timezone)); + } + + static void hour24(char * target, Time source, const DateLUTImpl & timezone) + { + writeNumber2(target, ToHourImpl::execute(source, timezone)); + } + + static void hour12(char * target, Time source, const DateLUTImpl & timezone) + { + auto x = ToHourImpl::execute(source, timezone); + writeNumber2(target, x == 0 ? 12 : (x > 12 ? x - 12 : x)); + } + + static void minute(char * target, Time source, const DateLUTImpl & timezone) + { + writeNumber2(target, ToMinuteImpl::execute(source, timezone)); + } + + static void AMPM(char * target, Time source, const DateLUTImpl & timezone) + { + auto hour = ToHourImpl::execute(source, timezone); + if (hour >= 12) + *target = 'P'; + } + + static void hhmm24(char * target, Time source, const DateLUTImpl & timezone) + { + writeNumber2(target, ToHourImpl::execute(source, timezone)); + writeNumber2(target + 3, ToMinuteImpl::execute(source, timezone)); + } + + static void second(char * target, Time source, const DateLUTImpl & timezone) + { + writeNumber2(target, ToSecondImpl::execute(source, timezone)); + } + + static void ISO8601Time(char * target, Time source, const DateLUTImpl & timezone) + { + writeNumber2(target, ToHourImpl::execute(source, timezone)); + writeNumber2(target + 3, ToMinuteImpl::execute(source, timezone)); + writeNumber2(target + 6, ToSecondImpl::execute(source, timezone)); + } + }; + +public: + static constexpr auto name = "formatDateTime"; + + static FunctionPtr create(const Context &) { return std::make_shared(); } + + String getName() const override + { + return name; + } + + bool useDefaultImplementationForConstants() const override { return true; } + + ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1, 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("Number of arguments for function " + getName() + " doesn't match: passed " + + toString(arguments.size()) + ", should be 2 or 3", + ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); + + if (!WhichDataType(arguments[0].type).isDateOrDateTime()) + throw Exception("Illegal type " + arguments[0].type->getName() + " of 1 argument of function " + getName() + + ". Should be a date or a date with time", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + + if (!WhichDataType(arguments[1].type).isString()) + throw Exception("Illegal type " + arguments[1].type->getName() + " of 2 argument of function " + getName() + ". Must be String.", + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + + if (arguments.size() == 3) + { + if (!WhichDataType(arguments[2].type).isString()) + throw Exception("Illegal type " + arguments[2].type->getName() + " of 3 argument of function " + getName() + ". Must be String.", + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + } + + return std::make_shared(); + } + + void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/) override + { + if (!executeType(block, arguments, result) + && !executeType(block, arguments, result)) + throw Exception("Illegal column " + block.getByPosition(arguments[0]).column->getName() + + " of function " + getName() + ", must be Date or DateTime", + ErrorCodes::ILLEGAL_COLUMN); + } + + template + bool executeType(Block & block, const ColumnNumbers & arguments, size_t result) + { + if (auto * times = checkAndGetColumn>(block.getByPosition(arguments[0]).column.get())) + { + const ColumnConst * pattern_column = checkAndGetColumnConst(block.getByPosition(arguments[1]).column.get()); + + if (!pattern_column) + throw Exception("Illegal column " + block.getByPosition(arguments[1]).column->getName() + + " of second ('format') argument of function " + getName() + + ". Must be constant string.", + ErrorCodes::ILLEGAL_COLUMN); + + String pattern = pattern_column->getValue(); + + std::vector> instructions; + String pattern_to_fill = parsePattern(pattern, instructions); + size_t result_size = pattern_to_fill.size(); + + const DateLUTImpl * time_zone_tmp = nullptr; + if (arguments.size() == 3) + time_zone_tmp = &extractTimeZoneFromFunctionArguments(block, arguments, 2, 0); + else + time_zone_tmp = &DateLUT::instance(); + + const DateLUTImpl & time_zone = *time_zone_tmp; + + const typename ColumnVector::Container & vec = times->getData(); + + auto col_res = ColumnString::create(); + auto & dst_data = col_res->getChars(); + auto & dst_offsets = col_res->getOffsets(); + dst_data.resize(vec.size() * (result_size + 1)); + dst_offsets.resize(vec.size()); + + /// Fill result with literals. + { + UInt8 * begin = dst_data.data(); + UInt8 * end = begin + dst_data.size(); + UInt8 * pos = begin; + + if (pos < end) + { + memcpy(pos, pattern_to_fill.data(), result_size + 1); /// With zero terminator. + pos += result_size + 1; + } + + /// Fill by copying exponential growing ranges. + while (pos < end) + { + size_t bytes_to_copy = std::min(pos - begin, end - pos); + memcpy(pos, begin, bytes_to_copy); + pos += bytes_to_copy; + } + } + + auto begin = reinterpret_cast(dst_data.data()); + auto pos = begin; + + for (size_t i = 0; i < vec.size(); ++i) + { + for(auto & instruction : instructions) + instruction.perform(pos, vec[i], time_zone); + + dst_offsets[i] = pos - begin; + } + + dst_data.resize(pos - begin); + block.getByPosition(result).column = std::move(col_res); + return true; + } + + return false; + } + + template + String parsePattern(const String & pattern, std::vector> & instructions) const + { + String result; + + const char * pos = pattern.data(); + const char * end = pos + pattern.size(); + + /// Add shift to previous action; or if there were none, add noop action with shift. + auto addShift = [&](size_t amount) + { + if (instructions.empty()) + instructions.emplace_back(&Action::noop); + instructions.back().shift += amount; + }; + + /// If the argument was DateTime, add instruction for printing. If it was date, just shift (the buffer is pre-filled with default values). + auto addInstructionOrShift = [&](typename Action::Func func [[maybe_unused]], size_t shift) + { + if constexpr (std::is_same_v) + instructions.emplace_back(func, shift); + else + addShift(shift); + }; + + while (true) + { + const char * percent_pos = find_first_symbols<'%'>(pos, end); + + if (percent_pos < end) + { + if (pos < percent_pos) + { + result.append(pos, percent_pos); + addShift(percent_pos - pos); + } + + pos = percent_pos + 1; + + if (pos >= end) + throw Exception("Sign '%' is the last in pattern, if you need it, use '%%'", ErrorCodes::BAD_ARGUMENTS); + + switch (*pos) + { + // Year, divided by 100, zero-padded + case 'C': + instructions.emplace_back(&Action::century, 2); + result.append("00"); + break; + + // Day of month, zero-padded (01-31) + case 'd': + instructions.emplace_back(&Action::dayOfMonth, 2); + result.append("00"); + break; + + // Short MM/DD/YY date, equivalent to %m/%d/%y + case 'D': + instructions.emplace_back(&Action::americanDate, 8); + result.append("00/00/00"); + break; + + // Day of month, space-padded ( 1-31) 23 + case 'e': + instructions.emplace_back(&Action::dayOfMonthSpacePadded, 2); + result.append(" 0"); + break; + + // Short YYYY-MM-DD date, equivalent to %Y-%m-%d 2001-08-23 + case 'F': + instructions.emplace_back(&Action::ISO8601Date, 10); + result.append("0000-00-00"); + break; + + // Day of the year (001-366) 235 + case 'j': + instructions.emplace_back(&Action::dayOfYear, 3); + result.append("000"); + break; + + // Month as a decimal number (01-12) + case 'm': + instructions.emplace_back(&Action::month, 2); + result.append("00"); + break; + + // ISO 8601 weekday as number with Monday as 1 (1-7) + case 'u': + instructions.emplace_back(&Action::dayOfWeek, 1); + result.append("0"); + break; + + // ISO 8601 week number (01-53) + case 'V': + instructions.emplace_back(&Action::ISO8601Week, 2); + result.append("00"); + break; + + // Weekday as a decimal number with Sunday as 0 (0-6) 4 + case 'w': + instructions.emplace_back(&Action::dayOfWeek0To6, 1); + result.append("0"); + break; + + // Two digits year + case 'y': + instructions.emplace_back(&Action::year2, 2); + result.append("00"); + break; + + // Four digits year + case 'Y': + instructions.emplace_back(&Action::year4, 4); + result.append("0000"); + break; + + /// Time components. If the argument is Date, not a DateTime, then this components will have default value. + + // Minute (00-59) + case 'M': + addInstructionOrShift(&Action::minute, 2); + result.append("00"); + break; + + // AM or PM + case 'p': + addInstructionOrShift(&Action::AMPM, 2); + result.append("AM"); + break; + + // 24-hour HH:MM time, equivalent to %H:%M 14:55 + case 'R': + addInstructionOrShift(&Action::hhmm24, 5); + result.append("00:00"); + break; + + // Seconds + case 'S': + addInstructionOrShift(&Action::second, 2); + result.append("00"); + break; + + // ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S 14:55:02 + case 'T': + addInstructionOrShift(&Action::ISO8601Time, 8); + result.append("00:00:00"); + break; + + // Hour in 24h format (00-23) + case 'H': + addInstructionOrShift(&Action::hour24, 2); + result.append("00"); + break; + + // Hour in 12h format (01-12) + case 'I': + addInstructionOrShift(&Action::hour12, 2); + result.append("12"); + break; + + /// Escaped literal characters. + case '%': + result += '%'; + addShift(1); + break; + case 't': + result += '\t'; + addShift(1); + break; + case 'n': + result += '\n'; + addShift(1); + break; + + // Unimplemented + case 'U': [[fallthrough]]; + case 'W': + throw Exception("Wrong pattern '" + pattern + "', symbol '" + *pos + " is not implemented ' for function " + getName(), + ErrorCodes::NOT_IMPLEMENTED); + + default: + throw Exception( + "Wrong pattern '" + pattern + "', unexpected symbol '" + *pos + "' for function " + getName(), ErrorCodes::ILLEGAL_COLUMN); + } + + ++pos; + } + else + { + result.append(pos, end); + addShift(end + 1 - pos); /// including zero terminator + break; + } + } + + return result; + } +}; + +void registerFunctionFormatDateTime(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} diff --git a/dbms/src/Functions/now.cpp b/dbms/src/Functions/now.cpp new file mode 100644 index 00000000000..59501d96088 --- /dev/null +++ b/dbms/src/Functions/now.cpp @@ -0,0 +1,44 @@ +#include + +#include +#include + + +namespace DB +{ + +/// Get the current time. (It is a constant, it is evaluated once for the entire query.) +class FunctionNow : public IFunction +{ +public: + static constexpr auto name = "now"; + static FunctionPtr create(const Context &) { return std::make_shared(); } + + String getName() const override + { + return name; + } + + size_t getNumberOfArguments() const override { return 0; } + + DataTypePtr getReturnTypeImpl(const DataTypes & /*arguments*/) const override + { + return std::make_shared(); + } + + bool isDeterministic() const override { return false; } + + void executeImpl(Block & block, const ColumnNumbers &, size_t result, size_t input_rows_count) override + { + block.getByPosition(result).column = DataTypeDateTime().createColumnConst( + input_rows_count, + static_cast(time(nullptr))); + } +}; + +void registerFunctionNow(FunctionFactory & factory) +{ + factory.registerFunction(FunctionFactory::CaseInsensitive); +} + +} diff --git a/dbms/src/Functions/subtractDays.cpp b/dbms/src/Functions/subtractDays.cpp new file mode 100644 index 00000000000..21966a15311 --- /dev/null +++ b/dbms/src/Functions/subtractDays.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + + +namespace DB +{ + +using FunctionSubtractDays = FunctionDateOrDateTimeAddInterval; + +void registerFunctionSubtractDays(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/subtractHours.cpp b/dbms/src/Functions/subtractHours.cpp new file mode 100644 index 00000000000..e71c9d74a01 --- /dev/null +++ b/dbms/src/Functions/subtractHours.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + + +namespace DB +{ + +using FunctionSubtractHours = FunctionDateOrDateTimeAddInterval; + +void registerFunctionSubtractHours(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/subtractMinutes.cpp b/dbms/src/Functions/subtractMinutes.cpp new file mode 100644 index 00000000000..ba9d593a64d --- /dev/null +++ b/dbms/src/Functions/subtractMinutes.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + + +namespace DB +{ + +using FunctionSubtractMinutes = FunctionDateOrDateTimeAddInterval; + +void registerFunctionSubtractMinutes(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/subtractMonths.cpp b/dbms/src/Functions/subtractMonths.cpp new file mode 100644 index 00000000000..64eeba2ce86 --- /dev/null +++ b/dbms/src/Functions/subtractMonths.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + + +namespace DB +{ + +using FunctionSubtractMonths = FunctionDateOrDateTimeAddInterval; + +void registerFunctionSubtractMonths(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/subtractSeconds.cpp b/dbms/src/Functions/subtractSeconds.cpp new file mode 100644 index 00000000000..81a7f7e2df1 --- /dev/null +++ b/dbms/src/Functions/subtractSeconds.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + + +namespace DB +{ + +using FunctionSubtractSeconds = FunctionDateOrDateTimeAddInterval; + +void registerFunctionSubtractSeconds(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/subtractWeeks.cpp b/dbms/src/Functions/subtractWeeks.cpp new file mode 100644 index 00000000000..55b52043dd0 --- /dev/null +++ b/dbms/src/Functions/subtractWeeks.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + + +namespace DB +{ + +using FunctionSubtractWeeks = FunctionDateOrDateTimeAddInterval; + +void registerFunctionSubtractWeeks(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/subtractYears.cpp b/dbms/src/Functions/subtractYears.cpp new file mode 100644 index 00000000000..241142722d5 --- /dev/null +++ b/dbms/src/Functions/subtractYears.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + + +namespace DB +{ + +using FunctionSubtractYears = FunctionDateOrDateTimeAddInterval; + +void registerFunctionSubtractYears(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/timeSlot.cpp b/dbms/src/Functions/timeSlot.cpp new file mode 100644 index 00000000000..f9763997b92 --- /dev/null +++ b/dbms/src/Functions/timeSlot.cpp @@ -0,0 +1,21 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionTimeSlot = FunctionDateOrDateTimeToSomething; + +void registerFunctionTimeSlot(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + + diff --git a/dbms/src/Functions/timeSlots.cpp b/dbms/src/Functions/timeSlots.cpp new file mode 100644 index 00000000000..16ade60cb50 --- /dev/null +++ b/dbms/src/Functions/timeSlots.cpp @@ -0,0 +1,182 @@ +#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; +} + +/** timeSlots(StartTime, Duration) + * - for the time interval beginning at `StartTime` and continuing `Duration` seconds, + * returns an array of time points, consisting of rounding down to half an hour of points from this interval. + * For example, timeSlots(toDateTime('2012-01-01 12:20:00'), 600) = [toDateTime('2012-01-01 12:00:00'), toDateTime('2012-01-01 12:30:00')]. + * This is necessary to search for hits that are part of the corresponding visit. + * + * This is obsolete function. It was developed for Yandex.Metrica, but no longer used. + */ + +template +struct TimeSlotsImpl +{ + static constexpr UInt32 TIME_SLOT_SIZE = 1800; + + static void vector_vector( + const PaddedPODArray & starts, const PaddedPODArray & durations, + PaddedPODArray & result_values, ColumnArray::Offsets & result_offsets) + { + size_t size = starts.size(); + + result_offsets.resize(size); + result_values.reserve(size); + + ColumnArray::Offset current_offset = 0; + for (size_t i = 0; i < size; ++i) + { + for (UInt32 value = starts[i] / TIME_SLOT_SIZE; value <= (starts[i] + durations[i]) / TIME_SLOT_SIZE; ++value) + { + result_values.push_back(value * TIME_SLOT_SIZE); + ++current_offset; + } + + result_offsets[i] = current_offset; + } + } + + static void vector_constant( + const PaddedPODArray & starts, DurationType duration, + PaddedPODArray & result_values, ColumnArray::Offsets & result_offsets) + { + size_t size = starts.size(); + + result_offsets.resize(size); + result_values.reserve(size); + + ColumnArray::Offset current_offset = 0; + for (size_t i = 0; i < size; ++i) + { + for (UInt32 value = starts[i] / TIME_SLOT_SIZE; value <= (starts[i] + duration) / TIME_SLOT_SIZE; ++value) + { + result_values.push_back(value * TIME_SLOT_SIZE); + ++current_offset; + } + + result_offsets[i] = current_offset; + } + } + + static void constant_vector( + UInt32 start, const PaddedPODArray & durations, + PaddedPODArray & result_values, ColumnArray::Offsets & result_offsets) + { + size_t size = durations.size(); + + result_offsets.resize(size); + result_values.reserve(size); + + ColumnArray::Offset current_offset = 0; + for (size_t i = 0; i < size; ++i) + { + for (UInt32 value = start / TIME_SLOT_SIZE; value <= (start + durations[i]) / TIME_SLOT_SIZE; ++value) + { + result_values.push_back(value * TIME_SLOT_SIZE); + ++current_offset; + } + + result_offsets[i] = current_offset; + } + } + + static void constant_constant( + UInt32 start, DurationType duration, + Array & result) + { + for (UInt32 value = start / TIME_SLOT_SIZE; value <= (start + duration) / TIME_SLOT_SIZE; ++value) + result.push_back(static_cast(value * TIME_SLOT_SIZE)); + } +}; + + +class FunctionTimeSlots : public IFunction +{ +public: + static constexpr auto name = "timeSlots"; + static FunctionPtr create(const Context &) { return std::make_shared(); } + + String getName() const override + { + return name; + } + + size_t getNumberOfArguments() const override { return 2; } + + DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override + { + if (!WhichDataType(arguments[0]).isDateTime()) + throw Exception("Illegal type " + arguments[0]->getName() + " of first argument of function " + getName() + ". Must be DateTime.", + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + + if (!WhichDataType(arguments[1]).isUInt32()) + throw Exception("Illegal type " + arguments[1]->getName() + " of second argument of function " + getName() + ". Must be UInt32.", + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + + return std::make_shared(std::make_shared()); + } + + void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override + { + auto starts = checkAndGetColumn(block.getByPosition(arguments[0]).column.get()); + auto const_starts = checkAndGetColumnConst(block.getByPosition(arguments[0]).column.get()); + + auto durations = checkAndGetColumn(block.getByPosition(arguments[1]).column.get()); + auto const_durations = checkAndGetColumnConst(block.getByPosition(arguments[1]).column.get()); + + auto res = ColumnArray::create(ColumnUInt32::create()); + ColumnUInt32::Container & res_values = typeid_cast(res->getData()).getData(); + + if (starts && durations) + { + TimeSlotsImpl::vector_vector(starts->getData(), durations->getData(), res_values, res->getOffsets()); + block.getByPosition(result).column = std::move(res); + } + else if (starts && const_durations) + { + TimeSlotsImpl::vector_constant(starts->getData(), const_durations->getValue(), res_values, res->getOffsets()); + block.getByPosition(result).column = std::move(res); + } + else if (const_starts && durations) + { + TimeSlotsImpl::constant_vector(const_starts->getValue(), durations->getData(), res_values, res->getOffsets()); + block.getByPosition(result).column = std::move(res); + } + else if (const_starts && const_durations) + { + Array const_res; + TimeSlotsImpl::constant_constant(const_starts->getValue(), const_durations->getValue(), const_res); + block.getByPosition(result).column = block.getByPosition(result).type->createColumnConst(input_rows_count, const_res); + } + else + throw Exception("Illegal columns " + block.getByPosition(arguments[0]).column->getName() + + ", " + block.getByPosition(arguments[1]).column->getName() + + " of arguments of function " + getName(), + ErrorCodes::ILLEGAL_COLUMN); + } +}; + +void registerFunctionTimeSlots(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} diff --git a/dbms/src/Functions/toDayOfMonth.cpp b/dbms/src/Functions/toDayOfMonth.cpp new file mode 100644 index 00000000000..5bd9cf42ff4 --- /dev/null +++ b/dbms/src/Functions/toDayOfMonth.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToDayOfMonth = FunctionDateOrDateTimeToSomething; + +void registerFunctionToDayOfMonth(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toDayOfWeek.cpp b/dbms/src/Functions/toDayOfWeek.cpp new file mode 100644 index 00000000000..34c0311d695 --- /dev/null +++ b/dbms/src/Functions/toDayOfWeek.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToDayOfWeek = FunctionDateOrDateTimeToSomething; + +void registerFunctionToDayOfWeek(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toDayOfYear.cpp b/dbms/src/Functions/toDayOfYear.cpp new file mode 100644 index 00000000000..d20cd28110f --- /dev/null +++ b/dbms/src/Functions/toDayOfYear.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToDayOfYear = FunctionDateOrDateTimeToSomething; + +void registerFunctionToDayOfYear(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toHour.cpp b/dbms/src/Functions/toHour.cpp new file mode 100644 index 00000000000..c056c95a222 --- /dev/null +++ b/dbms/src/Functions/toHour.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToHour = FunctionDateOrDateTimeToSomething; + +void registerFunctionToHour(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toISOWeek.cpp b/dbms/src/Functions/toISOWeek.cpp new file mode 100644 index 00000000000..451bd7e11eb --- /dev/null +++ b/dbms/src/Functions/toISOWeek.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToISOWeek = FunctionDateOrDateTimeToSomething; + +void registerFunctionToISOWeek(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toISOYear.cpp b/dbms/src/Functions/toISOYear.cpp new file mode 100644 index 00000000000..320994d20bd --- /dev/null +++ b/dbms/src/Functions/toISOYear.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToISOYear = FunctionDateOrDateTimeToSomething; + +void registerFunctionToISOYear(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toMinute.cpp b/dbms/src/Functions/toMinute.cpp new file mode 100644 index 00000000000..ab0c9792913 --- /dev/null +++ b/dbms/src/Functions/toMinute.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToMinute = FunctionDateOrDateTimeToSomething; + +void registerFunctionToMinute(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toMonday.cpp b/dbms/src/Functions/toMonday.cpp new file mode 100644 index 00000000000..579e760721c --- /dev/null +++ b/dbms/src/Functions/toMonday.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToMonday = FunctionDateOrDateTimeToSomething; + +void registerFunctionToMonday(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toMonth.cpp b/dbms/src/Functions/toMonth.cpp new file mode 100644 index 00000000000..d14b6f68cd0 --- /dev/null +++ b/dbms/src/Functions/toMonth.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToMonth = FunctionDateOrDateTimeToSomething; + +void registerFunctionToMonth(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toQuarter.cpp b/dbms/src/Functions/toQuarter.cpp new file mode 100644 index 00000000000..7f1c3d830f2 --- /dev/null +++ b/dbms/src/Functions/toQuarter.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToQuarter = FunctionDateOrDateTimeToSomething; + +void registerFunctionToQuarter(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toRelativeDayNum.cpp b/dbms/src/Functions/toRelativeDayNum.cpp new file mode 100644 index 00000000000..51410b1fbc9 --- /dev/null +++ b/dbms/src/Functions/toRelativeDayNum.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToRelativeDayNum = FunctionDateOrDateTimeToSomething; + +void registerFunctionToRelativeDayNum(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toRelativeHourNum.cpp b/dbms/src/Functions/toRelativeHourNum.cpp new file mode 100644 index 00000000000..f560f965137 --- /dev/null +++ b/dbms/src/Functions/toRelativeHourNum.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToRelativeHourNum = FunctionDateOrDateTimeToSomething; + +void registerFunctionToRelativeHourNum(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toRelativeMinuteNum.cpp b/dbms/src/Functions/toRelativeMinuteNum.cpp new file mode 100644 index 00000000000..8b787e3ca59 --- /dev/null +++ b/dbms/src/Functions/toRelativeMinuteNum.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToRelativeMinuteNum = FunctionDateOrDateTimeToSomething; + +void registerFunctionToRelativeMinuteNum(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toRelativeMonthNum.cpp b/dbms/src/Functions/toRelativeMonthNum.cpp new file mode 100644 index 00000000000..ea0f186642b --- /dev/null +++ b/dbms/src/Functions/toRelativeMonthNum.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToRelativeMonthNum = FunctionDateOrDateTimeToSomething; + +void registerFunctionToRelativeMonthNum(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toRelativeQuarterNum.cpp b/dbms/src/Functions/toRelativeQuarterNum.cpp new file mode 100644 index 00000000000..45b536c8c68 --- /dev/null +++ b/dbms/src/Functions/toRelativeQuarterNum.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToRelativeQuarterNum = FunctionDateOrDateTimeToSomething; + +void registerFunctionToRelativeQuarterNum(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toRelativeSecondNum.cpp b/dbms/src/Functions/toRelativeSecondNum.cpp new file mode 100644 index 00000000000..78aa6254eb0 --- /dev/null +++ b/dbms/src/Functions/toRelativeSecondNum.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToRelativeSecondNum = FunctionDateOrDateTimeToSomething; + +void registerFunctionToRelativeSecondNum(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toRelativeWeekNum.cpp b/dbms/src/Functions/toRelativeWeekNum.cpp new file mode 100644 index 00000000000..441ad50f5c6 --- /dev/null +++ b/dbms/src/Functions/toRelativeWeekNum.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToRelativeWeekNum = FunctionDateOrDateTimeToSomething; + +void registerFunctionToRelativeWeekNum(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toRelativeYearNum.cpp b/dbms/src/Functions/toRelativeYearNum.cpp new file mode 100644 index 00000000000..abe81a7b634 --- /dev/null +++ b/dbms/src/Functions/toRelativeYearNum.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToRelativeYearNum = FunctionDateOrDateTimeToSomething; + +void registerFunctionToRelativeYearNum(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toSecond.cpp b/dbms/src/Functions/toSecond.cpp new file mode 100644 index 00000000000..e0bdcecdefb --- /dev/null +++ b/dbms/src/Functions/toSecond.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToSecond = FunctionDateOrDateTimeToSomething; + +void registerFunctionToSecond(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toStartOfDay.cpp b/dbms/src/Functions/toStartOfDay.cpp new file mode 100644 index 00000000000..873c768de0e --- /dev/null +++ b/dbms/src/Functions/toStartOfDay.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToStartOfDay = FunctionDateOrDateTimeToSomething; + +void registerFunctionToStartOfDay(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toStartOfFifteenMinutes.cpp b/dbms/src/Functions/toStartOfFifteenMinutes.cpp new file mode 100644 index 00000000000..1ad52ad3ca2 --- /dev/null +++ b/dbms/src/Functions/toStartOfFifteenMinutes.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToStartOfFifteenMinutes = FunctionDateOrDateTimeToSomething; + +void registerFunctionToStartOfFifteenMinutes(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toStartOfFiveMinute.cpp b/dbms/src/Functions/toStartOfFiveMinute.cpp new file mode 100644 index 00000000000..758581ea409 --- /dev/null +++ b/dbms/src/Functions/toStartOfFiveMinute.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToStartOfFiveMinute = FunctionDateOrDateTimeToSomething; + +void registerFunctionToStartOfFiveMinute(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toStartOfHour.cpp b/dbms/src/Functions/toStartOfHour.cpp new file mode 100644 index 00000000000..e074ac3cd74 --- /dev/null +++ b/dbms/src/Functions/toStartOfHour.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToStartOfHour = FunctionDateOrDateTimeToSomething; + +void registerFunctionToStartOfHour(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toStartOfISOYear.cpp b/dbms/src/Functions/toStartOfISOYear.cpp new file mode 100644 index 00000000000..3288460e810 --- /dev/null +++ b/dbms/src/Functions/toStartOfISOYear.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToStartOfISOYear = FunctionDateOrDateTimeToSomething; + +void registerFunctionToStartOfISOYear(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toStartOfMinute.cpp b/dbms/src/Functions/toStartOfMinute.cpp new file mode 100644 index 00000000000..60b75371303 --- /dev/null +++ b/dbms/src/Functions/toStartOfMinute.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToStartOfMinute = FunctionDateOrDateTimeToSomething; + +void registerFunctionToStartOfMinute(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toStartOfMonth.cpp b/dbms/src/Functions/toStartOfMonth.cpp new file mode 100644 index 00000000000..1250b2ecf24 --- /dev/null +++ b/dbms/src/Functions/toStartOfMonth.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToStartOfMonth = FunctionDateOrDateTimeToSomething; + +void registerFunctionToStartOfMonth(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toStartOfQuarter.cpp b/dbms/src/Functions/toStartOfQuarter.cpp new file mode 100644 index 00000000000..e18f156d9ac --- /dev/null +++ b/dbms/src/Functions/toStartOfQuarter.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToStartOfQuarter = FunctionDateOrDateTimeToSomething; + +void registerFunctionToStartOfQuarter(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toStartOfYear.cpp b/dbms/src/Functions/toStartOfYear.cpp new file mode 100644 index 00000000000..48d26c705ee --- /dev/null +++ b/dbms/src/Functions/toStartOfYear.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToStartOfYear = FunctionDateOrDateTimeToSomething; + +void registerFunctionToStartOfYear(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toTime.cpp b/dbms/src/Functions/toTime.cpp new file mode 100644 index 00000000000..99cf1f29f02 --- /dev/null +++ b/dbms/src/Functions/toTime.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToTime = FunctionDateOrDateTimeToSomething; + +void registerFunctionToTime(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toTimeZone.cpp b/dbms/src/Functions/toTimeZone.cpp new file mode 100644 index 00000000000..d18b3d88e7b --- /dev/null +++ b/dbms/src/Functions/toTimeZone.cpp @@ -0,0 +1,59 @@ +#include + +#include +#include +#include + +#include + + +namespace DB +{ + +namespace ErrorCodes +{ + extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; + extern const int ILLEGAL_TYPE_OF_ARGUMENT; +} + +/// Just changes time zone information for data type. The calculation is free. +class FunctionToTimeZone : public IFunction +{ +public: + static constexpr auto name = "toTimeZone"; + static FunctionPtr create(const Context &) { return std::make_shared(); } + + String getName() const override + { + return name; + } + + size_t getNumberOfArguments() const override { return 2; } + + DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override + { + if (arguments.size() != 2) + throw Exception("Number of arguments for function " + getName() + " doesn't match: passed " + + toString(arguments.size()) + ", should be 2", + ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); + + if (!WhichDataType(arguments[0].type).isDateTime()) + throw Exception{"Illegal type " + arguments[0].type->getName() + " of argument of function " + getName() + + ". Should be DateTime", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; + + String time_zone_name = extractTimeZoneNameFromFunctionArguments(arguments, 1, 0); + return std::make_shared(time_zone_name); + } + + void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/) override + { + block.getByPosition(result).column = block.getByPosition(arguments[0]).column; + } +}; + +void registerFunctionToTimeZone(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} diff --git a/dbms/src/Functions/toYYYYMM.cpp b/dbms/src/Functions/toYYYYMM.cpp new file mode 100644 index 00000000000..bf02a54f48f --- /dev/null +++ b/dbms/src/Functions/toYYYYMM.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToYYYYMM = FunctionDateOrDateTimeToSomething; + +void registerFunctionToYYYYMM(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toYYYYMMDD.cpp b/dbms/src/Functions/toYYYYMMDD.cpp new file mode 100644 index 00000000000..973bc78c943 --- /dev/null +++ b/dbms/src/Functions/toYYYYMMDD.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToYYYYMMDD = FunctionDateOrDateTimeToSomething; + +void registerFunctionToYYYYMMDD(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toYYYYMMDDhhmmss.cpp b/dbms/src/Functions/toYYYYMMDDhhmmss.cpp new file mode 100644 index 00000000000..d85f0658b67 --- /dev/null +++ b/dbms/src/Functions/toYYYYMMDDhhmmss.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToYYYYMMDDhhmmss = FunctionDateOrDateTimeToSomething; + +void registerFunctionToYYYYMMDDhhmmss(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/toYear.cpp b/dbms/src/Functions/toYear.cpp new file mode 100644 index 00000000000..d0771a90dd5 --- /dev/null +++ b/dbms/src/Functions/toYear.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ + +using FunctionToYear = FunctionDateOrDateTimeToSomething; + +void registerFunctionToYear(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/today.cpp b/dbms/src/Functions/today.cpp new file mode 100644 index 00000000000..7a72f4d547f --- /dev/null +++ b/dbms/src/Functions/today.cpp @@ -0,0 +1,45 @@ +#include + +#include + +#include +#include + + +namespace DB +{ + +class FunctionToday : public IFunction +{ +public: + static constexpr auto name = "today"; + static FunctionPtr create(const Context &) { return std::make_shared(); } + + String getName() const override + { + return name; + } + + size_t getNumberOfArguments() const override { return 0; } + + DataTypePtr getReturnTypeImpl(const DataTypes & /*arguments*/) const override + { + return std::make_shared(); + } + + bool isDeterministic() const override { return false; } + + void executeImpl(Block & block, const ColumnNumbers &, size_t result, size_t input_rows_count) override + { + block.getByPosition(result).column = DataTypeDate().createColumnConst( + input_rows_count, + UInt64(DateLUT::instance().toDayNum(time(nullptr)))); + } +}; + +void registerFunctionToday(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} diff --git a/dbms/src/Functions/yesterday.cpp b/dbms/src/Functions/yesterday.cpp new file mode 100644 index 00000000000..506f84c863c --- /dev/null +++ b/dbms/src/Functions/yesterday.cpp @@ -0,0 +1,45 @@ +#include + +#include + +#include +#include + + +namespace DB +{ + +class FunctionYesterday : public IFunction +{ +public: + static constexpr auto name = "yesterday"; + static FunctionPtr create(const Context &) { return std::make_shared(); } + + String getName() const override + { + return name; + } + + size_t getNumberOfArguments() const override { return 0; } + + DataTypePtr getReturnTypeImpl(const DataTypes & /*arguments*/) const override + { + return std::make_shared(); + } + + bool isDeterministic() const override { return false; } + + void executeImpl(Block & block, const ColumnNumbers &, size_t result, size_t input_rows_count) override + { + block.getByPosition(result).column = DataTypeDate().createColumnConst( + input_rows_count, + UInt64(DateLUT::instance().toDayNum(time(nullptr)) - 1)); + } +}; + +void registerFunctionYesterday(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +}