|
|
|
@ -22,24 +22,25 @@ namespace ErrorCodes
|
|
|
|
|
extern const int ILLEGAL_COLUMN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO(vnemkov): in order to be overloadable for specific implementation, make this a base class
|
|
|
|
|
/// AddOnDateTime64DefaultImpl provides default implementation of add-X functionality for DateTime64.
|
|
|
|
|
///
|
|
|
|
|
/// Default implementation is not to change fractional part, but only modify whole part as if it was DateTime.
|
|
|
|
|
/// That means large whole values (for scale less than 9) might not fit into UInt32-range,
|
|
|
|
|
/// and hence default implementation will produce incorrect results.
|
|
|
|
|
template <typename T>
|
|
|
|
|
struct AddOnDateTime64Mixin : public T
|
|
|
|
|
struct AddOnDateTime64DefaultImpl
|
|
|
|
|
{
|
|
|
|
|
/*explicit*/ AddOnDateTime64Mixin(UInt32 scale_ = 0)
|
|
|
|
|
/*explicit*/ AddOnDateTime64DefaultImpl(UInt32 scale_ = 0)
|
|
|
|
|
: scale_multiplier(decimalScaleMultiplier<DateTime64::NativeType>(scale_)),
|
|
|
|
|
fractional_divider(decimalFractionalDivider<DateTime64>(scale_))
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
using T::execute;
|
|
|
|
|
|
|
|
|
|
// Default implementation for add/sub on DateTime64: do math on whole part, leave fractional as it is.
|
|
|
|
|
// Default implementation for add/sub on DateTime64: do math on whole part (the same way as for DateTime), leave fractional as it is.
|
|
|
|
|
inline DateTime64 execute(const DateTime64 & t, Int64 delta, const DateLUTImpl & time_zone) const
|
|
|
|
|
{
|
|
|
|
|
const auto components = decimalSplitWithScaleMultiplier(t, scale_multiplier);
|
|
|
|
|
// const auto components = decimalSplitWithScaleMultiplier(t, scale);
|
|
|
|
|
// TODO (vnemkov): choose proper overload: UInt64 if available, UInt32 otherwise.
|
|
|
|
|
const auto whole = T::execute(static_cast<UInt32>(components.whole), delta, time_zone);
|
|
|
|
|
const auto whole = static_cast<const T*>(this)->execute(static_cast<UInt32>(components.whole), delta, time_zone);
|
|
|
|
|
|
|
|
|
|
return decimalFromComponentsWithMultipliers<DateTime64>(static_cast<DateTime64::NativeType>(whole), components.fractional, scale_multiplier, fractional_divider);
|
|
|
|
|
// return decimalFromComponents<DateTime64>(static_cast<DateTime64::NativeType>(whole), components.fractional, scale);
|
|
|
|
@ -50,8 +51,22 @@ struct AddOnDateTime64Mixin : public T
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct AddSecondsImpl
|
|
|
|
|
/// Type of first argument of 'execute' function overload defines what INPUT DataType it is used for.
|
|
|
|
|
/// Return type defines what is the OUTPUT (return) type of the CH function.
|
|
|
|
|
/// Corresponding types:
|
|
|
|
|
/// - UInt16 => DataTypeDate
|
|
|
|
|
/// - UInt32 => DataTypeDateTime
|
|
|
|
|
/// - DateTime64 => DataTypeDateTime64
|
|
|
|
|
/// Please note that INPUT and OUTPUT types may differ, e.g.:
|
|
|
|
|
/// - 'AddSecondsImpl::execute(UInt32, ...) -> UInt32' is available to the ClickHouse users as 'addSeconds(DateTime, ...) -> DateTime'
|
|
|
|
|
/// - 'AddSecondsImpl::execute(UInt16, ...) -> UInt32' is available to the ClickHouse users as 'addSeconds(Date, ...) -> DateTime'
|
|
|
|
|
|
|
|
|
|
struct AddSecondsImpl : public AddOnDateTime64DefaultImpl<AddSecondsImpl>
|
|
|
|
|
{
|
|
|
|
|
using Base = AddOnDateTime64DefaultImpl<AddSecondsImpl>;
|
|
|
|
|
using Base::Base;
|
|
|
|
|
using Base::execute;
|
|
|
|
|
|
|
|
|
|
static constexpr auto name = "addSeconds";
|
|
|
|
|
|
|
|
|
|
static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl &)
|
|
|
|
@ -65,8 +80,12 @@ struct AddSecondsImpl
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct AddMinutesImpl
|
|
|
|
|
struct AddMinutesImpl : public AddOnDateTime64DefaultImpl<AddMinutesImpl>
|
|
|
|
|
{
|
|
|
|
|
using Base = AddOnDateTime64DefaultImpl<AddMinutesImpl>;
|
|
|
|
|
using Base::Base;
|
|
|
|
|
using Base::execute;
|
|
|
|
|
|
|
|
|
|
static constexpr auto name = "addMinutes";
|
|
|
|
|
|
|
|
|
|
static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl &)
|
|
|
|
@ -80,8 +99,12 @@ struct AddMinutesImpl
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct AddHoursImpl
|
|
|
|
|
struct AddHoursImpl : public AddOnDateTime64DefaultImpl<AddHoursImpl>
|
|
|
|
|
{
|
|
|
|
|
using Base = AddOnDateTime64DefaultImpl<AddHoursImpl>;
|
|
|
|
|
using Base::Base;
|
|
|
|
|
using Base::execute;
|
|
|
|
|
|
|
|
|
|
static constexpr auto name = "addHours";
|
|
|
|
|
|
|
|
|
|
static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl &)
|
|
|
|
@ -95,8 +118,12 @@ struct AddHoursImpl
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct AddDaysImpl
|
|
|
|
|
struct AddDaysImpl : public AddOnDateTime64DefaultImpl<AddDaysImpl>
|
|
|
|
|
{
|
|
|
|
|
using Base = AddOnDateTime64DefaultImpl<AddDaysImpl>;
|
|
|
|
|
using Base::Base;
|
|
|
|
|
using Base::execute;
|
|
|
|
|
|
|
|
|
|
static constexpr auto name = "addDays";
|
|
|
|
|
|
|
|
|
|
// static inline UInt32 execute(UInt64 t, Int64 delta, const DateLUTImpl & time_zone)
|
|
|
|
@ -116,8 +143,12 @@ struct AddDaysImpl
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct AddWeeksImpl
|
|
|
|
|
struct AddWeeksImpl : public AddOnDateTime64DefaultImpl<AddWeeksImpl>
|
|
|
|
|
{
|
|
|
|
|
using Base = AddOnDateTime64DefaultImpl<AddWeeksImpl>;
|
|
|
|
|
using Base::Base;
|
|
|
|
|
using Base::execute;
|
|
|
|
|
|
|
|
|
|
static constexpr auto name = "addWeeks";
|
|
|
|
|
|
|
|
|
|
static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl & time_zone)
|
|
|
|
@ -131,8 +162,12 @@ struct AddWeeksImpl
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct AddMonthsImpl
|
|
|
|
|
struct AddMonthsImpl : public AddOnDateTime64DefaultImpl<AddMonthsImpl>
|
|
|
|
|
{
|
|
|
|
|
using Base = AddOnDateTime64DefaultImpl<AddMonthsImpl>;
|
|
|
|
|
using Base::Base;
|
|
|
|
|
using Base::execute;
|
|
|
|
|
|
|
|
|
|
static constexpr auto name = "addMonths";
|
|
|
|
|
|
|
|
|
|
static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl & time_zone)
|
|
|
|
@ -146,8 +181,12 @@ struct AddMonthsImpl
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct AddQuartersImpl
|
|
|
|
|
struct AddQuartersImpl : public AddOnDateTime64DefaultImpl<AddQuartersImpl>
|
|
|
|
|
{
|
|
|
|
|
using Base = AddOnDateTime64DefaultImpl<AddQuartersImpl>;
|
|
|
|
|
using Base::Base;
|
|
|
|
|
using Base::execute;
|
|
|
|
|
|
|
|
|
|
static constexpr auto name = "addQuarters";
|
|
|
|
|
|
|
|
|
|
static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl & time_zone)
|
|
|
|
@ -161,8 +200,12 @@ struct AddQuartersImpl
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct AddYearsImpl
|
|
|
|
|
struct AddYearsImpl : public AddOnDateTime64DefaultImpl<AddYearsImpl>
|
|
|
|
|
{
|
|
|
|
|
using Base = AddOnDateTime64DefaultImpl<AddYearsImpl>;
|
|
|
|
|
using Base::Base;
|
|
|
|
|
using Base::execute;
|
|
|
|
|
|
|
|
|
|
static constexpr auto name = "addYears";
|
|
|
|
|
|
|
|
|
|
static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl & time_zone)
|
|
|
|
@ -176,28 +219,27 @@ struct AddYearsImpl
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <typename Transform>
|
|
|
|
|
struct SubtractIntervalImpl
|
|
|
|
|
struct SubtractIntervalImpl : public Transform
|
|
|
|
|
{
|
|
|
|
|
template <typename T>
|
|
|
|
|
static
|
|
|
|
|
inline decltype(Transform::execute(T{}, Int64{}, DateLUTImpl{""})) // to preserve return type of Transfor::execute and allow promoting/denoting types.
|
|
|
|
|
execute(T t, Int64 delta, const DateLUTImpl & time_zone)
|
|
|
|
|
{
|
|
|
|
|
using Transform::Transform;
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
inline decltype(std::declval<Transform>().execute(T{}, Int64{}, DateLUTImpl{""})) // to preserve return type of Transfor::execute and allow promoting/denoting types.
|
|
|
|
|
execute(T t, Int64 delta, const DateLUTImpl & time_zone) const
|
|
|
|
|
{
|
|
|
|
|
return Transform::execute(t, -delta, time_zone);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct SubtractSecondsImpl : AddOnDateTime64Mixin<SubtractIntervalImpl<AddSecondsImpl>> { static constexpr auto name = "subtractSeconds"; };
|
|
|
|
|
struct SubtractMinutesImpl : AddOnDateTime64Mixin<SubtractIntervalImpl<AddMinutesImpl>> { static constexpr auto name = "subtractMinutes"; };
|
|
|
|
|
struct SubtractHoursImpl : AddOnDateTime64Mixin<SubtractIntervalImpl<AddHoursImpl>> { static constexpr auto name = "subtractHours"; };
|
|
|
|
|
struct SubtractDaysImpl : AddOnDateTime64Mixin<SubtractIntervalImpl<AddDaysImpl>> { static constexpr auto name = "subtractDays"; };
|
|
|
|
|
struct SubtractWeeksImpl : AddOnDateTime64Mixin<SubtractIntervalImpl<AddWeeksImpl>> { static constexpr auto name = "subtractWeeks"; };
|
|
|
|
|
struct SubtractMonthsImpl : AddOnDateTime64Mixin<SubtractIntervalImpl<AddMonthsImpl>> { static constexpr auto name = "subtractMonths"; };
|
|
|
|
|
struct SubtractQuartersImpl : AddOnDateTime64Mixin<SubtractIntervalImpl<AddQuartersImpl>> { static constexpr auto name = "subtractQuarters"; };
|
|
|
|
|
struct SubtractYearsImpl : AddOnDateTime64Mixin<SubtractIntervalImpl<AddYearsImpl>> { static constexpr auto name = "subtractYears"; };
|
|
|
|
|
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 SubtractQuartersImpl : SubtractIntervalImpl<AddQuartersImpl> { static constexpr auto name = "subtractQuarters"; };
|
|
|
|
|
struct SubtractYearsImpl : SubtractIntervalImpl<AddYearsImpl> { static constexpr auto name = "subtractYears"; };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <typename Transform>
|
|
|
|
@ -210,7 +252,7 @@ struct Adder
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
template <typename FromVectorType, typename ToVectorType>
|
|
|
|
|
void vector_vector(const FromVectorType & vec_from, ToVectorType & vec_to, const IColumn & delta, const DateLUTImpl & time_zone)
|
|
|
|
|
void vector_vector(const FromVectorType & vec_from, ToVectorType & vec_to, const IColumn & delta, const DateLUTImpl & time_zone) const
|
|
|
|
|
{
|
|
|
|
|
size_t size = vec_from.size();
|
|
|
|
|
vec_to.resize(size);
|
|
|
|
@ -220,7 +262,7 @@ struct Adder
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename FromVectorType, typename ToVectorType>
|
|
|
|
|
void vector_constant(const FromVectorType & vec_from, ToVectorType & vec_to, Int64 delta, const DateLUTImpl & time_zone)
|
|
|
|
|
void vector_constant(const FromVectorType & vec_from, ToVectorType & vec_to, Int64 delta, const DateLUTImpl & time_zone) const
|
|
|
|
|
{
|
|
|
|
|
size_t size = vec_from.size();
|
|
|
|
|
vec_to.resize(size);
|
|
|
|
@ -230,7 +272,7 @@ struct Adder
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename FromType, typename ToVectorType>
|
|
|
|
|
void constant_vector(const FromType & from, ToVectorType & vec_to, const IColumn & delta, const DateLUTImpl & time_zone)
|
|
|
|
|
void constant_vector(const FromType & from, ToVectorType & vec_to, const IColumn & delta, const DateLUTImpl & time_zone) const
|
|
|
|
|
{
|
|
|
|
|
size_t size = delta.size();
|
|
|
|
|
vec_to.resize(size);
|
|
|
|
@ -283,6 +325,16 @@ struct DateTimeAddIntervalImpl
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
namespace date_and_time_type_details
|
|
|
|
|
{
|
|
|
|
|
// Compile-time mapping of value (DataType::FieldType) types to corresponding DataType
|
|
|
|
|
template <typename FieldType> struct ResultDataTypeMap {};
|
|
|
|
|
template <> struct ResultDataTypeMap<UInt16> { using ResultDataType = DataTypeDate; };
|
|
|
|
|
template <> struct ResultDataTypeMap<Int16> { using ResultDataType = DataTypeDate; };
|
|
|
|
|
template <> struct ResultDataTypeMap<UInt32> { using ResultDataType = DataTypeDateTime; };
|
|
|
|
|
template <> struct ResultDataTypeMap<Int32> { using ResultDataType = DataTypeDateTime; };
|
|
|
|
|
template <> struct ResultDataTypeMap<DateTime64> { using ResultDataType = DataTypeDateTime64; };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename Transform>
|
|
|
|
|
class FunctionDateOrDateTimeAddInterval : public IFunction
|
|
|
|
@ -332,11 +384,11 @@ public:
|
|
|
|
|
switch (arguments[0].type->getTypeId())
|
|
|
|
|
{
|
|
|
|
|
case TypeIndex::Date:
|
|
|
|
|
return resolveReturnType<typename DataTypeDate::FieldType>(arguments);
|
|
|
|
|
return resolveReturnType<DataTypeDate>(arguments);
|
|
|
|
|
case TypeIndex::DateTime:
|
|
|
|
|
return resolveReturnType<typename DataTypeDateTime::FieldType>(arguments);
|
|
|
|
|
return resolveReturnType<DataTypeDateTime>(arguments);
|
|
|
|
|
case TypeIndex::DateTime64:
|
|
|
|
|
return resolveReturnType<typename DataTypeDateTime64::FieldType>(arguments);
|
|
|
|
|
return resolveReturnType<DataTypeDateTime64>(arguments);
|
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
// TODO (vnemkov): quick and dirty way to check, remove before merging.
|
|
|
|
@ -352,23 +404,16 @@ public:
|
|
|
|
|
template <typename FieldType>
|
|
|
|
|
using TransformExecuteReturnType = decltype(std::declval<Transform>().execute(FieldType(), 0, std::declval<DateLUTImpl>()));
|
|
|
|
|
|
|
|
|
|
template <typename FieldType> struct ResultDataTypeMap {};
|
|
|
|
|
template <> struct ResultDataTypeMap<UInt16> { using ResultDataType = DataTypeDate; };
|
|
|
|
|
template <> struct ResultDataTypeMap<Int16> { using ResultDataType = DataTypeDate; };
|
|
|
|
|
template <> struct ResultDataTypeMap<UInt32> { using ResultDataType = DataTypeDateTime; };
|
|
|
|
|
template <> struct ResultDataTypeMap<Int32> { using ResultDataType = DataTypeDateTime; };
|
|
|
|
|
template <> struct ResultDataTypeMap<DateTime64> { using ResultDataType = DataTypeDateTime64; };
|
|
|
|
|
|
|
|
|
|
// Deduces result DataType from argument data type, based on return type of Transform{}.execute(from, UInt64, DateLUTImpl).
|
|
|
|
|
// e.g. for Transform-type that has execute()-overload with 'UInt16' input and 'UInt32' return,
|
|
|
|
|
// argument type is expected to be 'Date', and result type is deduced to be 'DateTime'.
|
|
|
|
|
template <typename FromFieldType>
|
|
|
|
|
using TransformResultDataType = typename ResultDataTypeMap<TransformExecuteReturnType<FromFieldType>>::ResultDataType;
|
|
|
|
|
using TransformResultDataType = typename date_and_time_type_details::ResultDataTypeMap<TransformExecuteReturnType<FromFieldType>>::ResultDataType;
|
|
|
|
|
|
|
|
|
|
template <typename FieldType>
|
|
|
|
|
template <typename FromDataType>
|
|
|
|
|
DataTypePtr resolveReturnType(const ColumnsWithTypeAndName & arguments) const
|
|
|
|
|
{
|
|
|
|
|
using ResultDataType = TransformResultDataType<FieldType>;
|
|
|
|
|
using ResultDataType = TransformResultDataType<typename FromDataType::FieldType>;
|
|
|
|
|
|
|
|
|
|
if constexpr (std::is_same_v<ResultDataType, DataTypeDate>)
|
|
|
|
|
return std::make_shared<DataTypeDate>();
|
|
|
|
@ -378,6 +423,8 @@ public:
|
|
|
|
|
}
|
|
|
|
|
else if constexpr (std::is_same_v<ResultDataType, DataTypeDateTime64>)
|
|
|
|
|
{
|
|
|
|
|
// TODO (vnemkov): what if there is an overload of Transform::execute() that returns DateTime64 from DateTime or Date ?
|
|
|
|
|
// Shall we use the default scale or one from optional argument ?
|
|
|
|
|
const auto & datetime64_type = assert_cast<const DataTypeDateTime64 &>(*arguments[0].type);
|
|
|
|
|
return std::make_shared<DataTypeDateTime64>(datetime64_type.getScale(), extractTimeZoneNameFromFunctionArguments(arguments, 2, 0));
|
|
|
|
|
}
|
|
|
|
|