Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
aa3c98ba
提交
aa3c98ba
authored
1月 14, 2019
作者:
Evgenij Ryazanov
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Allow any expressions in window frames
上级
f27c631e
显示空白字符变更
内嵌
并排
正在显示
10 个修改的文件
包含
314 行增加
和
67 行删除
+314
-67
Parser.java
h2/src/main/org/h2/command/Parser.java
+2
-12
AbstractAggregate.java
...c/main/org/h2/expression/aggregate/AbstractAggregate.java
+6
-3
DataAnalysisOperation.java
...ain/org/h2/expression/analysis/DataAnalysisOperation.java
+92
-22
Window.java
h2/src/main/org/h2/expression/analysis/Window.java
+10
-1
WindowFrame.java
h2/src/main/org/h2/expression/analysis/WindowFrame.java
+95
-21
WindowFrameBound.java
h2/src/main/org/h2/expression/analysis/WindowFrameBound.java
+61
-1
WindowFunction.java
h2/src/main/org/h2/expression/analysis/WindowFunction.java
+7
-6
array-agg.sql
...est/org/h2/test/scripts/functions/aggregate/array-agg.sql
+18
-0
nth_value.sql
...c/test/org/h2/test/scripts/functions/window/nth_value.sql
+22
-0
dictionary.txt
h2/src/tools/org/h2/build/doc/dictionary.txt
+1
-1
没有找到文件。
h2/src/main/org/h2/command/Parser.java
浏览文件 @
aa3c98ba
...
...
@@ -3294,7 +3294,7 @@ public class Parser {
read
(
ROW
);
return
new
WindowFrameBound
(
WindowFrameBoundType
.
CURRENT_ROW
,
null
);
}
Expression
value
=
read
ValueOrParameter
();
Expression
value
=
read
Expression
();
read
(
"PRECEDING"
);
return
new
WindowFrameBound
(
WindowFrameBoundType
.
PRECEDING
,
value
);
}
...
...
@@ -3311,7 +3311,7 @@ public class Parser {
read
(
ROW
);
return
new
WindowFrameBound
(
WindowFrameBoundType
.
CURRENT_ROW
,
null
);
}
Expression
value
=
read
ValueOrParameter
();
Expression
value
=
read
Expression
();
if
(
readIf
(
"PRECEDING"
))
{
return
new
WindowFrameBound
(
WindowFrameBoundType
.
PRECEDING
,
value
);
}
...
...
@@ -3319,16 +3319,6 @@ public class Parser {
return
new
WindowFrameBound
(
WindowFrameBoundType
.
FOLLOWING
,
value
);
}
private
Expression
readValueOrParameter
()
{
int
index
=
parseIndex
;
Expression
value
=
readExpression
();
if
(!(
value
instanceof
ValueExpression
)
&&
!(
value
instanceof
Parameter
))
{
parseIndex
=
index
;
throw
getSyntaxError
();
}
return
value
;
}
private
AggregateType
getAggregateType
(
String
name
)
{
if
(!
identifiersToUpper
)
{
// if not yet converted to uppercase, do it now
...
...
h2/src/main/org/h2/expression/aggregate/AbstractAggregate.java
浏览文件 @
aa3c98ba
...
...
@@ -98,7 +98,9 @@ public abstract class AbstractAggregate extends DataAnalysisOperation {
aggregateFastPartition
(
session
,
result
,
ordered
,
rowIdColumn
,
grouped
);
return
;
}
if
(
frame
.
getExclusion
()
==
WindowFrameExclusion
.
EXCLUDE_NO_OTHERS
)
{
if
(
frame
.
isVariableBounds
())
{
grouped
=
false
;
}
else
if
(
frame
.
getExclusion
()
==
WindowFrameExclusion
.
EXCLUDE_NO_OTHERS
)
{
WindowFrameBound
following
=
frame
.
getFollowing
();
boolean
unboundedFollowing
=
following
!=
null
&&
following
.
getType
()
==
WindowFrameBoundType
.
UNBOUNDED_FOLLOWING
;
...
...
@@ -117,10 +119,11 @@ public abstract class AbstractAggregate extends DataAnalysisOperation {
}
// All other types of frames (slow)
int
size
=
ordered
.
size
();
int
frameParametersOffset
=
getWindowFrameParametersOffset
();
for
(
int
i
=
0
;
i
<
size
;)
{
Object
aggregateData
=
createAggregateData
();
for
(
Iterator
<
Value
[]>
iter
=
WindowFrame
.
iterator
(
over
,
session
,
ordered
,
getOverOrderBySort
(),
i
,
false
);
iter
.
hasNext
();)
{
for
(
Iterator
<
Value
[]>
iter
=
WindowFrame
.
iterator
(
over
,
session
,
ordered
,
getOverOrderBySort
(),
f
rameParametersOffset
,
i
,
f
alse
);
iter
.
hasNext
();)
{
updateFromExpressions
(
session
,
aggregateData
,
iter
.
next
());
}
Value
r
=
getAggregatedValue
(
session
,
aggregateData
);
...
...
h2/src/main/org/h2/expression/analysis/DataAnalysisOperation.java
浏览文件 @
aa3c98ba
...
...
@@ -59,14 +59,19 @@ public abstract class DataAnalysisOperation extends Expression {
*/
protected
SortOrder
overOrderBySort
;
private
int
numFrameExpressions
;
private
int
lastGroupRowId
;
/**
* Create sort order.
*
* @param session database session
* @param orderBy array of order by expressions
* @param offset index offset
* @param session
* database session
* @param orderBy
* array of order by expressions
* @param offset
* index offset
* @return the SortOrder
*/
protected
static
SortOrder
createOrder
(
Session
session
,
ArrayList
<
SelectOrderBy
>
orderBy
,
int
offset
)
{
...
...
@@ -131,9 +136,12 @@ public abstract class DataAnalysisOperation extends Expression {
/**
* Map the columns of the resolver to expression columns.
*
* @param resolver the column resolver
* @param level the subquery nesting level
* @param innerState one of the Expression MAP_IN_* values
* @param resolver
* the column resolver
* @param level
* the subquery nesting level
* @param innerState
* one of the Expression MAP_IN_* values
*/
protected
void
mapColumnsAnalysis
(
ColumnResolver
resolver
,
int
level
,
int
innerState
)
{
if
(
over
!=
null
)
{
...
...
@@ -151,6 +159,18 @@ public abstract class DataAnalysisOperation extends Expression {
}
else
if
(!
isAggregate
())
{
overOrderBySort
=
new
SortOrder
(
session
.
getDatabase
(),
new
int
[
getNumExpressions
()],
new
int
[
0
],
null
);
}
WindowFrame
frame
=
over
.
getWindowFrame
();
if
(
frame
!=
null
)
{
int
n
=
0
;
if
(
frame
.
getStarting
().
isVariable
())
{
n
++;
}
WindowFrameBound
following
=
frame
.
getFollowing
();
if
(
following
!=
null
&&
following
.
isVariable
())
{
n
++;
}
numFrameExpressions
=
n
;
}
}
return
this
;
}
...
...
@@ -200,9 +220,12 @@ public abstract class DataAnalysisOperation extends Expression {
/**
* Update a row of an aggregate.
*
* @param session the database session
* @param groupData data for the aggregate group
* @param groupRowId row id of group
* @param session
* the database session
* @param groupData
* data for the aggregate group
* @param groupRowId
* row id of group
*/
protected
abstract
void
updateAggregate
(
Session
session
,
SelectGroups
groupData
,
int
groupRowId
);
...
...
@@ -222,12 +245,21 @@ public abstract class DataAnalysisOperation extends Expression {
}
/**
* Returns the number of expressions, excluding
FILTER and OVER clauses
.
* Returns the number of expressions, excluding
OVER clause
.
*
* @return the number of expressions
*/
protected
abstract
int
getNumExpressions
();
/**
* Returns the number of window frame expressions.
*
* @return the number of window frame expressions
*/
private
int
getNumFrameExpressions
()
{
return
numFrameExpressions
;
}
/**
* Stores current values of expressions into the specified array.
*
...
...
@@ -241,9 +273,12 @@ public abstract class DataAnalysisOperation extends Expression {
/**
* Get the aggregate data for a window clause.
*
* @param session database session
* @param groupData aggregate group data
* @param forOrderBy true if this is for ORDER BY
* @param session
* database session
* @param groupData
* aggregate group data
* @param forOrderBy
* true if this is for ORDER BY
* @return the aggregate data object, specific to each kind of aggregate.
*/
protected
Object
getWindowData
(
Session
session
,
SelectGroups
groupData
,
boolean
forOrderBy
)
{
...
...
@@ -261,9 +296,12 @@ public abstract class DataAnalysisOperation extends Expression {
/**
* Get the aggregate group data object from the collector object.
* @param groupData the collector object
* @param ifExists if true, return null if object not found,
* if false, return new object if nothing found
*
* @param groupData
* the collector object
* @param ifExists
* if true, return null if object not found, if false, return new
* object if nothing found
* @return group data object
*/
protected
Object
getGroupData
(
SelectGroups
groupData
,
boolean
ifExists
)
{
...
...
@@ -320,6 +358,20 @@ public abstract class DataAnalysisOperation extends Expression {
:
getWindowResult
(
session
,
groupData
);
}
/**
* Returns offset of window frame parameters.
*
* @return offset of window frame parameters
*/
protected
final
int
getWindowFrameParametersOffset
()
{
int
frameParametersOffset
=
getNumExpressions
();
ArrayList
<
SelectOrderBy
>
orderBy
=
over
.
getOrderBy
();
if
(
orderBy
!=
null
)
{
frameParametersOffset
+=
orderBy
.
size
();
}
return
frameParametersOffset
;
}
/**
* Returns result of this window function or window aggregate. This method
* is not used for plain aggregates.
...
...
@@ -374,22 +426,38 @@ public abstract class DataAnalysisOperation extends Expression {
/**
* Update a row of an ordered aggregate.
*
* @param session the database session
* @param groupData data for the aggregate group
* @param groupRowId row id of group
* @param orderBy list of order by expressions
* @param session
* the database session
* @param groupData
* data for the aggregate group
* @param groupRowId
* row id of group
* @param orderBy
* list of order by expressions
*/
protected
void
updateOrderedAggregate
(
Session
session
,
SelectGroups
groupData
,
int
groupRowId
,
ArrayList
<
SelectOrderBy
>
orderBy
)
{
int
ne
=
getNumExpressions
();
int
size
=
orderBy
!=
null
?
orderBy
.
size
()
:
0
;
Value
[]
array
=
new
Value
[
ne
+
size
+
1
];
int
frameSize
=
getNumFrameExpressions
();
Value
[]
array
=
new
Value
[
ne
+
size
+
frameSize
+
1
];
rememberExpressions
(
session
,
array
);
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
@SuppressWarnings
(
"null"
)
SelectOrderBy
o
=
orderBy
.
get
(
i
);
array
[
ne
++]
=
o
.
expression
.
getValue
(
session
);
}
if
(
frameSize
>
0
)
{
WindowFrame
frame
=
over
.
getWindowFrame
();
WindowFrameBound
bound
=
frame
.
getStarting
();
if
(
bound
.
isVariable
())
{
array
[
ne
++]
=
bound
.
getValue
().
getValue
(
session
);
}
bound
=
frame
.
getFollowing
();
if
(
bound
!=
null
&&
bound
.
isVariable
())
{
array
[
ne
++]
=
bound
.
getValue
().
getValue
(
session
);
}
}
array
[
ne
]
=
ValueInt
.
get
(
groupRowId
);
@SuppressWarnings
(
"unchecked"
)
ArrayList
<
Value
[]>
data
=
(
ArrayList
<
Value
[]>)
getWindowData
(
session
,
groupData
,
true
);
...
...
@@ -408,6 +476,7 @@ public abstract class DataAnalysisOperation extends Expression {
rowIdColumn
+=
orderBy
.
size
();
Collections
.
sort
(
orderedData
,
overOrderBySort
);
}
rowIdColumn
+=
getNumFrameExpressions
();
getOrderedResultLoop
(
session
,
result
,
orderedData
,
rowIdColumn
);
partition
.
setOrderedResult
(
result
);
}
...
...
@@ -433,7 +502,8 @@ public abstract class DataAnalysisOperation extends Expression {
/**
* Used to create SQL for the OVER and FILTER clauses.
*
* @param builder string builder
* @param builder
* string builder
* @return the builder object
*/
protected
StringBuilder
appendTailConditions
(
StringBuilder
builder
)
{
...
...
h2/src/main/org/h2/expression/analysis/Window.java
浏览文件 @
aa3c98ba
...
...
@@ -66,7 +66,7 @@ public final class Window {
* @param orderBy
* ORDER BY clause, or null
* @param frame
* window frame clause
* window frame clause
, or null
*/
public
Window
(
String
parent
,
ArrayList
<
Expression
>
partitionBy
,
ArrayList
<
SelectOrderBy
>
orderBy
,
WindowFrame
frame
)
{
...
...
@@ -97,6 +97,9 @@ public final class Window {
o
.
expression
.
mapColumns
(
resolver
,
level
,
Expression
.
MAP_IN_WINDOW
);
}
}
if
(
frame
!=
null
)
{
frame
.
mapColumns
(
resolver
,
level
,
Expression
.
MAP_IN_WINDOW
);
}
}
private
void
resolveWindows
(
ColumnResolver
resolver
)
{
...
...
@@ -136,6 +139,9 @@ public final class Window {
o
.
expression
=
o
.
expression
.
optimize
(
session
);
}
}
if
(
frame
!=
null
)
{
frame
.
optimize
(
session
);
}
}
/**
...
...
@@ -253,6 +259,9 @@ public final class Window {
o
.
expression
.
updateAggregate
(
session
,
stage
);
}
}
if
(
frame
!=
null
)
{
frame
.
updateAggregate
(
session
,
stage
);
}
}
@Override
...
...
h2/src/main/org/h2/expression/analysis/WindowFrame.java
浏览文件 @
aa3c98ba
...
...
@@ -12,10 +12,12 @@ import java.util.NoSuchElementException;
import
org.h2.engine.Session
;
import
org.h2.expression.BinaryOperation
;
import
org.h2.expression.Expression
;
import
org.h2.expression.BinaryOperation.OpType
;
import
org.h2.expression.ValueExpression
;
import
org.h2.message.DbException
;
import
org.h2.result.SortOrder
;
import
org.h2.table.ColumnResolver
;
import
org.h2.value.Value
;
/**
...
...
@@ -200,18 +202,19 @@ public final class WindowFrame {
* ordered rows
* @param sortOrder
* sort order
* @param frameParametersOffset
* offset of window frame parameters
* @param currentRow
* index of the current row
* @param reverse
* whether iterator should iterate in reverse order
*
* @return iterator
*/
public
static
Iterator
<
Value
[]>
iterator
(
Window
over
,
Session
session
,
ArrayList
<
Value
[]>
orderedRows
,
SortOrder
sortOrder
,
int
currentRow
,
boolean
reverse
)
{
SortOrder
sortOrder
,
int
frameParametersOffset
,
int
currentRow
,
boolean
reverse
)
{
WindowFrame
frame
=
over
.
getWindowFrame
();
if
(
frame
!=
null
)
{
return
frame
.
iterator
(
session
,
orderedRows
,
sortOrder
,
currentRow
,
reverse
);
return
frame
.
iterator
(
session
,
orderedRows
,
sortOrder
,
frameParametersOffset
,
currentRow
,
reverse
);
}
int
endIndex
=
orderedRows
.
size
()
-
1
;
return
plainIterator
(
orderedRows
,
0
,
...
...
@@ -286,8 +289,9 @@ public final class WindowFrame {
return
offset
;
}
private
static
int
getIntOffset
(
WindowFrameBound
bound
,
Session
session
)
{
int
value
=
bound
.
getValue
().
getValue
(
session
).
getInt
();
private
static
int
getIntOffset
(
WindowFrameBound
bound
,
Value
[]
values
,
int
parameterOffset
,
Session
session
)
{
Value
v
=
bound
.
isVariable
()
?
values
[
parameterOffset
]
:
bound
.
getValue
().
getValue
(
session
);
int
value
=
v
.
getInt
();
if
(
value
<
0
)
{
throw
DbException
.
getInvalidValueException
(
"unsigned"
,
value
);
}
...
...
@@ -295,19 +299,20 @@ public final class WindowFrame {
}
private
static
Value
[]
getCompareRow
(
Session
session
,
ArrayList
<
Value
[]>
orderedRows
,
SortOrder
sortOrder
,
int
currentRow
,
WindowFrameBound
bound
,
boolean
add
)
{
int
currentRow
,
WindowFrameBound
bound
,
int
parameterOffset
,
boolean
add
)
{
int
sortIndex
=
sortOrder
.
getQueryColumnIndexes
()[
0
];
OpType
opType
=
add
^
(
sortOrder
.
getSortTypes
()[
0
]
&
SortOrder
.
DESCENDING
)
!=
0
?
OpType
.
PLUS
:
OpType
.
MINUS
;
Value
[]
row
=
orderedRows
.
get
(
currentRow
);
Value
[]
newRow
=
row
.
clone
();
newRow
[
sortIndex
]
=
new
BinaryOperation
(
opType
,
//
ValueExpression
.
get
(
row
[
sortIndex
]),
ValueExpression
.
get
(
getValueOffset
(
bound
,
session
)))
//
ValueExpression
.
get
(
row
[
sortIndex
]),
ValueExpression
.
get
(
getValueOffset
(
bound
,
orderedRows
.
get
(
currentRow
),
parameterOffset
,
session
)))
.
optimize
(
session
).
getValue
(
session
);
return
newRow
;
}
private
static
Value
getValueOffset
(
WindowFrameBound
bound
,
Session
session
)
{
Value
value
=
bound
.
getValue
().
getValue
(
session
);
private
static
Value
getValueOffset
(
WindowFrameBound
bound
,
Value
[]
values
,
int
parameterOffset
,
Session
session
)
{
Value
value
=
bound
.
isVariable
()
?
values
[
parameterOffset
]
:
bound
.
getValue
().
getValue
(
session
);
if
(
value
.
getSignum
()
<
0
)
{
throw
DbException
.
getInvalidValueException
(
"unsigned"
,
value
.
getTraceSQL
());
}
...
...
@@ -385,6 +390,68 @@ public final class WindowFrame {
&&
s
.
compareTo
(
f
)
<=
0
;
}
/**
* Check if bounds of this frame has variable expressions. This method may
* be used only after {@link #optimize(Session)} invocation.
*
* @return if bounds of this frame has variable expressions
*/
public
boolean
isVariableBounds
()
{
if
(
starting
.
isVariable
())
{
return
true
;
}
if
(
following
!=
null
&&
following
.
isVariable
())
{
return
true
;
}
return
false
;
}
/**
* Map the columns of the resolver to expression columns.
*
* @param resolver
* the column resolver
* @param level
* the subquery nesting level
* @param state
* current state for nesting checks
*/
void
mapColumns
(
ColumnResolver
resolver
,
int
level
,
int
state
)
{
starting
.
mapColumns
(
resolver
,
level
,
state
);
if
(
following
!=
null
)
{
following
.
mapColumns
(
resolver
,
level
,
state
);
}
}
/**
* Try to optimize bound expressions.
*
* @param session
* the session
*/
void
optimize
(
Session
session
)
{
starting
.
optimize
(
session
);
if
(
following
!=
null
)
{
following
.
optimize
(
session
);
}
}
/**
* Update an aggregate value.
*
* @param session
* the session
* @param stage
* select stage
* @see Expression#updateAggregate(Session, int)
*/
void
updateAggregate
(
Session
session
,
int
stage
)
{
starting
.
updateAggregate
(
session
,
stage
);
if
(
following
!=
null
)
{
following
.
updateAggregate
(
session
,
stage
);
}
}
/**
* Returns iterator.
*
...
...
@@ -394,6 +461,8 @@ public final class WindowFrame {
* ordered rows
* @param sortOrder
* sort order
* @param frameParametersOffset
* offset of window frame parameters
* @param currentRow
* index of the current row
* @param reverse
...
...
@@ -401,9 +470,14 @@ public final class WindowFrame {
* @return iterator
*/
public
Iterator
<
Value
[]>
iterator
(
Session
session
,
ArrayList
<
Value
[]>
orderedRows
,
SortOrder
sortOrder
,
int
currentRow
,
boolean
reverse
)
{
int
startIndex
=
getIndex
(
session
,
orderedRows
,
sortOrder
,
currentRow
,
starting
,
false
);
int
endIndex
=
following
!=
null
?
getIndex
(
session
,
orderedRows
,
sortOrder
,
currentRow
,
following
,
true
)
int
frameParametersOffset
,
int
currentRow
,
boolean
reverse
)
{
int
followingOffset
=
frameParametersOffset
;
if
(
starting
.
isVariable
())
{
followingOffset
++;
}
int
startIndex
=
getIndex
(
session
,
orderedRows
,
sortOrder
,
currentRow
,
starting
,
frameParametersOffset
,
false
);
int
endIndex
=
following
!=
null
?
getIndex
(
session
,
orderedRows
,
sortOrder
,
currentRow
,
following
,
followingOffset
,
true
)
:
units
==
WindowFrameUnits
.
ROWS
?
currentRow
:
toGroupEnd
(
orderedRows
,
sortOrder
,
currentRow
,
orderedRows
.
size
()
-
1
);
if
(
endIndex
<
startIndex
)
{
...
...
@@ -443,7 +517,7 @@ public final class WindowFrame {
if
(
exclusion
!=
WindowFrameExclusion
.
EXCLUDE_NO_OTHERS
)
{
throw
new
UnsupportedOperationException
();
}
int
startIndex
=
getIndex
(
session
,
orderedRows
,
sortOrder
,
currentRow
,
starting
,
false
);
int
startIndex
=
getIndex
(
session
,
orderedRows
,
sortOrder
,
currentRow
,
starting
,
-
1
,
false
);
if
(
startIndex
<
0
)
{
startIndex
=
0
;
}
...
...
@@ -469,7 +543,7 @@ public final class WindowFrame {
if
(
exclusion
!=
WindowFrameExclusion
.
EXCLUDE_NO_OTHERS
)
{
throw
new
UnsupportedOperationException
();
}
int
endIndex
=
following
!=
null
?
getIndex
(
session
,
orderedRows
,
sortOrder
,
currentRow
,
following
,
true
)
int
endIndex
=
following
!=
null
?
getIndex
(
session
,
orderedRows
,
sortOrder
,
currentRow
,
following
,
-
1
,
true
)
:
units
==
WindowFrameUnits
.
ROWS
?
currentRow
:
toGroupEnd
(
orderedRows
,
sortOrder
,
currentRow
,
orderedRows
.
size
()
-
1
);
int
size
=
orderedRows
.
size
();
...
...
@@ -480,7 +554,7 @@ public final class WindowFrame {
}
private
int
getIndex
(
Session
session
,
ArrayList
<
Value
[]>
orderedRows
,
SortOrder
sortOrder
,
int
currentRow
,
WindowFrameBound
bound
,
boolean
forFollowing
)
{
WindowFrameBound
bound
,
int
parameterOffset
,
boolean
forFollowing
)
{
int
size
=
orderedRows
.
size
();
int
last
=
size
-
1
;
int
index
;
...
...
@@ -491,12 +565,12 @@ public final class WindowFrame {
case
PRECEDING:
switch
(
units
)
{
case
ROWS:
{
int
value
=
getIntOffset
(
bound
,
session
);
int
value
=
getIntOffset
(
bound
,
orderedRows
.
get
(
currentRow
),
parameterOffset
,
session
);
index
=
value
>
currentRow
?
-
1
:
currentRow
-
value
;
break
;
}
case
GROUPS:
{
int
value
=
getIntOffset
(
bound
,
session
);
int
value
=
getIntOffset
(
bound
,
orderedRows
.
get
(
currentRow
),
parameterOffset
,
session
);
if
(!
forFollowing
)
{
index
=
toGroupStart
(
orderedRows
,
sortOrder
,
currentRow
,
0
);
while
(
value
>
0
&&
index
>
0
)
{
...
...
@@ -521,7 +595,7 @@ public final class WindowFrame {
}
case
RANGE:
{
index
=
currentRow
;
Value
[]
row
=
getCompareRow
(
session
,
orderedRows
,
sortOrder
,
index
,
bound
,
false
);
Value
[]
row
=
getCompareRow
(
session
,
orderedRows
,
sortOrder
,
index
,
bound
,
parameterOffset
,
false
);
index
=
Collections
.
binarySearch
(
orderedRows
,
row
,
sortOrder
);
if
(
index
>=
0
)
{
if
(!
forFollowing
)
{
...
...
@@ -566,13 +640,13 @@ public final class WindowFrame {
case
FOLLOWING:
switch
(
units
)
{
case
ROWS:
{
int
value
=
getIntOffset
(
bound
,
session
);
int
value
=
getIntOffset
(
bound
,
orderedRows
.
get
(
currentRow
),
parameterOffset
,
session
);
int
rem
=
last
-
currentRow
;
index
=
value
>
rem
?
size
:
currentRow
+
value
;
break
;
}
case
GROUPS:
{
int
value
=
getIntOffset
(
bound
,
session
);
int
value
=
getIntOffset
(
bound
,
orderedRows
.
get
(
currentRow
),
parameterOffset
,
session
);
if
(
forFollowing
)
{
index
=
toGroupEnd
(
orderedRows
,
sortOrder
,
currentRow
,
last
);
while
(
value
>
0
&&
index
<
last
)
{
...
...
@@ -597,7 +671,7 @@ public final class WindowFrame {
}
case
RANGE:
{
index
=
currentRow
;
Value
[]
row
=
getCompareRow
(
session
,
orderedRows
,
sortOrder
,
index
,
bound
,
true
);
Value
[]
row
=
getCompareRow
(
session
,
orderedRows
,
sortOrder
,
index
,
bound
,
parameterOffset
,
true
);
index
=
Collections
.
binarySearch
(
orderedRows
,
row
,
sortOrder
);
if
(
index
>=
0
)
{
if
(
forFollowing
)
{
...
...
h2/src/main/org/h2/expression/analysis/WindowFrameBound.java
浏览文件 @
aa3c98ba
...
...
@@ -5,7 +5,9 @@
*/
package
org
.
h2
.
expression
.
analysis
;
import
org.h2.engine.Session
;
import
org.h2.expression.Expression
;
import
org.h2.table.ColumnResolver
;
/**
* Window frame bound.
...
...
@@ -14,7 +16,9 @@ public class WindowFrameBound {
private
final
WindowFrameBoundType
type
;
private
final
Expression
value
;
private
Expression
value
;
private
boolean
isVariable
;
/**
* Creates new instance of window frame bound.
...
...
@@ -51,6 +55,62 @@ public class WindowFrameBound {
return
value
;
}
/**
* Returns whether bound is defined with a variable. This method may be used
* only after {@link #optimize(Session)} invocation.
*
* @return whether bound is defined with a variable
*/
public
boolean
isVariable
()
{
return
isVariable
;
}
/**
* Map the columns of the resolver to expression columns.
*
* @param resolver
* the column resolver
* @param level
* the subquery nesting level
* @param state
* current state for nesting checks
*/
void
mapColumns
(
ColumnResolver
resolver
,
int
level
,
int
state
)
{
if
(
value
!=
null
)
{
value
.
mapColumns
(
resolver
,
level
,
state
);
}
}
/**
* Try to optimize bound expression.
*
* @param session
* the session
*/
void
optimize
(
Session
session
)
{
if
(
value
!=
null
)
{
value
=
value
.
optimize
(
session
);
if
(!
value
.
isConstant
())
{
isVariable
=
true
;
}
}
}
/**
* Update an aggregate value.
*
* @param session
* the session
* @param stage
* select stage
* @see Expression#updateAggregate(Session, int)
*/
void
updateAggregate
(
Session
session
,
int
stage
)
{
if
(
value
!=
null
)
{
value
.
updateAggregate
(
session
,
stage
);
}
}
/**
* Appends SQL representation to the specified builder.
*
...
...
h2/src/main/org/h2/expression/analysis/WindowFunction.java
浏览文件 @
aa3c98ba
...
...
@@ -349,18 +349,19 @@ public class WindowFunction extends DataAnalysisOperation {
private
void
getNth
(
Session
session
,
HashMap
<
Integer
,
Value
>
result
,
ArrayList
<
Value
[]>
ordered
,
int
rowIdColumn
)
{
int
size
=
ordered
.
size
();
int
frameParametersOffset
=
getWindowFrameParametersOffset
();
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
Value
[]
row
=
ordered
.
get
(
i
);
int
rowId
=
row
[
rowIdColumn
].
getInt
();
Value
v
;
switch
(
type
)
{
case
FIRST_VALUE:
v
=
getNthValue
(
WindowFrame
.
iterator
(
over
,
session
,
ordered
,
getOverOrderBySort
(),
i
,
false
),
0
,
ignoreNulls
);
v
=
getNthValue
(
WindowFrame
.
iterator
(
over
,
session
,
ordered
,
getOverOrderBySort
(),
frameParametersOffset
,
i
,
false
),
0
,
ignoreNulls
);
break
;
case
LAST_VALUE:
v
=
getNthValue
(
WindowFrame
.
iterator
(
over
,
session
,
ordered
,
getOverOrderBySort
(),
i
,
true
),
0
,
ignoreNulls
);
v
=
getNthValue
(
WindowFrame
.
iterator
(
over
,
session
,
ordered
,
getOverOrderBySort
(),
frameParametersOffset
,
i
,
true
),
0
,
ignoreNulls
);
break
;
case
NTH_VALUE:
{
int
n
=
row
[
1
].
getInt
();
...
...
@@ -368,8 +369,8 @@ public class WindowFunction extends DataAnalysisOperation {
throw
DbException
.
getInvalidValueException
(
"nth row"
,
n
);
}
n
--;
Iterator
<
Value
[]>
iter
=
WindowFrame
.
iterator
(
over
,
session
,
ordered
,
getOverOrderBySort
(),
i
,
fromLast
);
Iterator
<
Value
[]>
iter
=
WindowFrame
.
iterator
(
over
,
session
,
ordered
,
getOverOrderBySort
(),
fr
ameParametersOffset
,
i
,
fr
omLast
);
v
=
getNthValue
(
iter
,
n
,
ignoreNulls
);
break
;
}
...
...
h2/src/test/org/h2/test/scripts/functions/aggregate/array-agg.sql
浏览文件 @
aa3c98ba
...
...
@@ -596,5 +596,23 @@ SELECT ID, VALUE,
>
8
4
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
]
[
8
]
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
]
[
7
,
8
]
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
]
[
7
,
8
]
>
rows
:
8
SELECT
ID
,
VALUE
,
ARRAY_AGG
(
ID
ORDER
BY
ID
)
OVER
(
ORDER
BY
ID
RANGE
BETWEEN
UNBOUNDED
PRECEDING
AND
VALUE
FOLLOWING
)
RG
,
ARRAY_AGG
(
ID
ORDER
BY
ID
)
OVER
(
ORDER
BY
ID
RANGE
BETWEEN
VALUE
PRECEDING
AND
UNBOUNDED
FOLLOWING
)
RGR
,
ARRAY_AGG
(
ID
ORDER
BY
ID
)
OVER
(
ORDER
BY
ID
ROWS
BETWEEN
UNBOUNDED
PRECEDING
AND
VALUE
FOLLOWING
)
R
,
ARRAY_AGG
(
ID
ORDER
BY
ID
)
OVER
(
ORDER
BY
ID
ROWS
BETWEEN
VALUE
PRECEDING
AND
UNBOUNDED
FOLLOWING
)
RR
FROM
TEST
;
>
ID
VALUE
RG
RGR
R
RR
>
-- ----- ------------------------ ------------------------ ------------------------ ------------------------
>
1
1
[
1
,
2
]
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
]
[
1
,
2
]
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
]
>
2
1
[
1
,
2
,
3
]
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
]
[
1
,
2
,
3
]
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
]
>
3
2
[
1
,
2
,
3
,
4
,
5
]
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
]
[
1
,
2
,
3
,
4
,
5
]
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
]
>
4
2
[
1
,
2
,
3
,
4
,
5
,
6
]
[
2
,
3
,
4
,
5
,
6
,
7
,
8
]
[
1
,
2
,
3
,
4
,
5
,
6
]
[
2
,
3
,
4
,
5
,
6
,
7
,
8
]
>
5
3
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
]
[
2
,
3
,
4
,
5
,
6
,
7
,
8
]
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
]
[
2
,
3
,
4
,
5
,
6
,
7
,
8
]
>
6
3
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
]
[
3
,
4
,
5
,
6
,
7
,
8
]
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
]
[
3
,
4
,
5
,
6
,
7
,
8
]
>
7
4
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
]
[
3
,
4
,
5
,
6
,
7
,
8
]
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
]
[
3
,
4
,
5
,
6
,
7
,
8
]
>
8
4
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
]
[
4
,
5
,
6
,
7
,
8
]
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
]
[
4
,
5
,
6
,
7
,
8
]
>
rows
:
8
DROP
TABLE
TEST
;
>
ok
h2/src/test/org/h2/test/scripts/functions/window/nth_value.sql
浏览文件 @
aa3c98ba
...
...
@@ -218,6 +218,28 @@ SELECT ID, CATEGORY,
>
13
4
1
1
1
2
3
4
>
rows
(
ordered
):
13
SELECT
ID
,
CATEGORY
,
FIRST_VALUE
(
ID
)
OVER
(
ORDER
BY
ID
ROWS
BETWEEN
CATEGORY
FOLLOWING
AND
UNBOUNDED
FOLLOWING
)
F
,
LAST_VALUE
(
ID
)
OVER
(
ORDER
BY
ID
ROWS
BETWEEN
CURRENT
ROW
AND
CATEGORY
FOLLOWING
)
L
,
NTH_VALUE
(
ID
,
2
)
OVER
(
ORDER
BY
ID
ROWS
BETWEEN
CATEGORY
FOLLOWING
AND
UNBOUNDED
FOLLOWING
)
N
FROM
TEST
ORDER
BY
ID
;
>
ID
CATEGORY
F
L
N
>
-- -------- ---- -- ----
>
1
1
2
2
3
>
2
1
3
3
4
>
3
1
4
4
5
>
4
1
5
5
6
>
5
1
6
6
7
>
6
1
7
7
8
>
7
2
9
9
10
>
8
2
10
10
11
>
9
3
12
12
13
>
10
3
13
13
null
>
11
3
null
13
null
>
12
4
null
13
null
>
13
4
null
13
null
>
rows
(
ordered
):
13
DROP
TABLE
TEST
;
>
ok
...
...
h2/src/tools/org/h2/build/doc/dictionary.txt
浏览文件 @
aa3c98ba
...
...
@@ -805,4 +805,4 @@ queryparser tokenized freeze factorings recompilation unenclosed rfe dsync
econd irst bcef ordinality nord unnest
analyst occupation distributive josaph aor engineer sajeewa isuru randil kevin doctor businessman artist ashan
corrupts splitted disruption unintentional octets preconditions predicates subq objectweb insn opcodes
preserves masking holder unboxing avert iae transformed subtle reevaluate exclusions subclause ftbl
preserves masking holder unboxing avert iae transformed subtle reevaluate exclusions subclause ftbl
rgr
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论