Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
2dot5
ClickHouse
提交
4bb38f33
C
ClickHouse
项目概览
2dot5
/
ClickHouse
通知
3
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
C
ClickHouse
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
4bb38f33
编写于
2月 05, 2021
作者:
A
Alexander Kuzmenkov
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
some simple cases
上级
6824f13a
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
204 addition
and
34 deletion
+204
-34
src/Processors/Transforms/WindowTransform.cpp
src/Processors/Transforms/WindowTransform.cpp
+102
-30
src/Processors/Transforms/WindowTransform.h
src/Processors/Transforms/WindowTransform.h
+11
-4
tests/queries/0_stateless/01591_window_functions.reference
tests/queries/0_stateless/01591_window_functions.reference
+62
-0
tests/queries/0_stateless/01591_window_functions.sql
tests/queries/0_stateless/01591_window_functions.sql
+29
-0
未找到文件。
src/Processors/Transforms/WindowTransform.cpp
浏览文件 @
4bb38f33
...
...
@@ -63,6 +63,35 @@ 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.
if
(
window_description
.
frame
.
type
==
WindowFrame
::
FrameType
::
Range
&&
window_description
.
order_by
.
size
()
==
1
&&
window_description
.
order_by
[
0
].
direction
<
0
)
{
throw
Exception
(
ErrorCodes
::
NOT_IMPLEMENTED
,
"ORDER BY DESC for RANGE 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
()
...
...
@@ -290,21 +319,16 @@ void WindowTransform::advanceFrameStartRowsOffset()
assert
(
offset_left
>=
0
);
}
// Compares ORDER BY column values at given rows to find the boundaries of frame:
// [compared] with [reference] +/- offset. Return value is -1/0/+1, like in
// sorting predicates -- -1 means [compared] is less than [reference] +/- offset.
template
<
typename
ColumnType
>
static
bool
isBeforeFrameStar
t
(
const
ColumnType
*
compared_column
,
static
int
compareValuesWithOffse
t
(
const
ColumnType
*
compared_column
,
size_t
compared_row
,
const
ColumnType
*
reference_column
,
size_t
reference_row
,
typename
ColumnType
::
ValueType
offset
,
bool
is_preceding
)
typename
ColumnType
::
ValueType
offset
,
bool
offset_is_preceding
)
{
// The frame is [[current_row] + begin_offset, [current_row] + end_offset]
// We need to return "is to the left of frame", that is,
// [tested_row] < [current_row] + begin_offset
// 1) right side overflows to positive, the condition is
// false.
// 2) [frame_start] + begin_offset overflows to negative, the condition is
// false.
// 3) no overflows, perform the comparison normally
const
auto
compared_value_data
=
compared_column
->
getDataAt
(
compared_row
);
assert
(
compared_value_data
.
size
==
sizeof
(
typename
ColumnType
::
ValueType
));
auto
compared_value
=
unalignedLoad
<
typename
ColumnType
::
ValueType
>
(
...
...
@@ -317,20 +341,14 @@ static bool isBeforeFrameStart(const ColumnType * compared_column,
bool
is_overflow
;
bool
overflow_to_negative
;
if
(
is_preceding
)
if
(
offset_
is_preceding
)
{
// The frame start is ref] - offset, inclusive. We answer
// "is compared row to the left of the frame?", i.e.
// [compared] < [ref] - offset.
is_overflow
=
__builtin_sub_overflow
(
reference_value
,
offset
,
&
reference_value
);
overflow_to_negative
=
offset
>
0
;
}
else
{
// The frame start is [ref] + offset, inclusive. We answer
// "is compared row to the left of the frame?", i.e.
// [compared] < [ref] + offset.
is_overflow
=
__builtin_add_overflow
(
reference_value
,
offset
,
&
reference_value
);
overflow_to_negative
=
offset
<
0
;
...
...
@@ -347,41 +365,39 @@ static bool isBeforeFrameStart(const ColumnType * compared_column,
if
(
overflow_to_negative
)
{
// Overflow to the negative, [compared] must be greater.
return
false
;
return
1
;
}
else
{
// Overflow to the positive, [compared] must be less.
return
true
;
return
-
1
;
}
}
else
{
// No overflow, compare normally.
return
compared_value
<
reference_value
;
return
compared_value
<
reference_value
?
-
1
:
compared_value
==
reference_value
?
0
:
1
;
}
}
template
<
typename
ColumnType
>
void
WindowTransform
::
advanceFrameStartRangeOffset
()
{
// [frame_start] + begin_offset < [current_row]
// 1) [frame_start] + begin_offset overflows to positive, the condition is
// false.
// 2) [frame_start] + begin_offset overflows to negative, the condition is
// false.
// 3) no overflows, perform the comparison normally
const
int
direction
=
window_description
.
order_by
[
0
].
direction
;
const
auto
*
reference_column
=
assert_cast
<
const
ColumnType
*>
(
inputAt
(
current_row
)[
order_by_indices
[
0
]].
get
());
for
(;
frame_start
<
partition_end
;
advanceRowNumber
(
frame_start
))
{
// The first frame value is [current_row] with offset, so we advance
// while [frames_start] < [current_row] with offset.
const
auto
*
compared_column
=
assert_cast
<
const
ColumnType
*>
(
inputAt
(
frame_start
)[
order_by_indices
[
0
]].
get
());
if
(
!
isBeforeFrameStar
t
(
compared_column
,
frame_start
.
row
,
if
(
compareValuesWithOffse
t
(
compared_column
,
frame_start
.
row
,
reference_column
,
current_row
.
row
,
window_description
.
frame
.
begin_offset
,
window_description
.
frame
.
begin_preceding
))
window_description
.
frame
.
begin_preceding
)
*
direction
>=
0
)
{
frame_started
=
true
;
return
;
...
...
@@ -401,6 +417,10 @@ void WindowTransform::advanceFrameStartRangeOffsetDispatch()
{
advanceFrameStartRangeOffset
<
ColumnVector
<
UInt8
>>
();
}
else
if
(
typeid_cast
<
const
ColumnVector
<
Int8
>
*>
(
column
))
{
advanceFrameStartRangeOffset
<
ColumnVector
<
Int8
>>
();
}
else
{
throw
Exception
(
ErrorCodes
::
NOT_IMPLEMENTED
,
...
...
@@ -621,6 +641,55 @@ void WindowTransform::advanceFrameEndRowsOffset()
assert
(
offset_left
>=
0
);
}
template
<
typename
ColumnType
>
void
WindowTransform
::
advanceFrameEndRangeOffset
()
{
const
int
direction
=
window_description
.
order_by
[
0
].
direction
;
const
auto
*
reference_column
=
assert_cast
<
const
ColumnType
*>
(
inputAt
(
current_row
)[
order_by_indices
[
0
]].
get
());
for
(;
frame_end
<
partition_end
;
advanceRowNumber
(
frame_end
))
{
// The last frame value is current_row with offset, and we need a
// past-the-end pointer, so we advance while
// [frame_end] <= [current_row] with offset.
const
auto
*
compared_column
=
assert_cast
<
const
ColumnType
*>
(
inputAt
(
frame_end
)[
order_by_indices
[
0
]].
get
());
if
(
compareValuesWithOffset
(
compared_column
,
frame_end
.
row
,
reference_column
,
current_row
.
row
,
window_description
.
frame
.
end_offset
,
window_description
.
frame
.
end_preceding
)
*
direction
>
0
)
{
frame_ended
=
true
;
return
;
}
}
frame_ended
=
partition_ended
;
}
void
WindowTransform
::
advanceFrameEndRangeOffsetDispatch
()
{
// 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
))
{
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
()));
}
}
void
WindowTransform
::
advanceFrameEnd
()
{
// No reason for this function to be called again after it succeeded.
...
...
@@ -642,6 +711,9 @@ void WindowTransform::advanceFrameEnd()
case
WindowFrame
::
FrameType
::
Rows
:
advanceFrameEndRowsOffset
();
break
;
case
WindowFrame
::
FrameType
::
Range
:
advanceFrameEndRangeOffsetDispatch
();
break
;
default:
throw
Exception
(
ErrorCodes
::
NOT_IMPLEMENTED
,
"The frame end type '{}' is not implemented"
,
...
...
src/Processors/Transforms/WindowTransform.h
浏览文件 @
4bb38f33
...
...
@@ -106,16 +106,23 @@ public:
private:
void
advancePartitionEnd
();
void
advanceFrameStart
();
bool
arePeers
(
const
RowNumber
&
x
,
const
RowNumber
&
y
)
const
;
void
advanceFrameStartRowsOffset
();
void
advanceFrameStartRangeOffsetDispatch
();
template
<
typename
T
>
template
<
typename
ColumnType
>
void
advanceFrameStartRangeOffset
();
void
advanceFrameStart
();
void
advanceFrameEndRowsOffset
();
void
advanceFrameEndCurrentRow
();
void
advanceFrameEndUnbounded
();
void
advanceFrameEndRowsOffset
();
void
advanceFrameEnd
();
bool
arePeers
(
const
RowNumber
&
x
,
const
RowNumber
&
y
)
const
;
void
advanceFrameEndRangeOffsetDispatch
();
template
<
typename
ColumnType
>
void
advanceFrameEndRangeOffset
();
void
updateAggregationState
();
void
writeOutCurrentRow
();
...
...
tests/queries/0_stateless/01591_window_functions.reference
浏览文件 @
4bb38f33
...
...
@@ -709,3 +709,65 @@ from numbers(3);
1 3
1 3
1 3
-- RANGE OFFSET
-- a basic RANGE OFFSET frame
select x, min(x) over w, max(x) over w, count(x) over w from (
select toUInt8(number) x from numbers(11))
window w as (order by x asc range between 1 preceding and 2 following)
order by x;
0 0 2 3
1 0 3 4
2 1 4 4
3 2 5 4
4 3 6 4
5 4 7 4
6 5 8 4
7 6 9 4
8 7 10 4
9 8 10 3
10 9 10 2
-- overflow conditions
select x, min(x) over w, max(x) over w, count(x) over w
from (
select toUInt8(if(mod(number, 2),
toInt64(255 - intDiv(number, 2)),
toInt64(intDiv(number, 2)))) x
from numbers(10)
)
window w as (order by x range between 1 preceding and 2 following)
order by x;
0 0 2 3
1 0 3 4
2 1 4 4
3 2 4 3
4 3 4 2
251 251 253 3
252 251 254 4
253 252 255 4
254 253 255 3
255 254 255 2
select x, min(x) over w, max(x) over w, count(x) over w
from (
select toInt8(multiIf(
mod(number, 3) == 0, toInt64(intDiv(number, 3)),
mod(number, 3) == 1, toInt64(127 - intDiv(number, 3)),
toInt64(-128 + intDiv(number, 3)))) x
from numbers(15)
)
window w as (order by x range between 1 preceding and 2 following)
order by x;
-128 -128 -126 3
-127 -128 -125 4
-126 -127 -124 4
-125 -126 -124 3
-124 -125 -124 2
0 0 2 3
1 0 3 4
2 1 4 4
3 2 4 3
4 3 4 2
123 123 125 3
124 123 126 4
125 124 127 4
126 125 127 3
127 126 127 2
tests/queries/0_stateless/01591_window_functions.sql
浏览文件 @
4bb38f33
...
...
@@ -212,3 +212,32 @@ select
count
(
*
)
over
(
rows
between
current
row
and
current
row
),
count
(
*
)
over
(
range
between
current
row
and
current
row
)
from
numbers
(
3
);
-- RANGE OFFSET
-- a basic RANGE OFFSET frame
select
x
,
min
(
x
)
over
w
,
max
(
x
)
over
w
,
count
(
x
)
over
w
from
(
select
toUInt8
(
number
)
x
from
numbers
(
11
))
window
w
as
(
order
by
x
asc
range
between
1
preceding
and
2
following
)
order
by
x
;
-- overflow conditions
select
x
,
min
(
x
)
over
w
,
max
(
x
)
over
w
,
count
(
x
)
over
w
from
(
select
toUInt8
(
if
(
mod
(
number
,
2
),
toInt64
(
255
-
intDiv
(
number
,
2
)),
toInt64
(
intDiv
(
number
,
2
))))
x
from
numbers
(
10
)
)
window
w
as
(
order
by
x
range
between
1
preceding
and
2
following
)
order
by
x
;
select
x
,
min
(
x
)
over
w
,
max
(
x
)
over
w
,
count
(
x
)
over
w
from
(
select
toInt8
(
multiIf
(
mod
(
number
,
3
)
==
0
,
toInt64
(
intDiv
(
number
,
3
)),
mod
(
number
,
3
)
==
1
,
toInt64
(
127
-
intDiv
(
number
,
3
)),
toInt64
(
-
128
+
intDiv
(
number
,
3
))))
x
from
numbers
(
15
)
)
window
w
as
(
order
by
x
range
between
1
preceding
and
2
following
)
order
by
x
;
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录