-
Notifications
You must be signed in to change notification settings - Fork 3.6k
[feature](function) The date_add function supports DAY_SECOND as interval type #57253
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
9776a5d
f96c625
af07613
b637a6f
6ddc116
105c9a0
f7b7cce
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,6 +36,7 @@ | |
| #include "runtime/runtime_state.h" | ||
| #include "udf/udf.h" | ||
| #include "util/binary_cast.hpp" | ||
| #include "util/string_parser.hpp" | ||
| #include "vec/aggregate_functions/aggregate_function.h" | ||
| #include "vec/columns/column.h" | ||
| #include "vec/columns/column_const.h" | ||
|
|
@@ -79,6 +80,7 @@ auto date_time_add(const typename PrimitiveTypeTraits<ArgType>::DataType::FieldT | |
| if (!(ts_value.template date_add_interval<unit>(interval))) [[unlikely]] { | ||
| throw_out_of_bound_date_int<ValueType, NativeType>(get_time_unit_name(unit), t, delta); | ||
| } | ||
|
|
||
| // here DateValueType = ResultDateValueType | ||
| return binary_cast<ValueType, NativeType>(ts_value); | ||
| } | ||
|
|
@@ -96,6 +98,7 @@ auto date_time_add(const typename PrimitiveTypeTraits<ArgType>::DataType::FieldT | |
| TimeUnit::UNIT == TimeUnit::DAY || TimeUnit::UNIT == TimeUnit::HOUR) \ | ||
| ? PrimitiveType::TYPE_INT \ | ||
| : PrimitiveType::TYPE_BIGINT; \ | ||
| static constexpr PrimitiveType IntervalPRealType = PType; \ | ||
| using InputNativeType = typename PrimitiveTypeTraits<PType>::DataType::FieldType; \ | ||
| using ReturnNativeType = InputNativeType; \ | ||
| using IntervalDataType = typename PrimitiveTypeTraits<IntervalPType>::DataType; \ | ||
|
|
@@ -124,11 +127,34 @@ ADD_TIME_FUNCTION_IMPL(AddWeeksImpl, weeks_add, WEEK); | |
| ADD_TIME_FUNCTION_IMPL(AddMonthsImpl, months_add, MONTH); | ||
| ADD_TIME_FUNCTION_IMPL(AddYearsImpl, years_add, YEAR); | ||
|
|
||
| template <PrimitiveType PType> | ||
| struct AddDaySecondImpl { | ||
| static constexpr PrimitiveType ArgPType = PType; | ||
| static constexpr PrimitiveType ReturnType = PType; | ||
| static constexpr PrimitiveType IntervalPType = PrimitiveType ::TYPE_INT; | ||
| static constexpr PrimitiveType IntervalPRealType = TYPE_STRING; | ||
| using InputNativeType = typename PrimitiveTypeTraits<PType>::DataType ::FieldType; | ||
| using ReturnNativeType = InputNativeType; | ||
| using IntervalDataType = typename PrimitiveTypeTraits<IntervalPType>::DataType; | ||
| using IntervalNativeType = DataTypeInt32::FieldType; | ||
|
|
||
| static constexpr auto name = "day_second_add"; | ||
| static constexpr auto is_nullable = false; | ||
| static inline ReturnNativeType execute(const InputNativeType& t, IntervalNativeType delta) { | ||
| return date_time_add<TimeUnit ::SECOND, PType, IntervalNativeType>(t, delta); | ||
| } | ||
| static DataTypes get_variadic_argument_types() { | ||
| return {std ::make_shared<typename PrimitiveTypeTraits<PType>::DataType>(), | ||
| std ::make_shared<typename PrimitiveTypeTraits<IntervalPRealType>::DataType>()}; | ||
| } | ||
| }; | ||
|
|
||
| template <PrimitiveType PType> | ||
| struct AddQuartersImpl { | ||
| static constexpr PrimitiveType ArgPType = PType; | ||
| static constexpr PrimitiveType ReturnType = PType; | ||
| static constexpr PrimitiveType IntervalPType = PrimitiveType::TYPE_INT; | ||
| static constexpr PrimitiveType IntervalPRealType = TYPE_INT; | ||
| using InputNativeType = typename PrimitiveTypeTraits<PType>::DataType::FieldType; | ||
| using ReturnNativeType = InputNativeType; | ||
|
|
||
|
|
@@ -163,60 +189,70 @@ struct SubtractIntervalImpl { | |
| template <PrimitiveType DateType> | ||
| struct SubtractMicrosecondsImpl : SubtractIntervalImpl<AddMicrosecondsImpl<DateType>> { | ||
| static constexpr PrimitiveType IntervalPType = AddMicrosecondsImpl<DateType>::IntervalPType; | ||
| static constexpr PrimitiveType IntervalPRealType = AddMicrosecondsImpl<DateType>::IntervalPType; | ||
| static constexpr auto name = "microseconds_sub"; | ||
| }; | ||
|
|
||
| template <PrimitiveType DateType> | ||
| struct SubtractMillisecondsImpl : SubtractIntervalImpl<AddMillisecondsImpl<DateType>> { | ||
| static constexpr PrimitiveType IntervalPType = AddMillisecondsImpl<DateType>::IntervalPType; | ||
| static constexpr PrimitiveType IntervalPRealType = AddMicrosecondsImpl<DateType>::IntervalPType; | ||
| static constexpr auto name = "milliseconds_sub"; | ||
| }; | ||
|
|
||
| template <PrimitiveType DateType> | ||
| struct SubtractSecondsImpl : SubtractIntervalImpl<AddSecondsImpl<DateType>> { | ||
| static constexpr PrimitiveType IntervalPType = AddSecondsImpl<DateType>::IntervalPType; | ||
| static constexpr PrimitiveType IntervalPRealType = AddMicrosecondsImpl<DateType>::IntervalPType; | ||
| static constexpr auto name = "seconds_sub"; | ||
| }; | ||
|
|
||
| template <PrimitiveType DateType> | ||
| struct SubtractMinutesImpl : SubtractIntervalImpl<AddMinutesImpl<DateType>> { | ||
| static constexpr PrimitiveType IntervalPType = AddMinutesImpl<DateType>::IntervalPType; | ||
| static constexpr PrimitiveType IntervalPRealType = AddMicrosecondsImpl<DateType>::IntervalPType; | ||
| static constexpr auto name = "minutes_sub"; | ||
| }; | ||
|
|
||
| template <PrimitiveType DateType> | ||
| struct SubtractHoursImpl : SubtractIntervalImpl<AddHoursImpl<DateType>> { | ||
| static constexpr PrimitiveType IntervalPType = AddHoursImpl<DateType>::IntervalPType; | ||
| static constexpr PrimitiveType IntervalPRealType = AddMicrosecondsImpl<DateType>::IntervalPType; | ||
| static constexpr auto name = "hours_sub"; | ||
| }; | ||
|
|
||
| template <PrimitiveType DateType> | ||
| struct SubtractDaysImpl : SubtractIntervalImpl<AddDaysImpl<DateType>> { | ||
| static constexpr PrimitiveType IntervalPType = AddDaysImpl<DateType>::IntervalPType; | ||
| static constexpr PrimitiveType IntervalPRealType = AddMicrosecondsImpl<DateType>::IntervalPType; | ||
| static constexpr auto name = "days_sub"; | ||
| }; | ||
|
|
||
| template <PrimitiveType DateType> | ||
| struct SubtractWeeksImpl : SubtractIntervalImpl<AddWeeksImpl<DateType>> { | ||
| static constexpr PrimitiveType IntervalPType = AddWeeksImpl<DateType>::IntervalPType; | ||
| static constexpr PrimitiveType IntervalPRealType = AddMicrosecondsImpl<DateType>::IntervalPType; | ||
| static constexpr auto name = "weeks_sub"; | ||
| }; | ||
|
|
||
| template <PrimitiveType DateType> | ||
| struct SubtractMonthsImpl : SubtractIntervalImpl<AddMonthsImpl<DateType>> { | ||
| static constexpr PrimitiveType IntervalPType = AddMonthsImpl<DateType>::IntervalPType; | ||
| static constexpr PrimitiveType IntervalPRealType = AddMicrosecondsImpl<DateType>::IntervalPType; | ||
| static constexpr auto name = "months_sub"; | ||
| }; | ||
|
|
||
| template <PrimitiveType DateType> | ||
| struct SubtractQuartersImpl : SubtractIntervalImpl<AddQuartersImpl<DateType>> { | ||
| static constexpr PrimitiveType IntervalPType = AddQuartersImpl<DateType>::IntervalPType; | ||
| static constexpr PrimitiveType IntervalPRealType = AddMicrosecondsImpl<DateType>::IntervalPType; | ||
| static constexpr auto name = "quarters_sub"; | ||
| }; | ||
|
|
||
| template <PrimitiveType DateType> | ||
| struct SubtractYearsImpl : SubtractIntervalImpl<AddYearsImpl<DateType>> { | ||
| static constexpr PrimitiveType IntervalPType = AddYearsImpl<DateType>::IntervalPType; | ||
| static constexpr PrimitiveType IntervalPRealType = AddMicrosecondsImpl<DateType>::IntervalPType; | ||
| static constexpr auto name = "years_sub"; | ||
| }; | ||
|
|
||
|
|
@@ -299,6 +335,7 @@ TIME_DIFF_FUNCTION_IMPL(MicroSecondsDiffImpl, microseconds_diff, MICROSECOND); | |
| struct CLASS { \ | ||
| static constexpr PrimitiveType ArgPType = DateType; \ | ||
| static constexpr PrimitiveType IntervalPType = PrimitiveType::TYPE_INT; \ | ||
| static constexpr PrimitiveType IntervalPRealType = PrimitiveType::TYPE_INT; \ | ||
| using ArgType = typename PrimitiveTypeTraits<DateType>::DataType::FieldType; \ | ||
| using IntervalNativeType = \ | ||
| typename PrimitiveTypeTraits<IntervalPType>::DataType::FieldType; \ | ||
|
|
@@ -580,10 +617,72 @@ class FunctionDateOrDateTimeComputation : public IFunction { | |
| // vector-const | ||
| if (const auto* nest_col1_const = check_and_get_column<ColumnConst>(*nest_col1)) { | ||
| rconst = true; | ||
| const auto col1_inside_const = | ||
| assert_cast<const IntervalColumnType&>(nest_col1_const->get_data_column()); | ||
| Op::vector_constant(sources->get_data(), res_col->get_data(), | ||
| col1_inside_const.get_data()[0], nullmap0, nullmap1); | ||
| if constexpr (Transform::IntervalPRealType == TYPE_STRING) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. type is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the specific calculation logic shouldn't put here. should in |
||
| StringRef time_str = nest_col1_const->get_data_at(0).trim(); | ||
zclllyybb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // string format: "d h:m:s" | ||
| StringParser::ParseResult success; | ||
|
|
||
| size_t space_pos = time_str.find_first_of(' '); | ||
| // day | ||
| std::string days_sub = time_str.substring(0, space_pos).to_string(); | ||
| int days = StringParser::string_to_int_internal<int32_t, true>( | ||
| days_sub.data(), days_sub.size(), &success); | ||
| if (success != StringParser::PARSE_SUCCESS) { | ||
| return Status::InvalidArgument("Invalid days format in '{}'", | ||
| time_str.to_string()); | ||
| } | ||
|
|
||
| // hour:minute:second | ||
| StringRef time_hour_str = time_str.substring(space_pos + 1); | ||
| size_t colon1 = time_hour_str.find_first_of(':'); | ||
| if (colon1 == std::string::npos) { | ||
| return Status::InvalidArgument("Invalid time format, missing ':' in '{}'", | ||
| time_str.to_string()); | ||
| } | ||
|
|
||
| size_t colon2_rel = time_hour_str.substring(colon1 + 1).find_first_of(':'); | ||
| size_t colon2 = (colon2_rel != std::string::npos) ? colon1 + 1 + colon2_rel | ||
| : std::string::npos; | ||
| if (colon2 == std::string::npos) { | ||
| return Status::InvalidArgument("Invalid time format, missing ':' in '{}'", | ||
| time_str.to_string()); | ||
| } | ||
|
|
||
| std::string hours_sub = time_hour_str.substring(0, colon1).to_string(); | ||
| int hours = StringParser::string_to_int_internal<int32_t, true>( | ||
| hours_sub.data(), hours_sub.size(), &success); | ||
| if (success != StringParser::PARSE_SUCCESS) { | ||
| return Status::InvalidArgument("Invalid hours format in '{}'", | ||
| time_str.to_string()); | ||
| } | ||
|
|
||
| std::string minutes_sub = | ||
| time_hour_str.substring(colon1 + 1, colon2 - colon1 - 1).to_string(); | ||
| int minutes = StringParser::string_to_int_internal<int32_t, true>( | ||
| minutes_sub.data(), minutes_sub.size(), &success); | ||
| if (success != StringParser::PARSE_SUCCESS || minutes >= 60) { | ||
| return Status::InvalidArgument("Invalid minutes format in '{}'", | ||
| time_str.to_string()); | ||
| } | ||
|
|
||
| std::string seconds_sub = time_hour_str.substring(colon2 + 1).to_string(); | ||
| int seconds = StringParser::string_to_int_internal<int32_t, true>( | ||
| seconds_sub.data(), seconds_sub.size(), &success); | ||
| if (success != StringParser::PARSE_SUCCESS || seconds >= 60) { | ||
| return Status::InvalidArgument("Invalid seconds format in '{}'", | ||
| time_str.to_string()); | ||
| } | ||
|
|
||
| int delta = days * 24 * 3600 + hours * 3600 + minutes * 60 + seconds; | ||
|
|
||
| Op::vector_constant(sources->get_data(), res_col->get_data(), delta, nullmap0, | ||
| nullmap1); | ||
| } else { | ||
| const auto col1_inside_const = assert_cast<const IntervalColumnType&>( | ||
| nest_col1_const->get_data_column()); | ||
| Op::vector_constant(sources->get_data(), res_col->get_data(), | ||
| col1_inside_const.get_data()[0], nullmap0, nullmap1); | ||
| } | ||
| } else { // vector-vector | ||
| const auto concrete_col1 = assert_cast<const IntervalColumnType&>(*nest_col1); | ||
| Op::vector_vector(sources->get_data(), concrete_col1.get_data(), | ||
|
|
@@ -855,7 +954,8 @@ struct CurrentTimeImpl { | |
| dtv.microsecond()); | ||
| } else { | ||
| return Status::InvalidArgument( | ||
| "The precision in function CURTIME should be between 0 and 6, but got {}", | ||
| "The precision in function CURTIME should be between 0 and 6, but got " | ||
| "{}", | ||
| precision); | ||
| } | ||
| } else { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,6 +26,7 @@ using FunctionAddWeeksV2 = FunctionDateOrDateTimeComputation<AddWeeksImpl<TYPE_D | |
| using FunctionAddMonthsV2 = FunctionDateOrDateTimeComputation<AddMonthsImpl<TYPE_DATEV2>>; | ||
| using FunctionAddQuartersV2 = FunctionDateOrDateTimeComputation<AddQuartersImpl<TYPE_DATEV2>>; | ||
| using FunctionAddYearsV2 = FunctionDateOrDateTimeComputation<AddYearsImpl<TYPE_DATEV2>>; | ||
| using FunctionAddDaySecondV2 = FunctionDateOrDateTimeComputation<AddDaySecondImpl<TYPE_DATEV2>>; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you dont have this signature, please remove |
||
|
|
||
| using FunctionSubDaysV2 = FunctionDateOrDateTimeComputation<SubtractDaysImpl<TYPE_DATEV2>>; | ||
| using FunctionSubWeeksV2 = FunctionDateOrDateTimeComputation<SubtractWeeksImpl<TYPE_DATEV2>>; | ||
|
|
@@ -53,6 +54,8 @@ using FunctionDatetimeV2AddMonths = | |
| using FunctionDatetimeV2AddQuarters = | ||
| FunctionDateOrDateTimeComputation<AddQuartersImpl<TYPE_DATETIMEV2>>; | ||
| using FunctionDatetimeV2AddYears = FunctionDateOrDateTimeComputation<AddYearsImpl<TYPE_DATETIMEV2>>; | ||
| using FunctionDatetimeV2AddDaySecond = | ||
| FunctionDateOrDateTimeComputation<AddDaySecondImpl<TYPE_DATETIMEV2>>; | ||
|
|
||
| using FunctionDatetimeV2SubMicroseconds = | ||
| FunctionDateOrDateTimeComputation<SubtractMicrosecondsImpl<TYPE_DATETIMEV2>>; | ||
|
|
@@ -105,6 +108,7 @@ void register_function_date_time_computation_v2(SimpleFunctionFactory& factory) | |
| factory.register_function<FunctionAddMonthsV2>(); | ||
| factory.register_function<FunctionAddYearsV2>(); | ||
| factory.register_function<FunctionAddQuartersV2>(); | ||
| factory.register_function<FunctionAddDaySecondV2>(); | ||
|
|
||
| factory.register_function<FunctionDatetimeV2AddMicroseconds>(); | ||
| factory.register_function<FunctionDatetimeV2AddMilliseconds>(); | ||
|
|
@@ -116,6 +120,7 @@ void register_function_date_time_computation_v2(SimpleFunctionFactory& factory) | |
| factory.register_function<FunctionDatetimeV2AddMonths>(); | ||
| factory.register_function<FunctionDatetimeV2AddYears>(); | ||
| factory.register_function<FunctionDatetimeV2AddQuarters>(); | ||
| factory.register_function<FunctionDatetimeV2AddDaySecond>(); | ||
|
|
||
| factory.register_function<FunctionSubDaysV2>(); | ||
| factory.register_function<FunctionSubMonthsV2>(); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why add this? why cant just use
IntervalPType?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is actually a compromise solution. We introduced the IntervalPRealType field to handle cases like AddDaySecondImpl where the delta value passed during the execution of the execute method requires type conversion (StringRef → Integer). (So we cannot directly use the
ADD_TIME_FUNCTION_IMPLmacro to generate the code).If we hadn't introduced the
IntervalPRealTypefield and instead setIntervalPType = TYPE_STRING, then inFunctionDateOrDateTimeComputation::execute_impl, we would need to handle TYPE_STRING cases for all three scenarios: vector-vector, vector-const, and const-vector. While the vector-const scenario would be simple to handle, but handling other scenarios will be complex, as we would need to modify all execute methods to support the TYPE_STRING type.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this problem is easy to resolve——add requires clause to functions in DateTimeOp to specific if it should exist depending on template argument.