mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-18 21:51:57 +00:00
1326 lines
45 KiB
C++
1326 lines
45 KiB
C++
#pragma once
|
|
|
|
#include <DataTypes/DataTypesNumber.h>
|
|
#include <DataTypes/DataTypeDate.h>
|
|
#include <DataTypes/DataTypeDateTime.h>
|
|
#include <DataTypes/DataTypeArray.h>
|
|
#include <DataTypes/DataTypeString.h>
|
|
|
|
#include <Columns/ColumnsNumber.h>
|
|
#include <Columns/ColumnConst.h>
|
|
#include <Columns/ColumnArray.h>
|
|
#include <Columns/ColumnString.h>
|
|
#include <Columns/ColumnFixedString.h>
|
|
|
|
#include <Common/typeid_cast.h>
|
|
|
|
#include <IO/WriteHelpers.h>
|
|
|
|
#include <Functions/IFunction.h>
|
|
#include <Functions/FunctionHelpers.h>
|
|
|
|
#include <common/DateLUT.h>
|
|
|
|
#include <type_traits>
|
|
|
|
|
|
namespace DB
|
|
{
|
|
|
|
namespace ErrorCodes
|
|
{
|
|
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
|
}
|
|
|
|
/** Functions for working with date and time.
|
|
*
|
|
* toYear, toMonth, toDayOfMonth, toDayOfWeek, toHour, toMinute, toSecond,
|
|
* toMonday, toStartOfMonth, toStartOfYear, toStartOfMinute, toStartOfFiveMinute
|
|
* toStartOfHour, toTime,
|
|
* now, today, yesterday
|
|
* TODO: makeDate, makeDateTime
|
|
*
|
|
* (toDate - located in FunctionConversion.h file)
|
|
*
|
|
* Return types:
|
|
* toYear -> UInt16
|
|
* toMonth, toDayOfMonth, toDayOfWeek, toHour, toMinute, toSecond -> UInt8
|
|
* toMonday, toStartOfMonth, toStartOfYear -> Date
|
|
* toStartOfMinute, toStartOfHour, toTime, now -> DateTime
|
|
*
|
|
* And also:
|
|
*
|
|
* timeSlot(EventTime)
|
|
* - rounds the time to half an hour.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
|
|
/// 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);
|
|
const DateLUTImpl & extractTimeZoneFromFunctionArguments(Block & block, const ColumnNumbers & arguments, size_t time_zone_arg_num);
|
|
|
|
|
|
|
|
#define TIME_SLOT_SIZE 1800
|
|
|
|
/** 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).
|
|
*/
|
|
|
|
/// 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 &)
|
|
{
|
|
throw Exception("Illegal type Date of argument for function toStartOfDay", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
}
|
|
|
|
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_t(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_t(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_t(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_t(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 &)
|
|
{
|
|
throw Exception("Illegal type Date of argument for function toTime", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
}
|
|
|
|
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 &)
|
|
{
|
|
throw Exception("Illegal type Date of argument for function toStartOfMinute", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
}
|
|
|
|
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 &)
|
|
{
|
|
throw Exception("Illegal type Date of argument for function toStartOfFiveMinute", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
}
|
|
|
|
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 &)
|
|
{
|
|
throw Exception("Illegal type Date of argument for function toStartOfHour", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
}
|
|
|
|
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_t(d));
|
|
}
|
|
|
|
using FactorTransform = ZeroTransform;
|
|
};
|
|
|
|
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_t(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_t(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_t(d));
|
|
}
|
|
|
|
using FactorTransform = ToMondayImpl;
|
|
};
|
|
|
|
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 &)
|
|
{
|
|
throw Exception("Illegal type Date of argument for function toHour", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
}
|
|
|
|
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 &)
|
|
{
|
|
throw Exception("Illegal type Date of argument for function toMinute", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
}
|
|
|
|
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 &)
|
|
{
|
|
throw Exception("Illegal type Date of argument for function toSecond", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
}
|
|
|
|
using FactorTransform = ToStartOfMinuteImpl;
|
|
};
|
|
|
|
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_t(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_t(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_t(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<DayNum_t>(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, const DateLUTImpl &)
|
|
{
|
|
throw Exception("Illegal type Date of argument for function toRelativeHourNum", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
}
|
|
|
|
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, const DateLUTImpl &)
|
|
{
|
|
throw Exception("Illegal type Date of argument for function toRelativeMinuteNum", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
}
|
|
|
|
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, const DateLUTImpl &)
|
|
{
|
|
throw Exception("Illegal type Date of argument for function toRelativeSecondNum", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
}
|
|
|
|
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<DayNum_t>(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<DayNum_t>(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<DayNum_t>(d)));
|
|
}
|
|
|
|
using FactorTransform = ZeroTransform;
|
|
};
|
|
|
|
|
|
template <typename FromType, typename ToType, typename Transform>
|
|
struct Transformer
|
|
{
|
|
static void vector(const PaddedPODArray<FromType> & vec_from, PaddedPODArray<ToType> & 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 <typename FromType, typename ToType, typename Transform>
|
|
struct DateTimeTransformImpl
|
|
{
|
|
static void execute(Block & block, const ColumnNumbers & arguments, size_t result)
|
|
{
|
|
using Op = Transformer<FromType, ToType, Transform>;
|
|
|
|
const DateLUTImpl & time_zone = extractTimeZoneFromFunctionArguments(block, arguments, 1);
|
|
|
|
const ColumnPtr source_col = block.getByPosition(arguments[0]).column;
|
|
if (const auto * sources = checkAndGetColumn<ColumnVector<FromType>>(source_col.get()))
|
|
{
|
|
auto col_to = ColumnVector<ToType>::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);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
template <typename ToDataType, typename Transform>
|
|
class FunctionDateOrDateTimeToSomething : public IFunction
|
|
{
|
|
public:
|
|
static constexpr auto name = Transform::name;
|
|
static FunctionPtr create(const Context &) { return std::make_shared<FunctionDateOrDateTimeToSomething>(); };
|
|
|
|
String getName() const override
|
|
{
|
|
return name;
|
|
}
|
|
|
|
bool isVariadic() const override { return true; }
|
|
size_t getNumberOfArguments() const override { return 0; }
|
|
|
|
void getReturnTypeAndPrerequisitesImpl(
|
|
const ColumnsWithTypeAndName & arguments,
|
|
DataTypePtr & out_return_type,
|
|
std::vector<ExpressionAction> &) override
|
|
{
|
|
if (arguments.size() == 1)
|
|
{
|
|
if (!arguments[0].type->isDateOrDateTime())
|
|
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 (!checkDataType<DataTypeDateTime>(arguments[0].type.get())
|
|
|| !checkDataType<DataTypeString>(arguments[1].type.get()))
|
|
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<ToDataType, DataTypeDateTime>::value)
|
|
out_return_type = std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, 1));
|
|
else
|
|
out_return_type = std::make_shared<ToDataType>();
|
|
}
|
|
|
|
bool useDefaultImplementationForConstants() const override { return true; }
|
|
ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1}; }
|
|
|
|
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override
|
|
{
|
|
const IDataType * from_type = block.getByPosition(arguments[0]).type.get();
|
|
|
|
if (checkDataType<DataTypeDate>(from_type))
|
|
DateTimeTransformImpl<DataTypeDate::FieldType, typename ToDataType::FieldType, Transform>::execute(block, arguments, result);
|
|
else if (checkDataType<DataTypeDateTime>(from_type))
|
|
DateTimeTransformImpl<DataTypeDateTime::FieldType, typename ToDataType::FieldType, Transform>::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);
|
|
}
|
|
|
|
|
|
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<typename Transform::FactorTransform, ZeroTransform>::value)
|
|
{
|
|
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<DataTypeDate>(&type))
|
|
{
|
|
return Transform::FactorTransform::execute(UInt16(left.get<UInt64>()), date_lut)
|
|
== Transform::FactorTransform::execute(UInt16(right.get<UInt64>()), date_lut)
|
|
? is_monotonic : is_not_monotonic;
|
|
}
|
|
else
|
|
{
|
|
return Transform::FactorTransform::execute(UInt32(left.get<UInt64>()), date_lut)
|
|
== Transform::FactorTransform::execute(UInt32(right.get<UInt64>()), date_lut)
|
|
? is_monotonic : is_not_monotonic;
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
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_t(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_t(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_t(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_t(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_t(d), delta);
|
|
}
|
|
};
|
|
|
|
|
|
template <typename Transform>
|
|
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<AddSecondsImpl> { static constexpr auto name = "subtractSeconds"; };
|
|
struct SubtractMinutesImpl : SubtractIntervalImpl<AddMinutesImpl> { static constexpr auto name = "subtractMinutes"; };
|
|
struct SubtractHoursImpl : SubtractIntervalImpl<AddHoursImpl> { static constexpr auto name = "subtractHours"; };
|
|
struct SubtractDaysImpl : SubtractIntervalImpl<AddDaysImpl> { static constexpr auto name = "subtractDays"; };
|
|
struct SubtractWeeksImpl : SubtractIntervalImpl<AddWeeksImpl> { static constexpr auto name = "subtractWeeks"; };
|
|
struct SubtractMonthsImpl : SubtractIntervalImpl<AddMonthsImpl> { static constexpr auto name = "subtractMonths"; };
|
|
struct SubtractYearsImpl : SubtractIntervalImpl<AddYearsImpl> { static constexpr auto name = "subtractYears"; };
|
|
|
|
|
|
template <typename FromType, typename ToType, typename Transform>
|
|
struct Adder
|
|
{
|
|
static void vector_vector(const PaddedPODArray<FromType> & vec_from, PaddedPODArray<ToType> & 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<FromType> & vec_from, PaddedPODArray<ToType> & 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<ToType> & 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 <typename FromType, typename Transform>
|
|
struct DateTimeAddIntervalImpl
|
|
{
|
|
static void execute(Block & block, const ColumnNumbers & arguments, size_t result)
|
|
{
|
|
using ToType = decltype(Transform::execute(FromType(), 0, std::declval<DateLUTImpl>()));
|
|
using Op = Adder<FromType, ToType, Transform>;
|
|
|
|
const DateLUTImpl & time_zone = extractTimeZoneFromFunctionArguments(block, arguments, 2);
|
|
|
|
const ColumnPtr source_col = block.getByPosition(arguments[0]).column;
|
|
|
|
if (const auto * sources = checkAndGetColumn<ColumnVector<FromType>>(source_col.get()))
|
|
{
|
|
auto col_to = ColumnVector<ToType>::create();
|
|
|
|
const IColumn & delta_column = *block.getByPosition(arguments[1]).column;
|
|
|
|
if (const auto * delta_const_column = typeid_cast<const ColumnConst *>(&delta_column))
|
|
Op::vector_constant(sources->getData(), col_to->getData(), delta_const_column->getField().get<Int64>(), 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<ColumnVector<FromType>>(source_col.get()))
|
|
{
|
|
auto col_to = ColumnVector<ToType>::create();
|
|
Op::constant_vector(sources->template getValue<FromType>(), 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 <typename Transform>
|
|
class FunctionDateOrDateTimeAddInterval : public IFunction
|
|
{
|
|
public:
|
|
static constexpr auto name = Transform::name;
|
|
static FunctionPtr create(const Context &) { return std::make_shared<FunctionDateOrDateTimeAddInterval>(); };
|
|
|
|
String getName() const override
|
|
{
|
|
return name;
|
|
}
|
|
|
|
bool isVariadic() const override { return true; }
|
|
size_t getNumberOfArguments() const override { return 0; }
|
|
|
|
void getReturnTypeAndPrerequisitesImpl(
|
|
const ColumnsWithTypeAndName & arguments,
|
|
DataTypePtr & out_return_type,
|
|
std::vector<ExpressionAction> &) 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 (!arguments[1].type->isNumber())
|
|
throw Exception("Second argument for function " + getName() + " (delta) must be number",
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
if (arguments.size() == 2)
|
|
{
|
|
if (!arguments[0].type->isDateOrDateTime())
|
|
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 (!checkDataType<DataTypeDateTime>(arguments[0].type.get())
|
|
|| !checkDataType<DataTypeString>(arguments[2].type.get()))
|
|
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 (checkDataType<DataTypeDate>(arguments[0].type.get()))
|
|
{
|
|
if (std::is_same<decltype(Transform::execute(DataTypeDate::FieldType(), 0, std::declval<DateLUTImpl>())), UInt16>::value)
|
|
out_return_type = std::make_shared<DataTypeDate>();
|
|
else
|
|
out_return_type = std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, 2));
|
|
}
|
|
else
|
|
{
|
|
if (std::is_same<decltype(Transform::execute(DataTypeDateTime::FieldType(), 0, std::declval<DateLUTImpl>())), UInt16>::value)
|
|
out_return_type = std::make_shared<DataTypeDate>();
|
|
else
|
|
out_return_type = std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, 2));
|
|
}
|
|
}
|
|
|
|
bool useDefaultImplementationForConstants() const override { return true; }
|
|
ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {2}; }
|
|
|
|
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override
|
|
{
|
|
const IDataType * from_type = block.getByPosition(arguments[0]).type.get();
|
|
|
|
if (checkDataType<DataTypeDate>(from_type))
|
|
DateTimeAddIntervalImpl<DataTypeDate::FieldType, Transform>::execute(block, arguments, result);
|
|
else if (checkDataType<DataTypeDateTime>(from_type))
|
|
DateTimeAddIntervalImpl<DataTypeDateTime::FieldType, Transform>::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);
|
|
}
|
|
};
|
|
|
|
|
|
/// 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<FunctionNow>(); };
|
|
|
|
String getName() const override
|
|
{
|
|
return name;
|
|
}
|
|
|
|
size_t getNumberOfArguments() const override { return 0; }
|
|
|
|
DataTypePtr getReturnTypeImpl(const DataTypes & /*arguments*/) const override
|
|
{
|
|
return std::make_shared<DataTypeDateTime>();
|
|
}
|
|
|
|
void executeImpl(Block & block, const ColumnNumbers & /*arguments*/, size_t result) override
|
|
{
|
|
block.getByPosition(result).column = DataTypeUInt32().createColumnConst(
|
|
block.rows(),
|
|
static_cast<UInt64>(time(nullptr)));
|
|
}
|
|
};
|
|
|
|
|
|
class FunctionToday : public IFunction
|
|
{
|
|
public:
|
|
static constexpr auto name = "today";
|
|
static FunctionPtr create(const Context &) { return std::make_shared<FunctionToday>(); };
|
|
|
|
String getName() const override
|
|
{
|
|
return name;
|
|
}
|
|
|
|
size_t getNumberOfArguments() const override { return 0; }
|
|
|
|
DataTypePtr getReturnTypeImpl(const DataTypes & /*arguments*/) const override
|
|
{
|
|
return std::make_shared<DataTypeDate>();
|
|
}
|
|
|
|
void executeImpl(Block & block, const ColumnNumbers & /*arguments*/, size_t result) override
|
|
{
|
|
block.getByPosition(result).column = DataTypeUInt16().createColumnConst(
|
|
block.rows(),
|
|
UInt64(DateLUT::instance().toDayNum(time(nullptr))));
|
|
}
|
|
};
|
|
|
|
|
|
class FunctionYesterday : public IFunction
|
|
{
|
|
public:
|
|
static constexpr auto name = "yesterday";
|
|
static FunctionPtr create(const Context &) { return std::make_shared<FunctionYesterday>(); };
|
|
|
|
String getName() const override
|
|
{
|
|
return name;
|
|
}
|
|
|
|
size_t getNumberOfArguments() const override { return 0; }
|
|
|
|
DataTypePtr getReturnTypeImpl(const DataTypes & /*arguments*/) const override
|
|
{
|
|
return std::make_shared<DataTypeDate>();
|
|
}
|
|
|
|
void executeImpl(Block & block, const ColumnNumbers & /*arguments*/, size_t result) override
|
|
{
|
|
block.getByPosition(result).column = DataTypeUInt16().createColumnConst(
|
|
block.rows(),
|
|
UInt64(DateLUT::instance().toDayNum(time(nullptr)) - 1));
|
|
}
|
|
};
|
|
|
|
|
|
/// 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<FunctionToTimeZone>(); };
|
|
|
|
String getName() const override
|
|
{
|
|
return name;
|
|
}
|
|
|
|
size_t getNumberOfArguments() const override { return 2; }
|
|
|
|
void getReturnTypeAndPrerequisitesImpl(
|
|
const ColumnsWithTypeAndName & arguments,
|
|
DataTypePtr & out_return_type,
|
|
std::vector<ExpressionAction> &) 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 (!checkDataType<DataTypeDateTime>(arguments[0].type.get()))
|
|
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);
|
|
out_return_type = std::make_shared<DataTypeDateTime>(time_zone_name);
|
|
}
|
|
|
|
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override
|
|
{
|
|
block.getByPosition(result).column = block.getByPosition(arguments[0]).column;
|
|
}
|
|
};
|
|
|
|
|
|
class FunctionTimeSlot : public IFunction
|
|
{
|
|
public:
|
|
static constexpr auto name = "timeSlot";
|
|
static FunctionPtr create(const Context &) { return std::make_shared<FunctionTimeSlot>(); };
|
|
|
|
String getName() const override
|
|
{
|
|
return name;
|
|
}
|
|
|
|
size_t getNumberOfArguments() const override { return 1; }
|
|
|
|
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
|
|
{
|
|
if (!checkDataType<DataTypeDateTime>(arguments[0].get()))
|
|
throw Exception("Illegal type " + arguments[0]->getName() + " of first argument of function " + getName() + ". Must be DateTime.",
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
return std::make_shared<DataTypeDateTime>();
|
|
}
|
|
|
|
bool useDefaultImplementationForConstants() const override { return true; }
|
|
|
|
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override
|
|
{
|
|
if (const ColumnUInt32 * times = typeid_cast<const ColumnUInt32 *>(block.getByPosition(arguments[0]).column.get()))
|
|
{
|
|
auto res = ColumnUInt32::create();
|
|
ColumnUInt32::Container & res_vec = res->getData();
|
|
const ColumnUInt32::Container & vec = times->getData();
|
|
|
|
size_t size = vec.size();
|
|
res_vec.resize(size);
|
|
|
|
for (size_t i = 0; i < size; ++i)
|
|
res_vec[i] = vec[i] / TIME_SLOT_SIZE * TIME_SLOT_SIZE;
|
|
|
|
block.getByPosition(result).column = std::move(res);
|
|
}
|
|
else
|
|
throw Exception("Illegal column " + block.getByPosition(arguments[0]).column->getName()
|
|
+ " of argument of function " + getName(),
|
|
ErrorCodes::ILLEGAL_COLUMN);
|
|
}
|
|
};
|
|
|
|
|
|
template <typename DurationType>
|
|
struct TimeSlotsImpl
|
|
{
|
|
static void vector_vector(
|
|
const PaddedPODArray<UInt32> & starts, const PaddedPODArray<DurationType> & durations,
|
|
PaddedPODArray<UInt32> & 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<UInt32> & starts, DurationType duration,
|
|
PaddedPODArray<UInt32> & 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<DurationType> & durations,
|
|
PaddedPODArray<UInt32> & 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<UInt64>(value * TIME_SLOT_SIZE));
|
|
}
|
|
};
|
|
|
|
|
|
class FunctionTimeSlots : public IFunction
|
|
{
|
|
public:
|
|
static constexpr auto name = "timeSlots";
|
|
static FunctionPtr create(const Context &) { return std::make_shared<FunctionTimeSlots>(); };
|
|
|
|
String getName() const override
|
|
{
|
|
return name;
|
|
}
|
|
|
|
size_t getNumberOfArguments() const override { return 2; }
|
|
|
|
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
|
|
{
|
|
if (!checkDataType<DataTypeDateTime>(arguments[0].get()))
|
|
throw Exception("Illegal type " + arguments[0]->getName() + " of first argument of function " + getName() + ". Must be DateTime.",
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
if (!checkDataType<DataTypeUInt32>(arguments[1].get()))
|
|
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<DataTypeArray>(std::make_shared<DataTypeDateTime>());
|
|
}
|
|
|
|
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override
|
|
{
|
|
auto starts = checkAndGetColumn<ColumnUInt32>(block.getByPosition(arguments[0]).column.get());
|
|
auto const_starts = checkAndGetColumnConst<ColumnUInt32>(block.getByPosition(arguments[0]).column.get());
|
|
|
|
auto durations = checkAndGetColumn<ColumnUInt32>(block.getByPosition(arguments[1]).column.get());
|
|
auto const_durations = checkAndGetColumnConst<ColumnUInt32>(block.getByPosition(arguments[1]).column.get());
|
|
|
|
auto res = ColumnArray::create(ColumnUInt32::create());
|
|
ColumnUInt32::Container & res_values = typeid_cast<ColumnUInt32 &>(res->getData()).getData();
|
|
|
|
if (starts && durations)
|
|
{
|
|
TimeSlotsImpl<UInt32>::vector_vector(starts->getData(), durations->getData(), res_values, res->getOffsets());
|
|
block.getByPosition(result).column = std::move(res);
|
|
}
|
|
else if (starts && const_durations)
|
|
{
|
|
TimeSlotsImpl<UInt32>::vector_constant(starts->getData(), const_durations->getValue<UInt32>(), res_values, res->getOffsets());
|
|
block.getByPosition(result).column = std::move(res);
|
|
}
|
|
else if (const_starts && durations)
|
|
{
|
|
TimeSlotsImpl<UInt32>::constant_vector(const_starts->getValue<UInt32>(), durations->getData(), res_values, res->getOffsets());
|
|
block.getByPosition(result).column = std::move(res);
|
|
}
|
|
else if (const_starts && const_durations)
|
|
{
|
|
Array const_res;
|
|
TimeSlotsImpl<UInt32>::constant_constant(const_starts->getValue<UInt32>(), const_durations->getValue<UInt32>(), const_res);
|
|
block.getByPosition(result).column = block.getByPosition(result).type->createColumnConst(block.rows(), 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);
|
|
}
|
|
};
|
|
|
|
|
|
using FunctionToYear = FunctionDateOrDateTimeToSomething<DataTypeUInt16, ToYearImpl>;
|
|
using FunctionToMonth = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToMonthImpl>;
|
|
using FunctionToDayOfMonth = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToDayOfMonthImpl>;
|
|
using FunctionToDayOfWeek = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToDayOfWeekImpl>;
|
|
using FunctionToHour = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToHourImpl>;
|
|
using FunctionToMinute = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToMinuteImpl>;
|
|
using FunctionToSecond = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToSecondImpl>;
|
|
using FunctionToStartOfDay = FunctionDateOrDateTimeToSomething<DataTypeDateTime, ToStartOfDayImpl>;
|
|
using FunctionToMonday = FunctionDateOrDateTimeToSomething<DataTypeDate, ToMondayImpl>;
|
|
using FunctionToStartOfMonth = FunctionDateOrDateTimeToSomething<DataTypeDate, ToStartOfMonthImpl>;
|
|
using FunctionToStartOfQuarter = FunctionDateOrDateTimeToSomething<DataTypeDate, ToStartOfQuarterImpl>;
|
|
using FunctionToStartOfYear = FunctionDateOrDateTimeToSomething<DataTypeDate, ToStartOfYearImpl>;
|
|
using FunctionToStartOfMinute = FunctionDateOrDateTimeToSomething<DataTypeDateTime, ToStartOfMinuteImpl>;
|
|
using FunctionToStartOfFiveMinute = FunctionDateOrDateTimeToSomething<DataTypeDateTime, ToStartOfFiveMinuteImpl>;
|
|
using FunctionToStartOfHour = FunctionDateOrDateTimeToSomething<DataTypeDateTime, ToStartOfHourImpl>;
|
|
using FunctionToTime = FunctionDateOrDateTimeToSomething<DataTypeDateTime, ToTimeImpl>;
|
|
|
|
using FunctionToRelativeYearNum = FunctionDateOrDateTimeToSomething<DataTypeUInt16, ToRelativeYearNumImpl>;
|
|
using FunctionToRelativeMonthNum = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToRelativeMonthNumImpl>;
|
|
using FunctionToRelativeWeekNum = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToRelativeWeekNumImpl>;
|
|
using FunctionToRelativeDayNum = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToRelativeDayNumImpl>;
|
|
|
|
using FunctionToRelativeHourNum = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToRelativeHourNumImpl>;
|
|
using FunctionToRelativeMinuteNum = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToRelativeMinuteNumImpl>;
|
|
using FunctionToRelativeSecondNum = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToRelativeSecondNumImpl>;
|
|
|
|
using FunctionToYYYYMM = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToYYYYMMImpl>;
|
|
using FunctionToYYYYMMDD = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToYYYYMMDDImpl>;
|
|
using FunctionToYYYYMMDDhhmmss = FunctionDateOrDateTimeToSomething<DataTypeUInt64, ToYYYYMMDDhhmmssImpl>;
|
|
|
|
using FunctionAddSeconds = FunctionDateOrDateTimeAddInterval<AddSecondsImpl>;
|
|
using FunctionAddMinutes = FunctionDateOrDateTimeAddInterval<AddMinutesImpl>;
|
|
using FunctionAddHours = FunctionDateOrDateTimeAddInterval<AddHoursImpl>;
|
|
using FunctionAddDays = FunctionDateOrDateTimeAddInterval<AddDaysImpl>;
|
|
using FunctionAddWeeks = FunctionDateOrDateTimeAddInterval<AddWeeksImpl>;
|
|
using FunctionAddMonths = FunctionDateOrDateTimeAddInterval<AddMonthsImpl>;
|
|
using FunctionAddYears = FunctionDateOrDateTimeAddInterval<AddYearsImpl>;
|
|
|
|
using FunctionSubtractSeconds = FunctionDateOrDateTimeAddInterval<SubtractSecondsImpl>;
|
|
using FunctionSubtractMinutes = FunctionDateOrDateTimeAddInterval<SubtractMinutesImpl>;
|
|
using FunctionSubtractHours = FunctionDateOrDateTimeAddInterval<SubtractHoursImpl>;
|
|
using FunctionSubtractDays = FunctionDateOrDateTimeAddInterval<SubtractDaysImpl>;
|
|
using FunctionSubtractWeeks = FunctionDateOrDateTimeAddInterval<SubtractWeeksImpl>;
|
|
using FunctionSubtractMonths = FunctionDateOrDateTimeAddInterval<SubtractMonthsImpl>;
|
|
using FunctionSubtractYears = FunctionDateOrDateTimeAddInterval<SubtractYearsImpl>;
|
|
|
|
}
|