ClickHouse/dbms/src/Functions/FunctionsDateTime.h
2017-09-15 15:16:12 +03:00

968 lines
34 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.
*/
#define TIME_SLOT_SIZE 1800
/** Extra 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 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: to convert 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 t, const DateLUTImpl & time_zone) { return 0; }
static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone) { return 0; }
};
struct ToDateImpl
{
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return UInt16(time_zone.toDayNum(t));
}
static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return d;
}
using FactorTransform = ZeroTransform;
};
struct ToStartOfDayImpl
{
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toDate(t);
}
static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return d;
}
using FactorTransform = ZeroTransform;
};
struct ToMondayImpl
{
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 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 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 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
{
/// 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 d, const DateLUTImpl & time_zone)
{
throw Exception("Illegal type Date of argument for function toTime", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
}
using FactorTransform = ToDateImpl;
};
struct ToStartOfMinuteImpl
{
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfMinuteInaccurate(t);
}
static inline UInt32 execute(UInt16 d, const DateLUTImpl & time_zone)
{
throw Exception("Illegal type Date of argument for function toStartOfMinute", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
}
using FactorTransform = ZeroTransform;
};
struct ToStartOfFiveMinuteImpl
{
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfFiveMinuteInaccurate(t);
}
static inline UInt32 execute(UInt16 d, const DateLUTImpl & time_zone)
{
throw Exception("Illegal type Date of argument for function toStartOfFiveMinute", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
}
using FactorTransform = ZeroTransform;
};
struct ToStartOfHourImpl
{
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfHourInaccurate(t);
}
static inline UInt32 execute(UInt16 d, const DateLUTImpl & time_zone)
{
throw Exception("Illegal type Date of argument for function toStartOfHour", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
}
using FactorTransform = ZeroTransform;
};
struct ToYearImpl
{
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 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 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 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 inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toHour(t);
}
static inline UInt8 execute(UInt16 d, const DateLUTImpl & time_zone)
{
throw Exception("Illegal type Date of argument for function toHour", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
}
using FactorTransform = ToDateImpl;
};
struct ToMinuteImpl
{
static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toMinuteInaccurate(t);
}
static inline UInt8 execute(UInt16 d, const DateLUTImpl & time_zone)
{
throw Exception("Illegal type Date of argument for function toMinute", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
}
using FactorTransform = ToStartOfHourImpl;
};
struct ToSecondImpl
{
static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toSecondInaccurate(t);
}
static inline UInt8 execute(UInt16 d, const DateLUTImpl & time_zone)
{
throw Exception("Illegal type Date of argument for function toSecond", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
}
using FactorTransform = ToStartOfMinuteImpl;
};
struct ToRelativeYearNumImpl
{
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 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 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 inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toDayNum(t);
}
static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return static_cast<DayNum_t>(d);
}
using FactorTransform = ZeroTransform;
};
struct ToRelativeHourNumImpl
{
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)
{
throw Exception("Illegal type Date of argument for function toRelativeHourNum", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
}
using FactorTransform = ZeroTransform;
};
struct ToRelativeMinuteNumImpl
{
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)
{
throw Exception("Illegal type Date of argument for function toRelativeMinuteNum", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
}
using FactorTransform = ZeroTransform;
};
struct ToRelativeSecondNumImpl
{
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return t;
}
static inline UInt32 execute(UInt16 d, const DateLUTImpl & time_zone)
{
throw Exception("Illegal type Date of argument for function toRelativeSecondNum", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
}
using FactorTransform = ZeroTransform;
};
struct ToYYYYMMImpl
{
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 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 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);
}
static void constant(const FromType & from, ToType & to, const DateLUTImpl & time_zone)
{
to = Transform::execute(from, time_zone);
}
};
template <typename FromType, typename ToType, typename Transform, typename Name>
struct DateTimeTransformImpl
{
static void execute(Block & block, const ColumnNumbers & arguments, size_t result)
{
using Op = Transformer<FromType, ToType, Transform>;
const ColumnPtr source_col = block.getByPosition(arguments[0]).column;
const auto * sources = checkAndGetColumn<ColumnVector<FromType>>(source_col.get());
const ColumnConst * time_zone_column = nullptr;
if (arguments.size() == 2)
{
time_zone_column = checkAndGetColumnConst<ColumnString>(block.getByPosition(arguments[1]).column.get());
if (!time_zone_column)
throw Exception("Illegal column " + block.getByPosition(arguments[1]).column->getName()
+ " of second (time zone) argument of function " + Name::name + ", must be constant string",
ErrorCodes::ILLEGAL_COLUMN);
}
const DateLUTImpl & time_zone = time_zone_column
? DateLUT::instance(time_zone_column->getValue<String>())
: DateLUT::instance();
if (sources)
{
auto col_to = std::make_shared<ColumnVector<ToType>>();
block.getByPosition(result).column = col_to;
Op::vector(sources->getData(), col_to->getData(), time_zone);
}
else
{
throw Exception("Illegal column " + block.getByPosition(arguments[0]).column->getName()
+ " of first argument of function " + Name::name,
ErrorCodes::ILLEGAL_COLUMN);
}
}
};
template <typename ToDataType, typename Transform, typename Name>
class FunctionDateOrDateTimeToSomething : public IFunction
{
public:
static constexpr auto name = Name::name;
static FunctionPtr create(const Context & 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; }
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
{
if (arguments.size() == 1)
{
if (!checkDataType<DataTypeDate>(arguments[0].get())
&& !checkDataType<DataTypeDateTime>(arguments[0].get()))
throw Exception{
"Illegal type " + arguments[0]->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].get())
|| !checkDataType<DataTypeString>(arguments[1].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);
return 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
{
IDataType * from_type = block.getByPosition(arguments[0]).type.get();
if (checkDataType<DataTypeDate>(from_type))
DateTimeTransformImpl<DataTypeDate::FieldType, typename ToDataType::FieldType, Transform, Name>::execute(block, arguments, result);
else if (checkDataType<DataTypeDateTime>(from_type))
DateTimeTransformImpl<DataTypeDateTime::FieldType, typename ToDataType::FieldType, Transform, Name>::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;
}
}
};
/// 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 & 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().createConstColumn(
block.rows(),
static_cast<UInt64>(time(0)));
}
};
class FunctionToday : public IFunction
{
public:
static constexpr auto name = "today";
static FunctionPtr create(const Context & 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().createConstColumn(
block.rows(),
UInt64(DateLUT::instance().toDayNum(time(0))));
}
};
class FunctionYesterday : public IFunction
{
public:
static constexpr auto name = "yesterday";
static FunctionPtr create(const Context & 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().createConstColumn(
block.rows(),
UInt64(DateLUT::instance().toDayNum(time(0)) - 1));
}
};
class FunctionTimeSlot : public IFunction
{
public:
static constexpr auto name = "timeSlot";
static FunctionPtr create(const Context & 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 = std::make_shared<ColumnUInt32>();
ColumnPtr res_holder = res;
ColumnUInt32::Container_t & res_vec = res->getData();
const ColumnUInt32::Container_t & 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 = res_holder;
}
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_t & result_offsets)
{
size_t size = starts.size();
result_offsets.resize(size);
result_values.reserve(size);
ColumnArray::Offset_t 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_t & result_offsets)
{
size_t size = starts.size();
result_offsets.resize(size);
result_values.reserve(size);
ColumnArray::Offset_t 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_t & result_offsets)
{
size_t size = durations.size();
result_offsets.resize(size);
result_values.reserve(size);
ColumnArray::Offset_t 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 & 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 = std::make_shared<ColumnArray>(std::make_shared<ColumnUInt32>());
ColumnPtr res_holder = res;
ColumnUInt32::Container_t & 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 = res_holder;
}
else if (starts && const_durations)
{
TimeSlotsImpl<UInt32>::vector_constant(starts->getData(), const_durations->getValue<UInt32>(), res_values, res->getOffsets());
block.getByPosition(result).column = res_holder;
}
else if (const_starts && durations)
{
TimeSlotsImpl<UInt32>::constant_vector(const_starts->getValue<UInt32>(), durations->getData(), res_values, res->getOffsets());
block.getByPosition(result).column = res_holder;
}
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->createConstColumn(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);
}
};
struct NameToYear { static constexpr auto name = "toYear"; };
struct NameToMonth { static constexpr auto name = "toMonth"; };
struct NameToDayOfMonth { static constexpr auto name = "toDayOfMonth"; };
struct NameToDayOfWeek { static constexpr auto name = "toDayOfWeek"; };
struct NameToHour { static constexpr auto name = "toHour"; };
struct NameToMinute { static constexpr auto name = "toMinute"; };
struct NameToSecond { static constexpr auto name = "toSecond"; };
struct NameToStartOfDay { static constexpr auto name = "toStartOfDay"; };
struct NameToMonday { static constexpr auto name = "toMonday"; };
struct NameToStartOfMonth { static constexpr auto name = "toStartOfMonth"; };
struct NameToStartOfQuarter { static constexpr auto name = "toStartOfQuarter"; };
struct NameToStartOfYear { static constexpr auto name = "toStartOfYear"; };
struct NameToStartOfMinute { static constexpr auto name = "toStartOfMinute"; };
struct NameToStartOfFiveMinute { static constexpr auto name = "toStartOfFiveMinute"; };
struct NameToStartOfHour { static constexpr auto name = "toStartOfHour"; };
struct NameToTime { static constexpr auto name = "toTime"; };
struct NameToRelativeYearNum { static constexpr auto name = "toRelativeYearNum"; };
struct NameToRelativeMonthNum { static constexpr auto name = "toRelativeMonthNum"; };
struct NameToRelativeWeekNum { static constexpr auto name = "toRelativeWeekNum"; };
struct NameToRelativeDayNum { static constexpr auto name = "toRelativeDayNum"; };
struct NameToRelativeHourNum { static constexpr auto name = "toRelativeHourNum"; };
struct NameToRelativeMinuteNum { static constexpr auto name = "toRelativeMinuteNum"; };
struct NameToRelativeSecondNum { static constexpr auto name = "toRelativeSecondNum"; };
struct NameToYYYYMM { static constexpr auto name = "toYYYYMM"; };
struct NameToYYYYMMDD { static constexpr auto name = "toYYYYMMDD"; };
struct NameToYYYYMMDDhhmmss { static constexpr auto name = "toYYYYMMDDhhmmss"; };
using FunctionToYear = FunctionDateOrDateTimeToSomething<DataTypeUInt16, ToYearImpl, NameToYear>;
using FunctionToMonth = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToMonthImpl, NameToMonth>;
using FunctionToDayOfMonth = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToDayOfMonthImpl, NameToDayOfMonth>;
using FunctionToDayOfWeek = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToDayOfWeekImpl, NameToDayOfWeek>;
using FunctionToHour = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToHourImpl, NameToHour>;
using FunctionToMinute = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToMinuteImpl, NameToMinute>;
using FunctionToSecond = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToSecondImpl, NameToSecond>;
using FunctionToStartOfDay = FunctionDateOrDateTimeToSomething<DataTypeDateTime, ToStartOfDayImpl, NameToStartOfDay>;
using FunctionToMonday = FunctionDateOrDateTimeToSomething<DataTypeDate, ToMondayImpl, NameToMonday>;
using FunctionToStartOfMonth = FunctionDateOrDateTimeToSomething<DataTypeDate, ToStartOfMonthImpl, NameToStartOfMonth>;
using FunctionToStartOfQuarter = FunctionDateOrDateTimeToSomething<DataTypeDate, ToStartOfQuarterImpl, NameToStartOfQuarter>;
using FunctionToStartOfYear = FunctionDateOrDateTimeToSomething<DataTypeDate, ToStartOfYearImpl, NameToStartOfYear>;
using FunctionToStartOfMinute = FunctionDateOrDateTimeToSomething<DataTypeDateTime, ToStartOfMinuteImpl, NameToStartOfMinute>;
using FunctionToStartOfFiveMinute = FunctionDateOrDateTimeToSomething<DataTypeDateTime, ToStartOfFiveMinuteImpl, NameToStartOfFiveMinute>;
using FunctionToStartOfHour = FunctionDateOrDateTimeToSomething<DataTypeDateTime, ToStartOfHourImpl, NameToStartOfHour>;
using FunctionToTime = FunctionDateOrDateTimeToSomething<DataTypeDateTime, ToTimeImpl, NameToTime>;
using FunctionToRelativeYearNum = FunctionDateOrDateTimeToSomething<DataTypeUInt16, ToRelativeYearNumImpl, NameToRelativeYearNum>;
using FunctionToRelativeMonthNum = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToRelativeMonthNumImpl, NameToRelativeMonthNum>;
using FunctionToRelativeWeekNum = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToRelativeWeekNumImpl, NameToRelativeWeekNum>;
using FunctionToRelativeDayNum = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToRelativeDayNumImpl, NameToRelativeDayNum>;
using FunctionToRelativeHourNum = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToRelativeHourNumImpl, NameToRelativeHourNum>;
using FunctionToRelativeMinuteNum = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToRelativeMinuteNumImpl, NameToRelativeMinuteNum>;
using FunctionToRelativeSecondNum = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToRelativeSecondNumImpl, NameToRelativeSecondNum>;
using FunctionToYYYYMM = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToYYYYMMImpl, NameToYYYYMM>;
using FunctionToYYYYMMDD = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToYYYYMMDDImpl, NameToYYYYMMDD>;
using FunctionToYYYYMMDDhhmmss = FunctionDateOrDateTimeToSomething<DataTypeUInt64, ToYYYYMMDDhhmmssImpl, NameToYYYYMMDDhhmmss>;
}