mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 23:21:59 +00:00
ROWS OFFSET frame end
This commit is contained in:
parent
4abbbae583
commit
c1c71fc8e9
@ -109,6 +109,21 @@ void WindowFrame::checkValid() const
|
||||
return;
|
||||
}
|
||||
|
||||
if (end_type == BoundaryType::Offset
|
||||
&& begin_type == BoundaryType::Offset)
|
||||
{
|
||||
if (type == FrameType::Rows)
|
||||
{
|
||||
if (end_offset >= begin_offset)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// For RANGE and GROUPS, we must check that end follows begin if sorted
|
||||
// according to ORDER BY (we don't support them yet).
|
||||
}
|
||||
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS,
|
||||
"Window frame '{}' is invalid",
|
||||
toString());
|
||||
|
@ -271,16 +271,22 @@ void WindowTransform::advanceFrameStartRowsOffset()
|
||||
return;
|
||||
}
|
||||
|
||||
assert(frame_start <= partition_end);
|
||||
if (frame_start == partition_end && partition_ended)
|
||||
if (partition_end <= frame_start)
|
||||
{
|
||||
// A FOLLOWING frame start ran into the end of partition.
|
||||
frame_started = true;
|
||||
frame_start = partition_end;
|
||||
frame_started = partition_ended;
|
||||
return;
|
||||
}
|
||||
|
||||
// Handled the equality case above. Now the frame start is inside the
|
||||
// partition, if we walked all the offset, it's final.
|
||||
assert(partition_start < frame_start);
|
||||
frame_started = offset_left == 0;
|
||||
|
||||
// If we ran into the start of data (offset left is negative), we won't be
|
||||
// able to make progress. Should have handled this case above.
|
||||
assert(offset_left >= 0);
|
||||
}
|
||||
|
||||
void WindowTransform::advanceFrameStartChoose()
|
||||
@ -463,6 +469,39 @@ void WindowTransform::advanceFrameEndUnbounded()
|
||||
frame_ended = partition_ended;
|
||||
}
|
||||
|
||||
void WindowTransform::advanceFrameEndRowsOffset()
|
||||
{
|
||||
// Walk the specified offset from the current row. The "+1" is needed
|
||||
// because the frame_end is a past-the-end pointer.
|
||||
const auto [moved_row, offset_left] = moveRowNumber(current_row,
|
||||
window_description.frame.end_offset + 1);
|
||||
|
||||
if (partition_end <= moved_row)
|
||||
{
|
||||
// Clamp to the end of partition. It might not have ended yet, in which
|
||||
// case wait for more data.
|
||||
frame_end = partition_end;
|
||||
frame_ended = partition_ended;
|
||||
return;
|
||||
}
|
||||
|
||||
if (moved_row <= partition_start)
|
||||
{
|
||||
// Clamp to the start of partition.
|
||||
frame_end = partition_start;
|
||||
frame_ended = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Frame end inside partition, if we walked all the offset, it's final.
|
||||
frame_end = moved_row;
|
||||
frame_ended = offset_left == 0;
|
||||
|
||||
// If we ran into the start of data (offset left is negative), we won't be
|
||||
// able to make progress. Should have handled this case above.
|
||||
assert(offset_left >= 0);
|
||||
}
|
||||
|
||||
void WindowTransform::advanceFrameEnd()
|
||||
{
|
||||
// No reason for this function to be called again after it succeeded.
|
||||
@ -479,9 +518,17 @@ void WindowTransform::advanceFrameEnd()
|
||||
advanceFrameEndUnbounded();
|
||||
break;
|
||||
case WindowFrame::BoundaryType::Offset:
|
||||
throw Exception(ErrorCodes::NOT_IMPLEMENTED,
|
||||
"The frame end type '{}' is not implemented",
|
||||
WindowFrame::toString(window_description.frame.end_type));
|
||||
switch (window_description.frame.type)
|
||||
{
|
||||
case WindowFrame::FrameType::Rows:
|
||||
advanceFrameEndRowsOffset();
|
||||
break;
|
||||
default:
|
||||
throw Exception(ErrorCodes::NOT_IMPLEMENTED,
|
||||
"The frame end type '{}' is not implemented",
|
||||
WindowFrame::toString(window_description.frame.end_type));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// fmt::print(stderr, "frame_end {} -> {}\n", frame_end_before, frame_end);
|
||||
|
@ -109,9 +109,10 @@ private:
|
||||
void advanceFrameStart();
|
||||
void advanceFrameStartChoose();
|
||||
void advanceFrameStartRowsOffset();
|
||||
void advanceFrameEnd();
|
||||
void advanceFrameEndCurrentRow();
|
||||
void advanceFrameEndUnbounded();
|
||||
void advanceFrameEndRowsOffset();
|
||||
void advanceFrameEnd();
|
||||
bool arePeers(const RowNumber & x, const RowNumber & y) const;
|
||||
void updateAggregationState();
|
||||
void writeOutCurrentRow();
|
||||
|
@ -558,11 +558,106 @@ settings max_block_size = 2;
|
||||
28 5 3 2 1
|
||||
29 5 2 1 0
|
||||
30 6 1 1 0
|
||||
-- ROWS offset frame start and end
|
||||
select number, p,
|
||||
count(*) over (partition by p order by number
|
||||
rows between 2 preceding and 2 following)
|
||||
from (select number, intDiv(number, 7) p from numbers(71))
|
||||
order by p, number
|
||||
settings max_block_size = 2;
|
||||
0 0 3
|
||||
1 0 4
|
||||
2 0 5
|
||||
3 0 5
|
||||
4 0 5
|
||||
5 0 4
|
||||
6 0 3
|
||||
7 1 3
|
||||
8 1 4
|
||||
9 1 5
|
||||
10 1 5
|
||||
11 1 5
|
||||
12 1 4
|
||||
13 1 3
|
||||
14 2 3
|
||||
15 2 4
|
||||
16 2 5
|
||||
17 2 5
|
||||
18 2 5
|
||||
19 2 4
|
||||
20 2 3
|
||||
21 3 3
|
||||
22 3 4
|
||||
23 3 5
|
||||
24 3 5
|
||||
25 3 5
|
||||
26 3 4
|
||||
27 3 3
|
||||
28 4 3
|
||||
29 4 4
|
||||
30 4 5
|
||||
31 4 5
|
||||
32 4 5
|
||||
33 4 4
|
||||
34 4 3
|
||||
35 5 3
|
||||
36 5 4
|
||||
37 5 5
|
||||
38 5 5
|
||||
39 5 5
|
||||
40 5 4
|
||||
41 5 3
|
||||
42 6 3
|
||||
43 6 4
|
||||
44 6 5
|
||||
45 6 5
|
||||
46 6 5
|
||||
47 6 4
|
||||
48 6 3
|
||||
49 7 3
|
||||
50 7 4
|
||||
51 7 5
|
||||
52 7 5
|
||||
53 7 5
|
||||
54 7 4
|
||||
55 7 3
|
||||
56 8 3
|
||||
57 8 4
|
||||
58 8 5
|
||||
59 8 5
|
||||
60 8 5
|
||||
61 8 4
|
||||
62 8 3
|
||||
63 9 3
|
||||
64 9 4
|
||||
65 9 5
|
||||
66 9 5
|
||||
67 9 5
|
||||
68 9 4
|
||||
69 9 3
|
||||
70 10 1
|
||||
SELECT count(*) OVER (ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) FROM numbers(4);
|
||||
1
|
||||
2
|
||||
3
|
||||
3
|
||||
-- frame boundaries that runs into the partition end
|
||||
select
|
||||
count() over (partition by intDiv(number, 3)
|
||||
rows between 100 following and unbounded following),
|
||||
count() over (partition by intDiv(number, 3)
|
||||
rows between current row and 100 following)
|
||||
from numbers(10);
|
||||
0 3
|
||||
0 2
|
||||
0 1
|
||||
0 3
|
||||
0 2
|
||||
0 1
|
||||
0 3
|
||||
0 2
|
||||
0 1
|
||||
0 1
|
||||
-- seen a use-after-free under MSan in this query once
|
||||
SELECT number, max(number) OVER (PARTITION BY intDiv(number, 7) ORDER BY number ASC NULLS LAST ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) FROM numbers(1024) SETTINGS max_block_size = 2 FORMAT Null;
|
||||
-- a corner case
|
||||
|
@ -175,8 +175,24 @@ from (select number, intDiv(number, 5) p from numbers(31))
|
||||
order by p, number
|
||||
settings max_block_size = 2;
|
||||
|
||||
-- ROWS offset frame start and end
|
||||
select number, p,
|
||||
count(*) over (partition by p order by number
|
||||
rows between 2 preceding and 2 following)
|
||||
from (select number, intDiv(number, 7) p from numbers(71))
|
||||
order by p, number
|
||||
settings max_block_size = 2;
|
||||
|
||||
SELECT count(*) OVER (ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) FROM numbers(4);
|
||||
|
||||
-- frame boundaries that runs into the partition end
|
||||
select
|
||||
count() over (partition by intDiv(number, 3)
|
||||
rows between 100 following and unbounded following),
|
||||
count() over (partition by intDiv(number, 3)
|
||||
rows between current row and 100 following)
|
||||
from numbers(10);
|
||||
|
||||
-- seen a use-after-free under MSan in this query once
|
||||
SELECT number, max(number) OVER (PARTITION BY intDiv(number, 7) ORDER BY number ASC NULLS LAST ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) FROM numbers(1024) SETTINGS max_block_size = 2 FORMAT Null;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user