mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-28 02:21:59 +00:00
Fix infinite loop in function hop
This commit is contained in:
parent
1bba7f7eeb
commit
9065f34534
@ -27,6 +27,7 @@ namespace ErrorCodes
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
std::tuple<IntervalKind::Kind, Int64>
|
||||
dispatchForIntervalColumns(const ColumnWithTypeAndName & interval_column, const String & function_name)
|
||||
{
|
||||
@ -106,7 +107,43 @@ namespace
|
||||
checkIntervalArgument(argument, function_name, interval_kind, result_type_is_date);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
template <TimeWindowFunctionName type>
|
||||
struct TimeWindowImpl
|
||||
{
|
||||
static constexpr auto name = "UNKNOWN";
|
||||
|
||||
static DataTypePtr getReturnType(const ColumnsWithTypeAndName & arguments, const String & function_name);
|
||||
|
||||
static ColumnPtr dispatchForColumns(const ColumnsWithTypeAndName & arguments, const String & function_name);
|
||||
};
|
||||
|
||||
template <TimeWindowFunctionName type>
|
||||
class FunctionTimeWindow : public IFunction
|
||||
{
|
||||
public:
|
||||
static constexpr auto name = TimeWindowImpl<type>::name;
|
||||
static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionTimeWindow>(); }
|
||||
String getName() const override { return name; }
|
||||
bool isVariadic() const override { return true; }
|
||||
size_t getNumberOfArguments() const override { return 0; }
|
||||
bool useDefaultImplementationForConstants() const override { return true; }
|
||||
ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1, 2, 3}; }
|
||||
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo &) const override { return true; }
|
||||
|
||||
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override;
|
||||
|
||||
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t /*input_rows_count*/) const override;
|
||||
};
|
||||
|
||||
using FunctionTumble = FunctionTimeWindow<TUMBLE>;
|
||||
using FunctionTumbleStart = FunctionTimeWindow<TUMBLE_START>;
|
||||
using FunctionTumbleEnd = FunctionTimeWindow<TUMBLE_END>;
|
||||
using FunctionHop = FunctionTimeWindow<HOP>;
|
||||
using FunctionWindowId = FunctionTimeWindow<WINDOW_ID>;
|
||||
using FunctionHopStart = FunctionTimeWindow<HOP_START>;
|
||||
using FunctionHopEnd = FunctionTimeWindow<HOP_END>;
|
||||
|
||||
|
||||
template <>
|
||||
struct TimeWindowImpl<TUMBLE>
|
||||
@ -393,6 +430,9 @@ struct TimeWindowImpl<HOP>
|
||||
wstart = AddTime<kind>::execute(wend, -window_num_units, time_zone);
|
||||
ToType wend_latest;
|
||||
|
||||
if (wstart > wend)
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Time overflow in function {}", name);
|
||||
|
||||
do
|
||||
{
|
||||
wend_latest = wend;
|
||||
@ -414,7 +454,7 @@ struct TimeWindowImpl<WINDOW_ID>
|
||||
{
|
||||
static constexpr auto name = "windowID";
|
||||
|
||||
[[maybe_unused]] static DataTypePtr getReturnType(const ColumnsWithTypeAndName & arguments, const String & function_name)
|
||||
static DataTypePtr getReturnType(const ColumnsWithTypeAndName & arguments, const String & function_name)
|
||||
{
|
||||
bool result_type_is_date;
|
||||
IntervalKind interval_kind_1;
|
||||
@ -456,8 +496,7 @@ struct TimeWindowImpl<WINDOW_ID>
|
||||
return std::make_shared<DataTypeUInt32>();
|
||||
}
|
||||
|
||||
[[maybe_unused]] static ColumnPtr
|
||||
dispatchForHopColumns(const ColumnsWithTypeAndName & arguments, const String & function_name)
|
||||
static ColumnPtr dispatchForHopColumns(const ColumnsWithTypeAndName & arguments, const String & function_name)
|
||||
{
|
||||
const auto & time_column = arguments[0];
|
||||
const auto & hop_interval_column = arguments[1];
|
||||
@ -527,6 +566,9 @@ struct TimeWindowImpl<WINDOW_ID>
|
||||
ToType wend = AddTime<kind>::execute(wstart, hop_num_units, time_zone);
|
||||
ToType wend_latest;
|
||||
|
||||
if (wstart > wend)
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Time overflow in function {}", name);
|
||||
|
||||
do
|
||||
{
|
||||
wend_latest = wend;
|
||||
@ -538,14 +580,13 @@ struct TimeWindowImpl<WINDOW_ID>
|
||||
return end;
|
||||
}
|
||||
|
||||
[[maybe_unused]] static ColumnPtr
|
||||
dispatchForTumbleColumns(const ColumnsWithTypeAndName & arguments, const String & function_name)
|
||||
static ColumnPtr dispatchForTumbleColumns(const ColumnsWithTypeAndName & arguments, const String & function_name)
|
||||
{
|
||||
ColumnPtr column = TimeWindowImpl<TUMBLE>::dispatchForColumns(arguments, function_name);
|
||||
return executeWindowBound(column, 1, function_name);
|
||||
}
|
||||
|
||||
[[maybe_unused]] static ColumnPtr dispatchForColumns(const ColumnsWithTypeAndName & arguments, const String & function_name)
|
||||
static ColumnPtr dispatchForColumns(const ColumnsWithTypeAndName & arguments, const String & function_name)
|
||||
{
|
||||
if (arguments.size() == 2)
|
||||
return dispatchForTumbleColumns(arguments, function_name);
|
||||
@ -585,7 +626,7 @@ struct TimeWindowImpl<HOP_START>
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]] static ColumnPtr dispatchForColumns(const ColumnsWithTypeAndName & arguments, const String & function_name)
|
||||
static ColumnPtr dispatchForColumns(const ColumnsWithTypeAndName & arguments, const String & function_name)
|
||||
{
|
||||
const auto & time_column = arguments[0];
|
||||
const auto which_type = WhichDataType(time_column.type);
|
||||
@ -608,12 +649,12 @@ struct TimeWindowImpl<HOP_END>
|
||||
{
|
||||
static constexpr auto name = "hopEnd";
|
||||
|
||||
[[maybe_unused]] static DataTypePtr getReturnType(const ColumnsWithTypeAndName & arguments, const String & function_name)
|
||||
static DataTypePtr getReturnType(const ColumnsWithTypeAndName & arguments, const String & function_name)
|
||||
{
|
||||
return TimeWindowImpl<HOP_START>::getReturnType(arguments, function_name);
|
||||
}
|
||||
|
||||
[[maybe_unused]] static ColumnPtr dispatchForColumns(const ColumnsWithTypeAndName & arguments, const String & function_name)
|
||||
static ColumnPtr dispatchForColumns(const ColumnsWithTypeAndName & arguments, const String & function_name)
|
||||
{
|
||||
const auto & time_column = arguments[0];
|
||||
const auto which_type = WhichDataType(time_column.type);
|
||||
@ -644,6 +685,8 @@ ColumnPtr FunctionTimeWindow<type>::executeImpl(const ColumnsWithTypeAndName & a
|
||||
return TimeWindowImpl<type>::dispatchForColumns(arguments, name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
REGISTER_FUNCTION(TimeWindow)
|
||||
{
|
||||
factory.registerFunction<FunctionTumble>();
|
||||
|
@ -156,39 +156,4 @@ template <> \
|
||||
ADD_SUBSECONDS(Nanosecond, 9)
|
||||
#undef ADD_SUBSECONDS
|
||||
|
||||
template <TimeWindowFunctionName type>
|
||||
struct TimeWindowImpl
|
||||
{
|
||||
static constexpr auto name = "UNKNOWN";
|
||||
|
||||
static DataTypePtr getReturnType(const ColumnsWithTypeAndName & arguments, const String & function_name);
|
||||
|
||||
static ColumnPtr dispatchForColumns(const ColumnsWithTypeAndName & arguments, const String & function_name);
|
||||
};
|
||||
|
||||
template <TimeWindowFunctionName type>
|
||||
class FunctionTimeWindow : public IFunction
|
||||
{
|
||||
public:
|
||||
static constexpr auto name = TimeWindowImpl<type>::name;
|
||||
static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionTimeWindow>(); }
|
||||
String getName() const override { return name; }
|
||||
bool isVariadic() const override { return true; }
|
||||
size_t getNumberOfArguments() const override { return 0; }
|
||||
bool useDefaultImplementationForConstants() const override { return true; }
|
||||
ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1, 2, 3}; }
|
||||
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo &) const override { return true; }
|
||||
|
||||
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override;
|
||||
|
||||
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t /*input_rows_count*/) const override;
|
||||
};
|
||||
|
||||
using FunctionTumble = FunctionTimeWindow<TUMBLE>;
|
||||
using FunctionTumbleStart = FunctionTimeWindow<TUMBLE_START>;
|
||||
using FunctionTumbleEnd = FunctionTimeWindow<TUMBLE_END>;
|
||||
using FunctionHop = FunctionTimeWindow<HOP>;
|
||||
using FunctionWindowId = FunctionTimeWindow<WINDOW_ID>;
|
||||
using FunctionHopStart = FunctionTimeWindow<HOP_START>;
|
||||
using FunctionHopEnd = FunctionTimeWindow<HOP_END>;
|
||||
}
|
||||
|
2
tests/queries/0_stateless/03013_hop_infinite_loop.sql
Normal file
2
tests/queries/0_stateless/03013_hop_infinite_loop.sql
Normal file
@ -0,0 +1,2 @@
|
||||
SET allow_experimental_window_view = 1;
|
||||
SELECT hop(toDateTime(0), INTERVAL 1 DAY, INTERVAL 3 DAY); -- { serverError BAD_ARGUMENTS }
|
Loading…
Reference in New Issue
Block a user