Custom default window frame for ntile function

This commit is contained in:
vdimir 2023-04-24 10:41:43 +00:00
parent 6090648fc8
commit 65e63235ec
No known key found for this signature in database
GPG Key ID: 6EE4CE2BEDC51862
3 changed files with 74 additions and 40 deletions

View File

@ -44,6 +44,8 @@ public:
// Must insert the result for current_row. // Must insert the result for current_row.
virtual void windowInsertResultInto(const WindowTransform * transform, virtual void windowInsertResultInto(const WindowTransform * transform,
size_t function_index) = 0; size_t function_index) = 0;
virtual std::optional<WindowFrame> getDefaultFrame() const { return {}; }
}; };
// Compares ORDER BY column values at given rows to find the boundaries of frame: // Compares ORDER BY column values at given rows to find the boundaries of frame:
@ -222,6 +224,15 @@ WindowTransform::WindowTransform(const Block & input_header_,
/// Currently we have slightly wrong mixup of the interfaces of Window and Aggregate functions. /// Currently we have slightly wrong mixup of the interfaces of Window and Aggregate functions.
workspace.window_function_impl = dynamic_cast<IWindowFunction *>(const_cast<IAggregateFunction *>(aggregate_function.get())); workspace.window_function_impl = dynamic_cast<IWindowFunction *>(const_cast<IAggregateFunction *>(aggregate_function.get()));
/// Some functions may have non-standard default frame.
/// Use it if it's the only function over the current window.
if (window_description.frame.is_default && functions.size() == 1 && workspace.window_function_impl)
{
auto custom_default_frame = workspace.window_function_impl->getDefaultFrame();
if (custom_default_frame)
window_description.frame = *custom_default_frame;
}
workspace.aggregate_function_state.reset( workspace.aggregate_function_state.reset(
aggregate_function->sizeOfData(), aggregate_function->sizeOfData(),
aggregate_function->alignOfData()); aggregate_function->alignOfData());
@ -1977,18 +1988,23 @@ struct WindowFunctionNtile final : public WindowFunction
: WindowFunction(name_, argument_types_, parameters_, std::make_shared<DataTypeUInt64>()) : WindowFunction(name_, argument_types_, parameters_, std::make_shared<DataTypeUInt64>())
{ {
if (argument_types.size() != 1) if (argument_types.size() != 1)
{ throw Exception(ErrorCodes::BAD_ARGUMENTS, "Function {} takes exactly one argument", name_);
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Function {} takes exactly one parameter", name_);
}
auto type_id = argument_types[0]->getTypeId(); auto type_id = argument_types[0]->getTypeId();
if (type_id != TypeIndex::UInt8 && type_id != TypeIndex::UInt16 && type_id != TypeIndex::UInt32 && type_id != TypeIndex::UInt64) if (type_id != TypeIndex::UInt8 && type_id != TypeIndex::UInt16 && type_id != TypeIndex::UInt32 && type_id != TypeIndex::UInt64)
{ throw Exception(ErrorCodes::BAD_ARGUMENTS, "'{}' argument type must be an unsigned integer (not larger than 64-bit), got {}", name_, argument_types[0]->getName());
throw Exception(ErrorCodes::BAD_ARGUMENTS, "ntile's argument type must be an unsigned integer (not larger then 64-bit), but got {}", argument_types[0]->getName());
}
} }
bool allocatesMemoryInArena() const override { return false; } bool allocatesMemoryInArena() const override { return false; }
std::optional<WindowFrame> getDefaultFrame() const override
{
WindowFrame frame;
frame.type = WindowFrame::FrameType::ROWS;
frame.end_type = WindowFrame::BoundaryType::Unbounded;
return frame;
}
void windowInsertResultInto(const WindowTransform * transform, void windowInsertResultInto(const WindowTransform * transform,
size_t function_index) override size_t function_index) override
{ {
@ -1999,7 +2015,7 @@ struct WindowFunctionNtile final : public WindowFunction
const auto & workspace = transform->workspaces[function_index]; const auto & workspace = transform->workspaces[function_index];
const auto & arg_col = *current_block.original_input_columns[workspace.argument_column_indices[0]]; const auto & arg_col = *current_block.original_input_columns[workspace.argument_column_indices[0]];
if (!isColumnConst(arg_col)) if (!isColumnConst(arg_col))
throw Exception(ErrorCodes::BAD_ARGUMENTS, "ntile's argument must be a constant"); throw Exception(ErrorCodes::BAD_ARGUMENTS, "Argument of 'ntile' function must be a constant");
auto type_id = argument_types[0]->getTypeId(); auto type_id = argument_types[0]->getTypeId();
if (type_id == TypeIndex::UInt8) if (type_id == TypeIndex::UInt8)
buckets = arg_col[transform->current_row.row].get<UInt8>(); buckets = arg_col[transform->current_row.row].get<UInt8>();
@ -2012,7 +2028,7 @@ struct WindowFunctionNtile final : public WindowFunction
if (!buckets) if (!buckets)
{ {
throw Exception(ErrorCodes::BAD_ARGUMENTS, "ntile's argument must > 0"); throw Exception(ErrorCodes::BAD_ARGUMENTS, "Argument of 'ntile' funtcion must be greater than zero");
} }
} }
// new partition // new partition
@ -2090,22 +2106,16 @@ private:
static void checkWindowFrameType(const WindowTransform * transform) static void checkWindowFrameType(const WindowTransform * transform)
{ {
if (transform->order_by_indices.empty()) if (transform->order_by_indices.empty())
throw Exception(ErrorCodes::BAD_ARGUMENTS, "ntile's window frame must have order by clause"); throw Exception(ErrorCodes::BAD_ARGUMENTS, "Window frame for 'ntile' function must have ORDER BY clause");
if (transform->window_description.frame.type != WindowFrame::FrameType::ROWS)
{
throw Exception(ErrorCodes::BAD_ARGUMENTS, "ntile's frame type must be ROWS");
}
if (transform->window_description.frame.begin_type != WindowFrame::BoundaryType::Unbounded)
{
throw Exception(ErrorCodes::BAD_ARGUMENTS, "ntile's frame start type must be UNBOUNDED PRECEDING");
}
if (transform->window_description.frame.end_type != WindowFrame::BoundaryType::Unbounded)
{
// We must wait all for the partition end and get the total rows number in this // We must wait all for the partition end and get the total rows number in this
// partition. So before the end of this partition, there is no any block could be // partition. So before the end of this partition, there is no any block could be
// dropped out. // dropped out.
throw Exception(ErrorCodes::BAD_ARGUMENTS, "ntile's frame end type must be UNBOUNDED FOLLOWING"); bool is_frame_supported = transform->window_description.frame.begin_type == WindowFrame::BoundaryType::Unbounded
&& transform->window_description.frame.end_type == WindowFrame::BoundaryType::Unbounded;
if (!is_frame_supported)
{
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Window frame for function 'ntile' should be 'ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING'");
} }
} }
}; };

View File

@ -22,7 +22,28 @@ select a, b, ntile(3) over (partition by a order by b rows between unbounded pre
1 7 3 1 7 3
1 8 3 1 8 3
1 9 3 1 9 3
select a, b, ntile(2) over (partition by a order by b rows between unbounded preceding and unbounded following) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); select a, b, ntile(3) over (partition by a order by b) from(select intDiv(number,10) as a, number%10 as b from numbers(20));
0 0 1
0 1 1
0 2 1
0 3 1
0 4 2
0 5 2
0 6 2
0 7 3
0 8 3
0 9 3
1 0 1
1 1 1
1 2 1
1 3 1
1 4 2
1 5 2
1 6 2
1 7 3
1 8 3
1 9 3
select a, b, ntile(2) over (partition by a order by b) from(select intDiv(number,10) as a, number%10 as b from numbers(20));
0 0 1 0 0 1
0 1 1 0 1 1
0 2 1 0 2 1
@ -43,7 +64,7 @@ select a, b, ntile(2) over (partition by a order by b rows between unbounded pre
1 7 2 1 7 2
1 8 2 1 8 2
1 9 2 1 9 2
select a, b, ntile(1) over (partition by a order by b rows between unbounded preceding and unbounded following) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); select a, b, ntile(1) over (partition by a order by b) from(select intDiv(number,10) as a, number%10 as b from numbers(20));
0 0 1 0 0 1
0 1 1 0 1 1
0 2 1 0 2 1
@ -64,7 +85,7 @@ select a, b, ntile(1) over (partition by a order by b rows between unbounded pre
1 7 1 1 7 1
1 8 1 1 8 1
1 9 1 1 9 1
select a, b, ntile(100) over (partition by a order by b rows between unbounded preceding and unbounded following) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); select a, b, ntile(100) over (partition by a order by b) from(select intDiv(number,10) as a, number%10 as b from numbers(20));
0 0 1 0 0 1
0 1 2 0 1 2
0 2 3 0 2 3
@ -85,7 +106,7 @@ select a, b, ntile(100) over (partition by a order by b rows between unbounded p
1 7 8 1 7 8
1 8 9 1 8 9
1 9 10 1 9 10
select a, b, ntile(65535) over (partition by a order by b rows between unbounded preceding and unbounded following) from (select 1 as a, number as b from numbers(65535)) limit 100; select a, b, ntile(65535) over (partition by a order by b) from (select 1 as a, number as b from numbers(65535)) limit 100;
1 0 1 1 0 1
1 1 2 1 1 2
1 2 3 1 2 3
@ -187,11 +208,11 @@ select a, b, ntile(65535) over (partition by a order by b rows between unbounded
1 98 99 1 98 99
1 99 100 1 99 100
-- Bad arguments -- Bad arguments
select a, b, ntile(3.0) over (partition by a order by b rows between unbounded preceding and unbounded following) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 } select a, b, ntile(3.0) over (partition by a order by b) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 }
select a, b, ntile('2') over (partition by a order by b rows between unbounded preceding and unbounded following) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 } select a, b, ntile('2') over (partition by a order by b) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 }
select a, b, ntile(0) over (partition by a order by b rows between unbounded preceding and unbounded following) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 } select a, b, ntile(0) over (partition by a order by b) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 }
select a, b, ntile(-2) over (partition by a order by b rows between unbounded preceding and unbounded following) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 } select a, b, ntile(-2) over (partition by a order by b) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 }
select a, b, ntile(b + 1) over (partition by a order by b rows between unbounded preceding and unbounded following) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 } select a, b, ntile(b + 1) over (partition by a order by b) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 }
-- Bad window type -- Bad window type
select a, b, ntile(2) over (partition by a) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 } select a, b, ntile(2) over (partition by a) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 }
select a, b, ntile(2) over (partition by a order by b rows between 4 preceding and unbounded following) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 } select a, b, ntile(2) over (partition by a order by b rows between 4 preceding and unbounded following) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 }

View File

@ -2,17 +2,20 @@
-- Normal cases -- Normal cases
select a, b, ntile(3) over (partition by a order by b rows between unbounded preceding and unbounded following) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); select a, b, ntile(3) over (partition by a order by b rows between unbounded preceding and unbounded following) from(select intDiv(number,10) as a, number%10 as b from numbers(20));
select a, b, ntile(2) over (partition by a order by b rows between unbounded preceding and unbounded following) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); select a, b, ntile(3) over (partition by a order by b) from(select intDiv(number,10) as a, number%10 as b from numbers(20));
select a, b, ntile(1) over (partition by a order by b rows between unbounded preceding and unbounded following) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); select a, b, ntile(2) over (partition by a order by b) from(select intDiv(number,10) as a, number%10 as b from numbers(20));
select a, b, ntile(100) over (partition by a order by b rows between unbounded preceding and unbounded following) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); select a, b, ntile(1) over (partition by a order by b) from(select intDiv(number,10) as a, number%10 as b from numbers(20));
select a, b, ntile(65535) over (partition by a order by b rows between unbounded preceding and unbounded following) from (select 1 as a, number as b from numbers(65535)) limit 100; select a, b, ntile(100) over (partition by a order by b) from(select intDiv(number,10) as a, number%10 as b from numbers(20));
select a, b, ntile(65535) over (partition by a order by b) from (select 1 as a, number as b from numbers(65535)) limit 100;
-- Bad arguments -- Bad arguments
select a, b, ntile(3.0) over (partition by a order by b rows between unbounded preceding and unbounded following) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 } select a, b, ntile(3.0) over (partition by a order by b) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 }
select a, b, ntile('2') over (partition by a order by b rows between unbounded preceding and unbounded following) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 } select a, b, ntile('2') over (partition by a order by b) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 }
select a, b, ntile(0) over (partition by a order by b rows between unbounded preceding and unbounded following) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 } select a, b, ntile(0) over (partition by a order by b) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 }
select a, b, ntile(-2) over (partition by a order by b rows between unbounded preceding and unbounded following) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 } select a, b, ntile(-2) over (partition by a order by b) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 }
select a, b, ntile(b + 1) over (partition by a order by b rows between unbounded preceding and unbounded following) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 } select a, b, ntile(b + 1) over (partition by a order by b) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 }
-- Bad window type -- Bad window type
select a, b, ntile(2) over (partition by a) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 } select a, b, ntile(2) over (partition by a) from(select intDiv(number,10) as a, number%10 as b from numbers(20)); -- { serverError 36 }