mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
fix for the DESC frame
This commit is contained in:
parent
fe8b414a69
commit
6e40b9fb6c
@ -54,7 +54,9 @@ void WindowFrame::toString(WriteBuffer & buf) const
|
||||
}
|
||||
else if (begin_type == BoundaryType::Unbounded)
|
||||
{
|
||||
buf << "UNBOUNDED PRECEDING";
|
||||
buf << "UNBOUNDED";
|
||||
buf << " "
|
||||
<< (begin_preceding ? "PRECEDING" : "FOLLOWING");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -69,7 +71,9 @@ void WindowFrame::toString(WriteBuffer & buf) const
|
||||
}
|
||||
else if (end_type == BoundaryType::Unbounded)
|
||||
{
|
||||
buf << "UNBOUNDED PRECEDING";
|
||||
buf << "UNBOUNDED";
|
||||
buf << " "
|
||||
<< (end_preceding ? "PRECEDING" : "FOLLOWING");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -119,10 +123,10 @@ void WindowFrame::checkValid() const
|
||||
{
|
||||
if (!(end_preceding && !begin_preceding))
|
||||
{
|
||||
if (begin_offset <= end_offset)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Should probably check here that starting offset is less than
|
||||
// ending offset, but with regard to ORDER BY direction for RANGE
|
||||
// frames.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,8 +38,9 @@ struct WindowFrame
|
||||
|
||||
FrameType type = FrameType::Range;
|
||||
|
||||
// UNBOUNDED FOLLOWING for the frame end doesn't make much sense, so
|
||||
// Unbounded here means UNBOUNDED PRECEDING.
|
||||
// UNBOUNDED FOLLOWING for the frame end is forbidden by the standard, but for
|
||||
// uniformity the begin_preceding still has to be set to true for UNBOUNDED
|
||||
// frame start.
|
||||
// Offset might be both preceding and following, controlled by begin_preceding,
|
||||
// but the offset value must be positive.
|
||||
BoundaryType begin_type = BoundaryType::Unbounded;
|
||||
@ -47,7 +48,8 @@ struct WindowFrame
|
||||
int64_t begin_offset = 0;
|
||||
bool begin_preceding = true;
|
||||
|
||||
// Here as well, Unbounded is UNBOUNDED FOLLOWING.
|
||||
// Here as well, Unbounded can only be UNBOUNDED FOLLOWING, and end_preceding
|
||||
// must be false.
|
||||
BoundaryType end_type = BoundaryType::Current;
|
||||
int64_t end_offset = 0;
|
||||
bool end_preceding = false;
|
||||
|
@ -63,38 +63,6 @@ WindowTransform::WindowTransform(const Block & input_header_,
|
||||
order_by_indices.push_back(
|
||||
input_header.getPositionByName(column.column_name));
|
||||
}
|
||||
|
||||
// FIXME this is just all wrong. Disabled desc order for now.
|
||||
const auto & frame = window_description.frame;
|
||||
if (frame.type == WindowFrame::FrameType::Range
|
||||
&& window_description.order_by.size() == 1
|
||||
&& window_description.order_by[0].direction < 0
|
||||
&& (frame.begin_type == WindowFrame::BoundaryType::Offset
|
||||
|| frame.end_type == WindowFrame::BoundaryType::Offset))
|
||||
{
|
||||
throw Exception(ErrorCodes::NOT_IMPLEMENTED,
|
||||
"ORDER BY DESC for RANGE OFFSET frames is not implemented");
|
||||
}
|
||||
// // If we have at least one RANGE OFFSET frame boundary, no UNBOUNDED frame
|
||||
// // boundaries, and the ORDER BY is DESC, we have to swap the frame end
|
||||
// // and frame start. This is tricky and I'm not sure how to explain the
|
||||
// // reason, so I can only suggest to draw various RANGE OFFSET frames with
|
||||
// // ASC and DESC orders to understand...
|
||||
// // swap is a no-op if both frames are CURRENT ROW, so use a simpler condition.
|
||||
// auto & frame = window_description.frame;
|
||||
// if (frame.type == WindowFrame::FrameType::Range
|
||||
// && (frame.end_type != WindowFrame::BoundaryType::Unbounded
|
||||
// && frame.begin_type != WindowFrame::BoundaryType::Unbounded)
|
||||
// && window_description.order_by.size() == 1
|
||||
// && window_description.order_by[0].direction < 0)
|
||||
// {
|
||||
// std::swap(frame.begin_type, frame.end_type);
|
||||
// std::swap(frame.begin_preceding, frame.end_preceding);
|
||||
// std::swap(frame.begin_offset, frame.end_offset);
|
||||
//
|
||||
// fmt::print(stderr, "swapped frame boundaries\n");
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
WindowTransform::~WindowTransform()
|
||||
@ -357,11 +325,12 @@ static int compareValuesWithOffset(const ColumnType * compared_column,
|
||||
overflow_to_negative = offset < 0;
|
||||
}
|
||||
|
||||
fmt::print(stderr,
|
||||
"compared [{}] = {}, ref [{}] = {}, offset {} overflow {} to negative {}\n",
|
||||
compared_row, toString(compared_value),
|
||||
reference_row, toString(reference_value),
|
||||
toString(offset), is_overflow, overflow_to_negative);
|
||||
// fmt::print(stderr,
|
||||
// "compared [{}] = {}, ref [{}] = {}, offset {} preceding {} overflow {} to negative {}\n",
|
||||
// compared_row, toString(compared_value),
|
||||
// reference_row, toString(reference_value),
|
||||
// toString(offset), offset_is_preceding,
|
||||
// is_overflow, overflow_to_negative);
|
||||
|
||||
if (is_overflow)
|
||||
{
|
||||
@ -387,7 +356,10 @@ static int compareValuesWithOffset(const ColumnType * compared_column,
|
||||
template <typename ColumnType>
|
||||
void WindowTransform::advanceFrameStartRangeOffset()
|
||||
{
|
||||
// See the comment for advanceFrameEndRangeOffset().
|
||||
const int direction = window_description.order_by[0].direction;
|
||||
const bool preceding = window_description.frame.begin_preceding
|
||||
== (direction > 0);
|
||||
const auto * reference_column = assert_cast<const ColumnType *>(
|
||||
inputAt(current_row)[order_by_indices[0]].get());
|
||||
for (; frame_start < partition_end; advanceRowNumber(frame_start))
|
||||
@ -399,7 +371,7 @@ void WindowTransform::advanceFrameStartRangeOffset()
|
||||
if (compareValuesWithOffset(compared_column, frame_start.row,
|
||||
reference_column, current_row.row,
|
||||
window_description.frame.begin_offset,
|
||||
window_description.frame.begin_preceding)
|
||||
preceding)
|
||||
* direction >= 0)
|
||||
{
|
||||
frame_started = true;
|
||||
@ -410,26 +382,40 @@ void WindowTransform::advanceFrameStartRangeOffset()
|
||||
frame_started = partition_ended;
|
||||
}
|
||||
|
||||
// Helper macros to dispatch on type of the ORDER BY column
|
||||
#define APPLY_FOR_ONE_TYPE(FUNCTION, TYPE) \
|
||||
else if (typeid_cast<const TYPE *>(column)) \
|
||||
{ \
|
||||
FUNCTION<TYPE>(); \
|
||||
}
|
||||
|
||||
#define APPLY_FOR_TYPES(FUNCTION) \
|
||||
if (false) /* NOLINT */ \
|
||||
{ \
|
||||
/* Do nothing, a starter condition. */ \
|
||||
} \
|
||||
APPLY_FOR_ONE_TYPE(FUNCTION, ColumnVector<Int8>) \
|
||||
APPLY_FOR_ONE_TYPE(FUNCTION, ColumnVector<UInt8>) \
|
||||
APPLY_FOR_ONE_TYPE(FUNCTION, ColumnVector<Int16>) \
|
||||
APPLY_FOR_ONE_TYPE(FUNCTION, ColumnVector<UInt16>) \
|
||||
APPLY_FOR_ONE_TYPE(FUNCTION, ColumnVector<Int32>) \
|
||||
APPLY_FOR_ONE_TYPE(FUNCTION, ColumnVector<UInt32>) \
|
||||
APPLY_FOR_ONE_TYPE(FUNCTION, ColumnVector<Int64>) \
|
||||
APPLY_FOR_ONE_TYPE(FUNCTION, ColumnVector<UInt64>) \
|
||||
else \
|
||||
{ \
|
||||
throw Exception(ErrorCodes::NOT_IMPLEMENTED, \
|
||||
"The RANGE OFFSET frame for '{}' ORDER BY column is not implemented", \
|
||||
demangle(typeid(*column).name())); \
|
||||
}
|
||||
|
||||
void WindowTransform::advanceFrameStartRangeOffsetDispatch()
|
||||
{
|
||||
// Dispatch on the type of the ORDER BY column.
|
||||
assert(order_by_indices.size() == 1);
|
||||
const IColumn * column = inputAt(current_row)[order_by_indices[0]].get();
|
||||
|
||||
if (typeid_cast<const ColumnVector<UInt8> *>(column))
|
||||
{
|
||||
advanceFrameStartRangeOffset<ColumnVector<UInt8>>();
|
||||
}
|
||||
else if (typeid_cast<const ColumnVector<Int8> *>(column))
|
||||
{
|
||||
advanceFrameStartRangeOffset<ColumnVector<Int8>>();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Exception(ErrorCodes::NOT_IMPLEMENTED,
|
||||
"The RANGE OFFSET frame start for '{}' ORDER BY column is not implemented",
|
||||
demangle(typeid(*column).name()));
|
||||
}
|
||||
APPLY_FOR_TYPES(advanceFrameStartRangeOffset)
|
||||
}
|
||||
|
||||
void WindowTransform::advanceFrameStart()
|
||||
@ -647,7 +633,11 @@ void WindowTransform::advanceFrameEndRowsOffset()
|
||||
template <typename ColumnType>
|
||||
void WindowTransform::advanceFrameEndRangeOffset()
|
||||
{
|
||||
// PRECEDING/FOLLOWING change direction for DESC order.
|
||||
// See CD 9075-2:201?(E) 7.14 <window clause> p. 429.
|
||||
const int direction = window_description.order_by[0].direction;
|
||||
const bool preceding = window_description.frame.end_preceding
|
||||
== (direction > 0);
|
||||
const auto * reference_column = assert_cast<const ColumnType *>(
|
||||
inputAt(current_row)[order_by_indices[0]].get());
|
||||
for (; frame_end < partition_end; advanceRowNumber(frame_end))
|
||||
@ -660,7 +650,7 @@ void WindowTransform::advanceFrameEndRangeOffset()
|
||||
if (compareValuesWithOffset(compared_column, frame_end.row,
|
||||
reference_column, current_row.row,
|
||||
window_description.frame.end_offset,
|
||||
window_description.frame.end_preceding)
|
||||
preceding)
|
||||
* direction > 0)
|
||||
{
|
||||
frame_ended = true;
|
||||
@ -677,20 +667,7 @@ void WindowTransform::advanceFrameEndRangeOffsetDispatch()
|
||||
assert(order_by_indices.size() == 1);
|
||||
const IColumn * column = inputAt(current_row)[order_by_indices[0]].get();
|
||||
|
||||
if (typeid_cast<const ColumnVector<UInt8> *>(column))
|
||||
{
|
||||
advanceFrameEndRangeOffset<ColumnVector<UInt8>>();
|
||||
}
|
||||
else if (typeid_cast<const ColumnVector<Int8> *>(column))
|
||||
{
|
||||
advanceFrameEndRangeOffset<ColumnVector<Int8>>();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Exception(ErrorCodes::NOT_IMPLEMENTED,
|
||||
"The RANGE OFFSET frame end for '{}' ORDER BY column is not implemented",
|
||||
demangle(typeid(*column).name()));
|
||||
}
|
||||
APPLY_FOR_TYPES(advanceFrameEndRangeOffset)
|
||||
}
|
||||
|
||||
void WindowTransform::advanceFrameEnd()
|
||||
|
@ -771,3 +771,52 @@ order by x;
|
||||
125 124 127 4
|
||||
126 125 127 3
|
||||
127 126 127 2
|
||||
-- RANGE OFFSET ORDER BY DESC
|
||||
select x, min(x) over w, max(x) over w, count(x) over w from (
|
||||
select toUInt8(number) x from numbers(11)) t
|
||||
window w as (order by x desc range between 1 preceding and 2 following)
|
||||
order by x
|
||||
settings max_block_size = 1;
|
||||
0 0 1 2
|
||||
1 0 2 3
|
||||
2 0 3 4
|
||||
3 1 4 4
|
||||
4 2 5 4
|
||||
5 3 6 4
|
||||
6 4 7 4
|
||||
7 5 8 4
|
||||
8 6 9 4
|
||||
9 7 10 4
|
||||
10 8 10 3
|
||||
select x, min(x) over w, max(x) over w, count(x) over w from (
|
||||
select toUInt8(number) x from numbers(11)) t
|
||||
window w as (order by x desc range between 1 preceding and unbounded following)
|
||||
order by x
|
||||
settings max_block_size = 2;
|
||||
0 0 1 2
|
||||
1 0 2 3
|
||||
2 0 3 4
|
||||
3 0 4 5
|
||||
4 0 5 6
|
||||
5 0 6 7
|
||||
6 0 7 8
|
||||
7 0 8 9
|
||||
8 0 9 10
|
||||
9 0 10 11
|
||||
10 0 10 11
|
||||
select x, min(x) over w, max(x) over w, count(x) over w from (
|
||||
select toUInt8(number) x from numbers(11)) t
|
||||
window w as (order by x desc range between unbounded preceding and 2 following)
|
||||
order by x
|
||||
settings max_block_size = 3;
|
||||
0 0 10 11
|
||||
1 0 10 11
|
||||
2 0 10 11
|
||||
3 1 10 10
|
||||
4 2 10 9
|
||||
5 3 10 8
|
||||
6 4 10 7
|
||||
7 5 10 6
|
||||
8 6 10 5
|
||||
9 7 10 4
|
||||
10 8 10 3
|
||||
|
@ -241,3 +241,22 @@ from (
|
||||
)
|
||||
window w as (order by x range between 1 preceding and 2 following)
|
||||
order by x;
|
||||
|
||||
-- RANGE OFFSET ORDER BY DESC
|
||||
select x, min(x) over w, max(x) over w, count(x) over w from (
|
||||
select toUInt8(number) x from numbers(11)) t
|
||||
window w as (order by x desc range between 1 preceding and 2 following)
|
||||
order by x
|
||||
settings max_block_size = 1;
|
||||
|
||||
select x, min(x) over w, max(x) over w, count(x) over w from (
|
||||
select toUInt8(number) x from numbers(11)) t
|
||||
window w as (order by x desc range between 1 preceding and unbounded following)
|
||||
order by x
|
||||
settings max_block_size = 2;
|
||||
|
||||
select x, min(x) over w, max(x) over w, count(x) over w from (
|
||||
select toUInt8(number) x from numbers(11)) t
|
||||
window w as (order by x desc range between unbounded preceding and 2 following)
|
||||
order by x
|
||||
settings max_block_size = 3;
|
||||
|
Loading…
Reference in New Issue
Block a user