ClickHouse
520 строк · 27.3 Кб
1#include <DataTypes/DataTypeDateTime.h>2#include <DataTypes/DataTypeDateTime64.h>3#include <DataTypes/DataTypesNumber.h>4#include <Common/IntervalKind.h>5#include <Columns/ColumnString.h>6#include <Columns/ColumnsDateTime.h>7#include <Columns/ColumnsNumber.h>8#include <Columns/ColumnDecimal.h>9#include <Formats/FormatSettings.h>10#include <Functions/IFunction.h>11#include <Functions/FunctionHelpers.h>12#include <Functions/FunctionFactory.h>13#include <Functions/extractTimeZoneFromFunctionArguments.h>14#include <Functions/DateTimeTransforms.h>15#include <Functions/TransformDateTime64.h>16
17#include <IO/WriteHelpers.h>18
19#include <base/find_symbols.h>20
21#include <type_traits>22
23
24namespace DB25{
26
27namespace ErrorCodes28{
29extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;30extern const int ILLEGAL_TYPE_OF_ARGUMENT;31extern const int ILLEGAL_COLUMN;32extern const int BAD_ARGUMENTS;33}
34
35namespace
36{
37
38template <bool is_diff>39class DateDiffImpl40{
41public:42using ColumnDateTime64 = ColumnDecimal<DateTime64>;43
44explicit DateDiffImpl(const String & name_) : name(name_) {}45
46template <typename Transform>47void dispatchForColumns(48const IColumn & x, const IColumn & y,49const DateLUTImpl & timezone_x, const DateLUTImpl & timezone_y,50ColumnInt64::Container & result) const51{52if (const auto * x_vec_16 = checkAndGetColumn<ColumnDate>(&x))53dispatchForSecondColumn<Transform>(*x_vec_16, y, timezone_x, timezone_y, result);54else if (const auto * x_vec_32 = checkAndGetColumn<ColumnDateTime>(&x))55dispatchForSecondColumn<Transform>(*x_vec_32, y, timezone_x, timezone_y, result);56else if (const auto * x_vec_32_s = checkAndGetColumn<ColumnDate32>(&x))57dispatchForSecondColumn<Transform>(*x_vec_32_s, y, timezone_x, timezone_y, result);58else if (const auto * x_vec_64 = checkAndGetColumn<ColumnDateTime64>(&x))59dispatchForSecondColumn<Transform>(*x_vec_64, y, timezone_x, timezone_y, result);60else if (const auto * x_const_16 = checkAndGetColumnConst<ColumnDate>(&x))61dispatchConstForSecondColumn<Transform>(x_const_16->getValue<UInt16>(), y, timezone_x, timezone_y, result);62else if (const auto * x_const_32 = checkAndGetColumnConst<ColumnDateTime>(&x))63dispatchConstForSecondColumn<Transform>(x_const_32->getValue<UInt32>(), y, timezone_x, timezone_y, result);64else if (const auto * x_const_32_s = checkAndGetColumnConst<ColumnDate32>(&x))65dispatchConstForSecondColumn<Transform>(x_const_32_s->getValue<Int32>(), y, timezone_x, timezone_y, result);66else if (const auto * x_const_64 = checkAndGetColumnConst<ColumnDateTime64>(&x))67dispatchConstForSecondColumn<Transform>(x_const_64->getValue<DecimalField<DateTime64>>(), y, timezone_x, timezone_y, result);68else69throw Exception(ErrorCodes::ILLEGAL_COLUMN,70"Illegal column for first argument of function {}, must be Date, Date32, DateTime or DateTime64",71name);72}73
74template <typename Transform, typename LeftColumnType>75void dispatchForSecondColumn(76const LeftColumnType & x, const IColumn & y,77const DateLUTImpl & timezone_x, const DateLUTImpl & timezone_y,78ColumnInt64::Container & result) const79{80if (const auto * y_vec_16 = checkAndGetColumn<ColumnDate>(&y))81vectorVector<Transform>(x, *y_vec_16, timezone_x, timezone_y, result);82else if (const auto * y_vec_32 = checkAndGetColumn<ColumnDateTime>(&y))83vectorVector<Transform>(x, *y_vec_32, timezone_x, timezone_y, result);84else if (const auto * y_vec_32_s = checkAndGetColumn<ColumnDate32>(&y))85vectorVector<Transform>(x, *y_vec_32_s, timezone_x, timezone_y, result);86else if (const auto * y_vec_64 = checkAndGetColumn<ColumnDateTime64>(&y))87vectorVector<Transform>(x, *y_vec_64, timezone_x, timezone_y, result);88else if (const auto * y_const_16 = checkAndGetColumnConst<ColumnDate>(&y))89vectorConstant<Transform>(x, y_const_16->getValue<UInt16>(), timezone_x, timezone_y, result);90else if (const auto * y_const_32 = checkAndGetColumnConst<ColumnDateTime>(&y))91vectorConstant<Transform>(x, y_const_32->getValue<UInt32>(), timezone_x, timezone_y, result);92else if (const auto * y_const_32_s = checkAndGetColumnConst<ColumnDate32>(&y))93vectorConstant<Transform>(x, y_const_32_s->getValue<Int32>(), timezone_x, timezone_y, result);94else if (const auto * y_const_64 = checkAndGetColumnConst<ColumnDateTime64>(&y))95vectorConstant<Transform>(x, y_const_64->getValue<DecimalField<DateTime64>>(), timezone_x, timezone_y, result);96else97throw Exception(ErrorCodes::ILLEGAL_COLUMN,98"Illegal column for second argument of function {}, must be Date, Date32, DateTime or DateTime64",99name);100}101
102template <typename Transform, typename T1>103void dispatchConstForSecondColumn(104T1 x, const IColumn & y,105const DateLUTImpl & timezone_x, const DateLUTImpl & timezone_y,106ColumnInt64::Container & result) const107{108if (const auto * y_vec_16 = checkAndGetColumn<ColumnDate>(&y))109constantVector<Transform>(x, *y_vec_16, timezone_x, timezone_y, result);110else if (const auto * y_vec_32 = checkAndGetColumn<ColumnDateTime>(&y))111constantVector<Transform>(x, *y_vec_32, timezone_x, timezone_y, result);112else if (const auto * y_vec_32_s = checkAndGetColumn<ColumnDate32>(&y))113constantVector<Transform>(x, *y_vec_32_s, timezone_x, timezone_y, result);114else if (const auto * y_vec_64 = checkAndGetColumn<ColumnDateTime64>(&y))115constantVector<Transform>(x, *y_vec_64, timezone_x, timezone_y, result);116else117throw Exception(ErrorCodes::ILLEGAL_COLUMN,118"Illegal column for second argument of function {}, must be Date, Date32, DateTime or DateTime64",119name);120}121
122template <typename Transform, typename LeftColumnType, typename RightColumnType>123void vectorVector(124const LeftColumnType & x, const RightColumnType & y,125const DateLUTImpl & timezone_x, const DateLUTImpl & timezone_y,126ColumnInt64::Container & result) const127{128const auto & x_data = x.getData();129const auto & y_data = y.getData();130
131const auto transform_x = TransformDateTime64<Transform>(getScale(x));132const auto transform_y = TransformDateTime64<Transform>(getScale(y));133for (size_t i = 0, size = x.size(); i < size; ++i)134result[i] = calculate(transform_x, transform_y, x_data[i], y_data[i], timezone_x, timezone_y);135}136
137template <typename Transform, typename LeftColumnType, typename T2>138void vectorConstant(139const LeftColumnType & x, T2 y,140const DateLUTImpl & timezone_x, const DateLUTImpl & timezone_y,141ColumnInt64::Container & result) const142{143const auto & x_data = x.getData();144const auto transform_x = TransformDateTime64<Transform>(getScale(x));145const auto transform_y = TransformDateTime64<Transform>(getScale(y));146const auto y_value = stripDecimalFieldValue(y);147
148for (size_t i = 0, size = x.size(); i < size; ++i)149result[i] = calculate(transform_x, transform_y, x_data[i], y_value, timezone_x, timezone_y);150}151
152template <typename Transform, typename T1, typename RightColumnType>153void constantVector(154T1 x, const RightColumnType & y,155const DateLUTImpl & timezone_x, const DateLUTImpl & timezone_y,156ColumnInt64::Container & result) const157{158const auto & y_data = y.getData();159const auto transform_x = TransformDateTime64<Transform>(getScale(x));160const auto transform_y = TransformDateTime64<Transform>(getScale(y));161const auto x_value = stripDecimalFieldValue(x);162
163for (size_t i = 0, size = y.size(); i < size; ++i)164result[i] = calculate(transform_x, transform_y, x_value, y_data[i], timezone_x, timezone_y);165}166
167template <typename TransformX, typename TransformY, typename T1, typename T2>168Int64 calculate(const TransformX & transform_x, const TransformY & transform_y, T1 x, T2 y, const DateLUTImpl & timezone_x, const DateLUTImpl & timezone_y) const169{170if constexpr (is_diff)171return static_cast<Int64>(transform_y.execute(y, timezone_y))172- static_cast<Int64>(transform_x.execute(x, timezone_x));173else174{175auto res = static_cast<Int64>(transform_y.execute(y, timezone_y))176- static_cast<Int64>(transform_x.execute(x, timezone_x));177DateTimeComponentsWithFractionalPart a_comp;178DateTimeComponentsWithFractionalPart b_comp;179Int64 adjust_value;180auto x_nanoseconds = TransformDateTime64<ToRelativeSubsecondNumImpl<nanosecond_multiplier>>(transform_x.getScaleMultiplier()).execute(x, timezone_x);181auto y_nanoseconds = TransformDateTime64<ToRelativeSubsecondNumImpl<nanosecond_multiplier>>(transform_y.getScaleMultiplier()).execute(y, timezone_y);182
183if (x_nanoseconds <= y_nanoseconds)184{185a_comp = TransformDateTime64<ToDateTimeComponentsImpl>(transform_x.getScaleMultiplier()).execute(x, timezone_x);186b_comp = TransformDateTime64<ToDateTimeComponentsImpl>(transform_y.getScaleMultiplier()).execute(y, timezone_y);187adjust_value = -1;188}189else190{191a_comp = TransformDateTime64<ToDateTimeComponentsImpl>(transform_y.getScaleMultiplier()).execute(y, timezone_y);192b_comp = TransformDateTime64<ToDateTimeComponentsImpl>(transform_x.getScaleMultiplier()).execute(x, timezone_x);193adjust_value = 1;194}195
196if constexpr (std::is_same_v<TransformX, TransformDateTime64<ToRelativeYearNumImpl<ResultPrecision::Extended>>>)197{198if ((a_comp.date.month > b_comp.date.month)199|| ((a_comp.date.month == b_comp.date.month) && ((a_comp.date.day > b_comp.date.day)200|| ((a_comp.date.day == b_comp.date.day) && ((a_comp.time.hour > b_comp.time.hour)201|| ((a_comp.time.hour == b_comp.time.hour) && ((a_comp.time.minute > b_comp.time.minute)202|| ((a_comp.time.minute == b_comp.time.minute) && ((a_comp.time.second > b_comp.time.second)203|| ((a_comp.time.second == b_comp.time.second) && ((a_comp.millisecond > b_comp.millisecond)204|| ((a_comp.millisecond == b_comp.millisecond) && ((a_comp.microsecond > b_comp.microsecond)205|| ((a_comp.microsecond == b_comp.microsecond) && (a_comp.nanosecond > b_comp.nanosecond)))))))))))))))206res += adjust_value;207}208else if constexpr (std::is_same_v<TransformX, TransformDateTime64<ToRelativeQuarterNumImpl<ResultPrecision::Extended>>>)209{210auto x_month_in_quarter = (a_comp.date.month - 1) % 3;211auto y_month_in_quarter = (b_comp.date.month - 1) % 3;212if ((x_month_in_quarter > y_month_in_quarter)213|| ((x_month_in_quarter == y_month_in_quarter) && ((a_comp.date.day > b_comp.date.day)214|| ((a_comp.date.day == b_comp.date.day) && ((a_comp.time.hour > b_comp.time.hour)215|| ((a_comp.time.hour == b_comp.time.hour) && ((a_comp.time.minute > b_comp.time.minute)216|| ((a_comp.time.minute == b_comp.time.minute) && ((a_comp.time.second > b_comp.time.second)217|| ((a_comp.time.second == b_comp.time.second) && ((a_comp.millisecond > b_comp.millisecond)218|| ((a_comp.millisecond == b_comp.millisecond) && ((a_comp.microsecond > b_comp.microsecond)219|| ((a_comp.microsecond == b_comp.microsecond) && (a_comp.nanosecond > b_comp.nanosecond)))))))))))))))220res += adjust_value;221}222else if constexpr (std::is_same_v<TransformX, TransformDateTime64<ToRelativeMonthNumImpl<ResultPrecision::Extended>>>)223{224if ((a_comp.date.day > b_comp.date.day)225|| ((a_comp.date.day == b_comp.date.day) && ((a_comp.time.hour > b_comp.time.hour)226|| ((a_comp.time.hour == b_comp.time.hour) && ((a_comp.time.minute > b_comp.time.minute)227|| ((a_comp.time.minute == b_comp.time.minute) && ((a_comp.time.second > b_comp.time.second)228|| ((a_comp.time.second == b_comp.time.second) && ((a_comp.millisecond > b_comp.millisecond)229|| ((a_comp.millisecond == b_comp.millisecond) && ((a_comp.microsecond > b_comp.microsecond)230|| ((a_comp.microsecond == b_comp.microsecond) && (a_comp.nanosecond > b_comp.nanosecond)))))))))))))231res += adjust_value;232}233else if constexpr (std::is_same_v<TransformX, TransformDateTime64<ToRelativeWeekNumImpl<ResultPrecision::Extended>>>)234{235auto x_day_of_week = TransformDateTime64<ToDayOfWeekImpl>(transform_x.getScaleMultiplier()).execute(x, 0, timezone_x);236auto y_day_of_week = TransformDateTime64<ToDayOfWeekImpl>(transform_y.getScaleMultiplier()).execute(y, 0, timezone_y);237if ((x_day_of_week > y_day_of_week)238|| ((x_day_of_week == y_day_of_week) && (a_comp.time.hour > b_comp.time.hour))239|| ((a_comp.time.hour == b_comp.time.hour) && ((a_comp.time.minute > b_comp.time.minute)240|| ((a_comp.time.minute == b_comp.time.minute) && ((a_comp.time.second > b_comp.time.second)241|| ((a_comp.time.second == b_comp.time.second) && ((a_comp.millisecond > b_comp.millisecond)242|| ((a_comp.millisecond == b_comp.millisecond) && ((a_comp.microsecond > b_comp.microsecond)243|| ((a_comp.microsecond == b_comp.microsecond) && (a_comp.nanosecond > b_comp.nanosecond)))))))))))244res += adjust_value;245}246else if constexpr (std::is_same_v<TransformX, TransformDateTime64<ToRelativeDayNumImpl<ResultPrecision::Extended>>>)247{248if ((a_comp.time.hour > b_comp.time.hour)249|| ((a_comp.time.hour == b_comp.time.hour) && ((a_comp.time.minute > b_comp.time.minute)250|| ((a_comp.time.minute == b_comp.time.minute) && ((a_comp.time.second > b_comp.time.second)251|| ((a_comp.time.second == b_comp.time.second) && ((a_comp.millisecond > b_comp.millisecond)252|| ((a_comp.millisecond == b_comp.millisecond) && ((a_comp.microsecond > b_comp.microsecond)253|| ((a_comp.microsecond == b_comp.microsecond) && (a_comp.nanosecond > b_comp.nanosecond)))))))))))254res += adjust_value;255}256else if constexpr (std::is_same_v<TransformX, TransformDateTime64<ToRelativeHourNumImpl<ResultPrecision::Extended>>>)257{258if ((a_comp.time.minute > b_comp.time.minute)259|| ((a_comp.time.minute == b_comp.time.minute) && ((a_comp.time.second > b_comp.time.second)260|| ((a_comp.time.second == b_comp.time.second) && ((a_comp.millisecond > b_comp.millisecond)261|| ((a_comp.millisecond == b_comp.millisecond) && ((a_comp.microsecond > b_comp.microsecond)262|| ((a_comp.microsecond == b_comp.microsecond) && (a_comp.nanosecond > b_comp.nanosecond)))))))))263res += adjust_value;264}265else if constexpr (std::is_same_v<TransformX, TransformDateTime64<ToRelativeMinuteNumImpl<ResultPrecision::Extended>>>)266{267if ((a_comp.time.second > b_comp.time.second)268|| ((a_comp.time.second == b_comp.time.second) && ((a_comp.millisecond > b_comp.millisecond)269|| ((a_comp.millisecond == b_comp.millisecond) && ((a_comp.microsecond > b_comp.microsecond)270|| ((a_comp.microsecond == b_comp.microsecond) && (a_comp.nanosecond > b_comp.nanosecond)))))))271res += adjust_value;272}273else if constexpr (std::is_same_v<TransformX, TransformDateTime64<ToRelativeSecondNumImpl<ResultPrecision::Extended>>>)274{275if ((a_comp.millisecond > b_comp.millisecond)276|| ((a_comp.millisecond == b_comp.millisecond) && ((a_comp.microsecond > b_comp.microsecond)277|| ((a_comp.microsecond == b_comp.microsecond) && (a_comp.nanosecond > b_comp.nanosecond)))))278res += adjust_value;279}280else if constexpr (std::is_same_v<TransformX, TransformDateTime64<ToRelativeSubsecondNumImpl<millisecond_multiplier>>>)281{282if ((a_comp.microsecond > b_comp.microsecond)283|| ((a_comp.microsecond == b_comp.microsecond) && (a_comp.nanosecond > b_comp.nanosecond)))284res += adjust_value;285}286else if constexpr (std::is_same_v<TransformX, TransformDateTime64<ToRelativeSubsecondNumImpl<microsecond_multiplier>>>)287{288if (a_comp.nanosecond > b_comp.nanosecond)289res += adjust_value;290}291return res;292}293}294
295template <typename T>296static UInt32 getScale(const T & v)297{298if constexpr (std::is_same_v<T, ColumnDateTime64>)299return v.getScale();300else if constexpr (std::is_same_v<T, DecimalField<DateTime64>>)301return v.getScale();302
303return 0;304}305template <typename T>306static auto stripDecimalFieldValue(T && v)307{308if constexpr (std::is_same_v<std::decay_t<T>, DecimalField<DateTime64>>)309return v.getValue();310else311return v;312}313private:314String name;315};316
317
318/** dateDiff('unit', t1, t2, [timezone])
319* age('unit', t1, t2, [timezone])
320* t1 and t2 can be Date, Date32, DateTime or DateTime64
321*
322* If timezone is specified, it applied to both arguments.
323* If not, timezones from datatypes t1 and t2 are used.
324* If that timezones are not the same, the result is unspecified.
325*
326* Timezone matters because days can have different length.
327*/
328template <bool is_relative>329class FunctionDateDiff : public IFunction330{
331public:332static constexpr auto name = is_relative ? "dateDiff" : "age";333static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionDateDiff>(); }334
335String getName() const override336{337return name;338}339
340bool isVariadic() const override { return true; }341bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; }342size_t getNumberOfArguments() const override { return 0; }343
344DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override345{346if (arguments.size() != 3 && arguments.size() != 4)347throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,348"Number of arguments for function {} doesn't match: passed {}, should be 3 or 4",349getName(), arguments.size());350
351if (!isString(arguments[0]))352throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,353"First argument for function {} (unit) must be String",354getName());355
356if (!isDate(arguments[1]) && !isDate32(arguments[1]) && !isDateTime(arguments[1]) && !isDateTime64(arguments[1]))357throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,358"Second argument for function {} must be Date, Date32, DateTime or DateTime64",359getName());360
361if (!isDate(arguments[2]) && !isDate32(arguments[2]) && !isDateTime(arguments[2]) && !isDateTime64(arguments[2]))362throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,363"Third argument for function {} must be Date, Date32, DateTime or DateTime64",364getName()365);366
367if (arguments.size() == 4 && !isString(arguments[3]))368throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,369"Fourth argument for function {} (timezone) must be String",370getName());371
372return std::make_shared<DataTypeInt64>();373}374
375bool useDefaultImplementationForConstants() const override { return true; }376ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {0, 3}; }377
378ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override379{380const auto * unit_column = checkAndGetColumnConst<ColumnString>(arguments[0].column.get());381if (!unit_column)382throw Exception(ErrorCodes::ILLEGAL_COLUMN,383"First argument for function {} must be constant String",384getName());385
386String unit = Poco::toLower(unit_column->getValue<String>());387
388const IColumn & x = *arguments[1].column;389const IColumn & y = *arguments[2].column;390
391size_t rows = input_rows_count;392auto res = ColumnInt64::create(rows);393
394const auto & timezone_x = extractTimeZoneFromFunctionArguments(arguments, 3, 1);395const auto & timezone_y = extractTimeZoneFromFunctionArguments(arguments, 3, 2);396
397if (unit == "year" || unit == "years" || unit == "yy" || unit == "yyyy")398impl.template dispatchForColumns<ToRelativeYearNumImpl<ResultPrecision::Extended>>(x, y, timezone_x, timezone_y, res->getData());399else if (unit == "quarter" || unit == "quarters" || unit == "qq" || unit == "q")400impl.template dispatchForColumns<ToRelativeQuarterNumImpl<ResultPrecision::Extended>>(x, y, timezone_x, timezone_y, res->getData());401else if (unit == "month" || unit == "months" || unit == "mm" || unit == "m")402impl.template dispatchForColumns<ToRelativeMonthNumImpl<ResultPrecision::Extended>>(x, y, timezone_x, timezone_y, res->getData());403else if (unit == "week" || unit == "weeks" || unit == "wk" || unit == "ww")404impl.template dispatchForColumns<ToRelativeWeekNumImpl<ResultPrecision::Extended>>(x, y, timezone_x, timezone_y, res->getData());405else if (unit == "day" || unit == "days" || unit == "dd" || unit == "d")406impl.template dispatchForColumns<ToRelativeDayNumImpl<ResultPrecision::Extended>>(x, y, timezone_x, timezone_y, res->getData());407else if (unit == "hour" || unit == "hours" || unit == "hh" || unit == "h")408impl.template dispatchForColumns<ToRelativeHourNumImpl<ResultPrecision::Extended>>(x, y, timezone_x, timezone_y, res->getData());409else if (unit == "minute" || unit == "minutes" || unit == "mi" || unit == "n")410impl.template dispatchForColumns<ToRelativeMinuteNumImpl<ResultPrecision::Extended>>(x, y, timezone_x, timezone_y, res->getData());411else if (unit == "second" || unit == "seconds" || unit == "ss" || unit == "s")412impl.template dispatchForColumns<ToRelativeSecondNumImpl<ResultPrecision::Extended>>(x, y, timezone_x, timezone_y, res->getData());413else if (unit == "millisecond" || unit == "milliseconds" || unit == "ms")414impl.template dispatchForColumns<ToRelativeSubsecondNumImpl<millisecond_multiplier>>(x, y, timezone_x, timezone_y, res->getData());415else if (unit == "microsecond" || unit == "microseconds" || unit == "us" || unit == "u")416impl.template dispatchForColumns<ToRelativeSubsecondNumImpl<microsecond_multiplier>>(x, y, timezone_x, timezone_y, res->getData());417else if (unit == "nanosecond" || unit == "nanoseconds" || unit == "ns")418impl.template dispatchForColumns<ToRelativeSubsecondNumImpl<nanosecond_multiplier>>(x, y, timezone_x, timezone_y, res->getData());419else420throw Exception(ErrorCodes::BAD_ARGUMENTS,421"Function {} does not support '{}' unit", getName(), unit);422
423return res;424}425private:426DateDiffImpl<is_relative> impl{name};427};428
429
430/** timeDiff(t1, t2)
431* t1 and t2 can be Date or DateTime
432*/
433class FunctionTimeDiff : public IFunction434{
435using ColumnDateTime64 = ColumnDecimal<DateTime64>;436public:437static constexpr auto name = "timeDiff";438static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionTimeDiff>(); }439
440String getName() const override441{442return name;443}444
445bool isVariadic() const override { return false; }446bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; }447size_t getNumberOfArguments() const override { return 2; }448
449DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override450{451if (arguments.size() != 2)452throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,453"Number of arguments for function {} doesn't match: passed {}, should be 2",454getName(), arguments.size());455
456if (!isDate(arguments[0]) && !isDate32(arguments[0]) && !isDateTime(arguments[0]) && !isDateTime64(arguments[0]))457throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,458"First argument for function {} must be Date, Date32, DateTime or DateTime64",459getName());460
461if (!isDate(arguments[1]) && !isDate32(arguments[1]) && !isDateTime(arguments[1]) && !isDateTime64(arguments[1]))462throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,463"Second argument for function {} must be Date, Date32, DateTime or DateTime64",464getName()465);466
467return std::make_shared<DataTypeInt64>();468}469
470bool useDefaultImplementationForConstants() const override { return true; }471ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {}; }472
473ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override474{475const IColumn & x = *arguments[0].column;476const IColumn & y = *arguments[1].column;477
478size_t rows = input_rows_count;479auto res = ColumnInt64::create(rows);480
481impl.dispatchForColumns<ToRelativeSecondNumImpl<ResultPrecision::Extended>>(x, y, DateLUT::instance(), DateLUT::instance(), res->getData());482
483return res;484}485private:486DateDiffImpl<true> impl{name};487};488
489}
490
491REGISTER_FUNCTION(DateDiff)492{
493factory.registerFunction<FunctionDateDiff<true>>({}, FunctionFactory::CaseInsensitive);494factory.registerAlias("date_diff", FunctionDateDiff<true>::name);495factory.registerAlias("DATE_DIFF", FunctionDateDiff<true>::name);496factory.registerAlias("timestampDiff", FunctionDateDiff<true>::name);497factory.registerAlias("timestamp_diff", FunctionDateDiff<true>::name);498factory.registerAlias("TIMESTAMP_DIFF", FunctionDateDiff<true>::name);499}
500
501REGISTER_FUNCTION(TimeDiff)502{
503factory.registerFunction<FunctionTimeDiff>(FunctionDocumentation{.description=R"(504Returns the difference between two dates or dates with time values. The difference is calculated in seconds units (see toRelativeSecondNum).
505It is same as `dateDiff` and was added only for MySQL support. `dateDiff` is preferred.
506
507Example:
508[example:typical]
509)",510.examples{511{"typical", "SELECT timeDiff(UTCTimestamp(), now());", ""}},512.categories{"Dates and Times"}}, FunctionFactory::CaseInsensitive);513}
514
515REGISTER_FUNCTION(Age)516{
517factory.registerFunction<FunctionDateDiff<false>>({}, FunctionFactory::CaseInsensitive);518}
519
520}
521