Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
bced9290
提交
bced9290
authored
1月 15, 2019
作者:
Evgenij Ryazanov
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Detect overflow in window frame bounds
上级
122fa953
隐藏空白字符变更
内嵌
并排
正在显示
2 个修改的文件
包含
118 行增加
和
34 行删除
+118
-34
WindowFrame.java
h2/src/main/org/h2/expression/analysis/WindowFrame.java
+92
-34
window.sql
h2/src/test/org/h2/test/scripts/window.sql
+26
-0
没有找到文件。
h2/src/main/org/h2/expression/analysis/WindowFrame.java
浏览文件 @
bced9290
...
@@ -10,10 +10,11 @@ import java.util.Collections;
...
@@ -10,10 +10,11 @@ import java.util.Collections;
import
java.util.Iterator
;
import
java.util.Iterator
;
import
java.util.NoSuchElementException
;
import
java.util.NoSuchElementException
;
import
org.h2.api.ErrorCode
;
import
org.h2.engine.Session
;
import
org.h2.engine.Session
;
import
org.h2.expression.BinaryOperation
;
import
org.h2.expression.BinaryOperation
;
import
org.h2.expression.Expression
;
import
org.h2.expression.BinaryOperation.OpType
;
import
org.h2.expression.BinaryOperation.OpType
;
import
org.h2.expression.Expression
;
import
org.h2.expression.ValueExpression
;
import
org.h2.expression.ValueExpression
;
import
org.h2.message.DbException
;
import
org.h2.message.DbException
;
import
org.h2.result.SortOrder
;
import
org.h2.result.SortOrder
;
...
@@ -297,14 +298,32 @@ public final class WindowFrame {
...
@@ -297,14 +298,32 @@ public final class WindowFrame {
return
value
;
return
value
;
}
}
/**
* Appends bound value to the current row and produces row for comparison
* operations.
*
* @param session
* the session
* @param orderedRows
* rows in partition
* @param sortOrder
* the sort order
* @param currentRow
* index of the current row
* @param bound
* window frame bound
* @param add
* false for PRECEDING, true for FOLLOWING
* @return row for comparison operations, or null if result is out of range
* and should be treated as UNLIMITED
*/
private
static
Value
[]
getCompareRow
(
Session
session
,
ArrayList
<
Value
[]>
orderedRows
,
SortOrder
sortOrder
,
private
static
Value
[]
getCompareRow
(
Session
session
,
ArrayList
<
Value
[]>
orderedRows
,
SortOrder
sortOrder
,
int
currentRow
,
WindowFrameBound
bound
,
boolean
add
)
{
int
currentRow
,
WindowFrameBound
bound
,
boolean
add
)
{
int
sortIndex
=
sortOrder
.
getQueryColumnIndexes
()[
0
];
int
sortIndex
=
sortOrder
.
getQueryColumnIndexes
()[
0
];
OpType
opType
=
add
^
(
sortOrder
.
getSortTypes
()[
0
]
&
SortOrder
.
DESCENDING
)
!=
0
?
OpType
.
PLUS
:
OpType
.
MINUS
;
Value
[]
row
=
orderedRows
.
get
(
currentRow
);
Value
[]
row
=
orderedRows
.
get
(
currentRow
);
Value
[]
newRow
=
row
.
clone
();
Value
currentValue
=
row
[
sortIndex
];
Value
currentValue
=
row
[
sortIndex
];
switch
(
currentValue
.
getType
())
{
int
type
=
currentValue
.
getType
();
switch
(
type
)
{
case
Value
.
BYTE
:
case
Value
.
BYTE
:
case
Value
.
SHORT
:
case
Value
.
SHORT
:
case
Value
.
INT
:
case
Value
.
INT
:
...
@@ -334,8 +353,20 @@ public final class WindowFrame {
...
@@ -334,8 +353,20 @@ public final class WindowFrame {
throw
DbException
.
getInvalidValueException
(
"ORDER BY value for RANGE frame"
,
currentValue
.
getTraceSQL
());
throw
DbException
.
getInvalidValueException
(
"ORDER BY value for RANGE frame"
,
currentValue
.
getTraceSQL
());
}
}
Value
range
=
getValueOffset
(
bound
,
orderedRows
.
get
(
currentRow
),
session
);
Value
range
=
getValueOffset
(
bound
,
orderedRows
.
get
(
currentRow
),
session
);
Value
newValue
=
new
BinaryOperation
(
opType
,
ValueExpression
.
get
(
currentValue
),
ValueExpression
.
get
(
range
))
OpType
opType
=
add
^
(
sortOrder
.
getSortTypes
()[
0
]
&
SortOrder
.
DESCENDING
)
!=
0
?
OpType
.
PLUS
:
OpType
.
MINUS
;
.
optimize
(
session
).
getValue
(
session
);
Value
newValue
;
try
{
newValue
=
new
BinaryOperation
(
opType
,
ValueExpression
.
get
(
currentValue
),
ValueExpression
.
get
(
range
))
.
optimize
(
session
).
getValue
(
session
).
convertTo
(
type
);
}
catch
(
DbException
ex
)
{
switch
(
ex
.
getErrorCode
())
{
case
ErrorCode
.
NUMERIC_VALUE_OUT_OF_RANGE_1
:
case
ErrorCode
.
NUMERIC_VALUE_OUT_OF_RANGE_2
:
return
null
;
}
throw
ex
;
}
Value
[]
newRow
=
row
.
clone
();
newRow
[
sortIndex
]
=
newValue
;
newRow
[
sortIndex
]
=
newValue
;
return
newRow
;
return
newRow
;
}
}
...
@@ -575,6 +606,25 @@ public final class WindowFrame {
...
@@ -575,6 +606,25 @@ public final class WindowFrame {
return
endIndex
;
return
endIndex
;
}
}
/**
* Returns starting or ending index of a window frame.
*
* @param session
* the session
* @param orderedRows
* rows in partition
* @param sortOrder
* the sort order
* @param currentRow
* index of the current row
* @param bound
* window frame bound
* @param forFollowing
* false for start index, true for end index
* @return starting or ending index of a window frame (inclusive), can be 0
* or be equal to the number of rows if frame is not limited from
* that side
*/
private
int
getIndex
(
Session
session
,
ArrayList
<
Value
[]>
orderedRows
,
SortOrder
sortOrder
,
int
currentRow
,
private
int
getIndex
(
Session
session
,
ArrayList
<
Value
[]>
orderedRows
,
SortOrder
sortOrder
,
int
currentRow
,
WindowFrameBound
bound
,
boolean
forFollowing
)
{
WindowFrameBound
bound
,
boolean
forFollowing
)
{
int
size
=
orderedRows
.
size
();
int
size
=
orderedRows
.
size
();
...
@@ -618,26 +668,30 @@ public final class WindowFrame {
...
@@ -618,26 +668,30 @@ public final class WindowFrame {
case
RANGE:
{
case
RANGE:
{
index
=
currentRow
;
index
=
currentRow
;
Value
[]
row
=
getCompareRow
(
session
,
orderedRows
,
sortOrder
,
index
,
bound
,
false
);
Value
[]
row
=
getCompareRow
(
session
,
orderedRows
,
sortOrder
,
index
,
bound
,
false
);
index
=
Collections
.
binarySearch
(
orderedRows
,
row
,
sortOrder
);
if
(
row
!=
null
)
{
if
(
index
>=
0
)
{
index
=
Collections
.
binarySearch
(
orderedRows
,
row
,
sortOrder
);
if
(!
forFollowing
)
{
if
(
index
>=
0
)
{
while
(
index
>
0
&&
sortOrder
.
compare
(
row
,
orderedRows
.
get
(
index
-
1
))
==
0
)
{
if
(!
forFollowing
)
{
index
--;
while
(
index
>
0
&&
sortOrder
.
compare
(
row
,
orderedRows
.
get
(
index
-
1
))
==
0
)
{
index
--;
}
}
else
{
while
(
index
<
last
&&
sortOrder
.
compare
(
row
,
orderedRows
.
get
(
index
+
1
))
==
0
)
{
index
++;
}
}
}
}
else
{
}
else
{
while
(
index
<
last
&&
sortOrder
.
compare
(
row
,
orderedRows
.
get
(
index
+
1
))
==
0
)
{
index
=
~
index
;
index
++;
if
(!
forFollowing
)
{
if
(
index
==
0
)
{
index
=
-
1
;
}
}
else
{
index
--;
}
}
}
}
}
else
{
}
else
{
index
=
~
index
;
index
=
-
1
;
if
(!
forFollowing
)
{
if
(
index
==
0
)
{
index
=
-
1
;
}
}
else
{
index
--;
}
}
}
break
;
break
;
}
}
...
@@ -694,24 +748,28 @@ public final class WindowFrame {
...
@@ -694,24 +748,28 @@ public final class WindowFrame {
case
RANGE:
{
case
RANGE:
{
index
=
currentRow
;
index
=
currentRow
;
Value
[]
row
=
getCompareRow
(
session
,
orderedRows
,
sortOrder
,
index
,
bound
,
true
);
Value
[]
row
=
getCompareRow
(
session
,
orderedRows
,
sortOrder
,
index
,
bound
,
true
);
index
=
Collections
.
binarySearch
(
orderedRows
,
row
,
sortOrder
);
if
(
row
!=
null
)
{
if
(
index
>=
0
)
{
index
=
Collections
.
binarySearch
(
orderedRows
,
row
,
sortOrder
);
if
(
forFollowing
)
{
if
(
index
>=
0
)
{
while
(
index
<
last
&&
sortOrder
.
compare
(
row
,
orderedRows
.
get
(
index
+
1
))
==
0
)
{
if
(
forFollowing
)
{
index
++;
while
(
index
<
last
&&
sortOrder
.
compare
(
row
,
orderedRows
.
get
(
index
+
1
))
==
0
)
{
index
++;
}
}
else
{
while
(
index
>
0
&&
sortOrder
.
compare
(
row
,
orderedRows
.
get
(
index
-
1
))
==
0
)
{
index
--;
}
}
}
}
else
{
}
else
{
while
(
index
>
0
&&
sortOrder
.
compare
(
row
,
orderedRows
.
get
(
index
-
1
))
==
0
)
{
index
=
~
index
;
index
--;
if
(
forFollowing
)
{
if
(
index
!=
size
)
{
index
--;
}
}
}
}
}
}
else
{
}
else
{
index
=
~
index
;
index
=
size
;
if
(
forFollowing
)
{
if
(
index
!=
size
)
{
index
--;
}
}
}
}
break
;
break
;
}
}
...
...
h2/src/test/org/h2/test/scripts/window.sql
浏览文件 @
bced9290
...
@@ -121,5 +121,31 @@ SELECT SUM(V) OVER (ORDER BY V RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING) FROM V
...
@@ -121,5 +121,31 @@ SELECT SUM(V) OVER (ORDER BY V RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING) FROM V
SELECT
SUM
(
V
)
OVER
(
ORDER
BY
V
RANGE
BETWEEN
1
PRECEDING
AND
1
FOLLOWING
)
FROM
VALUES
(
TRUE
)
T
(
V
);
SELECT
SUM
(
V
)
OVER
(
ORDER
BY
V
RANGE
BETWEEN
1
PRECEDING
AND
1
FOLLOWING
)
FROM
VALUES
(
TRUE
)
T
(
V
);
>
exception
INVALID_VALUE_2
>
exception
INVALID_VALUE_2
SELECT
SUM
(
ID
)
OVER
(
ORDER
BY
ID
RANGE
BETWEEN
10000000000
PRECEDING
AND
CURRENT
ROW
)
P
,
SUM
(
ID
)
OVER
(
ORDER
BY
ID
RANGE
BETWEEN
10000000001
PRECEDING
AND
10000000000
PRECEDING
)
P2
,
SUM
(
ID
)
OVER
(
ORDER
BY
ID
RANGE
BETWEEN
CURRENT
ROW
AND
2147483647
FOLLOWING
)
F
,
SUM
(
ID
)
OVER
(
ORDER
BY
ID
RANGE
BETWEEN
2147483647
FOLLOWING
AND
2147483648
FOLLOWING
)
F2
,
ID
FROM
TEST
ORDER
BY
ID
;
>
P
P2
F
F2
ID
>
-- ---- -- ---- --
>
1
null
63
null
1
>
3
null
62
null
2
>
7
null
60
null
4
>
15
null
56
null
8
>
31
null
48
null
16
>
63
null
32
null
32
>
rows
(
ordered
):
6
DROP
TABLE
TEST
;
DROP
TABLE
TEST
;
>
ok
>
ok
SELECT
ARRAY_AGG
(
T
)
OVER
(
ORDER
BY
T
RANGE
BETWEEN
INTERVAL
1
DAY
PRECEDING
AND
CURRENT
ROW
)
C
,
ARRAY_AGG
(
T
)
OVER
(
ORDER
BY
T
RANGE
BETWEEN
INTERVAL
2
HOUR
PRECEDING
AND
INTERVAL
1
HOUR
PRECEDING
)
P
,
T
FROM
VALUES
(
TIME
'00:00:00'
),
(
TIME
'01:30:00'
)
TEST
(
T
)
ORDER
BY
T
;
>
C
P
T
>
-------------------- ---------- --------
>
[
00
:
00
:
00
]
null
00
:
00
:
00
>
[
00
:
00
:
00
,
01
:
30
:
00
]
[
00
:
00
:
00
]
01
:
30
:
00
>
rows
(
ordered
):
2
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论