Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
a092ef8b
Unverified
提交
a092ef8b
authored
1月 14, 2019
作者:
Evgenij Ryazanov
提交者:
GitHub
1月 14, 2019
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #1664 from katzyn/window
Allow any expressions in window frames
上级
f27c631e
f49e90a9
隐藏空白字符变更
内嵌
并排
正在显示
11 个修改的文件
包含
361 行增加
和
50 行删除
+361
-50
help.csv
h2/src/docsrc/help/help.csv
+2
-2
changelog.html
h2/src/docsrc/html/changelog.html
+2
-0
Parser.java
h2/src/main/org/h2/command/Parser.java
+2
-12
AbstractAggregate.java
...c/main/org/h2/expression/aggregate/AbstractAggregate.java
+32
-1
DataAnalysisOperation.java
...ain/org/h2/expression/analysis/DataAnalysisOperation.java
+85
-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
+75
-10
WindowFrameBound.java
h2/src/main/org/h2/expression/analysis/WindowFrameBound.java
+82
-1
array-agg.sql
...est/org/h2/test/scripts/functions/aggregate/array-agg.sql
+38
-0
nth_value.sql
...c/test/org/h2/test/scripts/functions/window/nth_value.sql
+32
-0
dictionary.txt
h2/src/tools/org/h2/build/doc/dictionary.txt
+1
-1
没有找到文件。
h2/src/docsrc/help/help.csv
浏览文件 @
a092ef8b
...
@@ -2709,7 +2709,7 @@ ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE TIES
...
@@ -2709,7 +2709,7 @@ ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE TIES
UNBOUNDED PRECEDING|value PRECEDING|CURRENT ROW
UNBOUNDED PRECEDING|value PRECEDING|CURRENT ROW
","
","
A window frame preceding clause.
A window frame preceding clause.
If value is specified it should
be non-negative value or parameter
.
If value is specified it should
not be negative
.
","
","
UNBOUNDED PRECEDING
UNBOUNDED PRECEDING
1 PRECEDING
1 PRECEDING
...
@@ -2721,7 +2721,7 @@ UNBOUNDED PRECEDING|value PRECEDING|CURRENT ROW
...
@@ -2721,7 +2721,7 @@ UNBOUNDED PRECEDING|value PRECEDING|CURRENT ROW
|value FOLLOWING|UNBOUNDED FOLLOWING
|value FOLLOWING|UNBOUNDED FOLLOWING
","
","
A window frame bound clause.
A window frame bound clause.
If value is specified it should
be non-negative value or parameter
.
If value is specified it should
not be negative
.
","
","
UNBOUNDED PRECEDING
UNBOUNDED PRECEDING
UNBOUNDED FOLLOWING
UNBOUNDED FOLLOWING
...
...
h2/src/docsrc/html/changelog.html
浏览文件 @
a092ef8b
...
@@ -21,6 +21,8 @@ Change Log
...
@@ -21,6 +21,8 @@ Change Log
<h2>
Next Version (unreleased)
</h2>
<h2>
Next Version (unreleased)
</h2>
<ul>
<ul>
<li>
PR #1664: Allow any expressions in window frames
</li>
<li>
Issue #1576: H2 Console should not display precision and scale for data types that don't have them
<li>
Issue #1576: H2 Console should not display precision and scale for data types that don't have them
</li>
</li>
<li>
PR #1662: Fix Alter Table Drop Column In View when table name is wrapped by Double Quotes
<li>
PR #1662: Fix Alter Table Drop Column In View when table name is wrapped by Double Quotes
...
...
h2/src/main/org/h2/command/Parser.java
浏览文件 @
a092ef8b
...
@@ -3294,7 +3294,7 @@ public class Parser {
...
@@ -3294,7 +3294,7 @@ public class Parser {
read
(
ROW
);
read
(
ROW
);
return
new
WindowFrameBound
(
WindowFrameBoundType
.
CURRENT_ROW
,
null
);
return
new
WindowFrameBound
(
WindowFrameBoundType
.
CURRENT_ROW
,
null
);
}
}
Expression
value
=
read
ValueOrParameter
();
Expression
value
=
read
Expression
();
read
(
"PRECEDING"
);
read
(
"PRECEDING"
);
return
new
WindowFrameBound
(
WindowFrameBoundType
.
PRECEDING
,
value
);
return
new
WindowFrameBound
(
WindowFrameBoundType
.
PRECEDING
,
value
);
}
}
...
@@ -3311,7 +3311,7 @@ public class Parser {
...
@@ -3311,7 +3311,7 @@ public class Parser {
read
(
ROW
);
read
(
ROW
);
return
new
WindowFrameBound
(
WindowFrameBoundType
.
CURRENT_ROW
,
null
);
return
new
WindowFrameBound
(
WindowFrameBoundType
.
CURRENT_ROW
,
null
);
}
}
Expression
value
=
read
ValueOrParameter
();
Expression
value
=
read
Expression
();
if
(
readIf
(
"PRECEDING"
))
{
if
(
readIf
(
"PRECEDING"
))
{
return
new
WindowFrameBound
(
WindowFrameBoundType
.
PRECEDING
,
value
);
return
new
WindowFrameBound
(
WindowFrameBoundType
.
PRECEDING
,
value
);
}
}
...
@@ -3319,16 +3319,6 @@ public class Parser {
...
@@ -3319,16 +3319,6 @@ public class Parser {
return
new
WindowFrameBound
(
WindowFrameBoundType
.
FOLLOWING
,
value
);
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
)
{
private
AggregateType
getAggregateType
(
String
name
)
{
if
(!
identifiersToUpper
)
{
if
(!
identifiersToUpper
)
{
// if not yet converted to uppercase, do it now
// if not yet converted to uppercase, do it now
...
...
h2/src/main/org/h2/expression/aggregate/AbstractAggregate.java
浏览文件 @
a092ef8b
...
@@ -98,7 +98,13 @@ public abstract class AbstractAggregate extends DataAnalysisOperation {
...
@@ -98,7 +98,13 @@ public abstract class AbstractAggregate extends DataAnalysisOperation {
aggregateFastPartition
(
session
,
result
,
ordered
,
rowIdColumn
,
grouped
);
aggregateFastPartition
(
session
,
result
,
ordered
,
rowIdColumn
,
grouped
);
return
;
return
;
}
}
if
(
frame
.
getExclusion
()
==
WindowFrameExclusion
.
EXCLUDE_NO_OTHERS
)
{
boolean
variableBounds
=
frame
.
isVariableBounds
();
if
(
variableBounds
)
{
variableBounds
=
checkVariableBounds
(
frame
,
ordered
);
}
if
(
variableBounds
)
{
grouped
=
false
;
}
else
if
(
frame
.
getExclusion
()
==
WindowFrameExclusion
.
EXCLUDE_NO_OTHERS
)
{
WindowFrameBound
following
=
frame
.
getFollowing
();
WindowFrameBound
following
=
frame
.
getFollowing
();
boolean
unboundedFollowing
=
following
!=
null
boolean
unboundedFollowing
=
following
!=
null
&&
following
.
getType
()
==
WindowFrameBoundType
.
UNBOUNDED_FOLLOWING
;
&&
following
.
getType
()
==
WindowFrameBoundType
.
UNBOUNDED_FOLLOWING
;
...
@@ -128,6 +134,31 @@ public abstract class AbstractAggregate extends DataAnalysisOperation {
...
@@ -128,6 +134,31 @@ public abstract class AbstractAggregate extends DataAnalysisOperation {
}
}
}
}
private
static
boolean
checkVariableBounds
(
WindowFrame
frame
,
ArrayList
<
Value
[]>
ordered
)
{
int
size
=
ordered
.
size
();
WindowFrameBound
bound
=
frame
.
getStarting
();
if
(
bound
.
isVariable
())
{
int
offset
=
bound
.
getExpressionIndex
();
Value
v
=
ordered
.
get
(
0
)[
offset
];
for
(
int
i
=
1
;
i
<
size
;
i
++)
{
if
(!
v
.
equals
(
ordered
.
get
(
i
)[
offset
]))
{
return
true
;
}
}
}
bound
=
frame
.
getFollowing
();
if
(
bound
!=
null
&&
bound
.
isVariable
())
{
int
offset
=
bound
.
getExpressionIndex
();
Value
v
=
ordered
.
get
(
0
)[
offset
];
for
(
int
i
=
1
;
i
<
size
;
i
++)
{
if
(!
v
.
equals
(
ordered
.
get
(
i
)[
offset
]))
{
return
true
;
}
}
}
return
false
;
}
private
void
aggregateFastPartition
(
Session
session
,
HashMap
<
Integer
,
Value
>
result
,
ArrayList
<
Value
[]>
ordered
,
private
void
aggregateFastPartition
(
Session
session
,
HashMap
<
Integer
,
Value
>
result
,
ArrayList
<
Value
[]>
ordered
,
int
rowIdColumn
,
boolean
grouped
)
{
int
rowIdColumn
,
boolean
grouped
)
{
Object
aggregateData
=
createAggregateData
();
Object
aggregateData
=
createAggregateData
();
...
...
h2/src/main/org/h2/expression/analysis/DataAnalysisOperation.java
浏览文件 @
a092ef8b
...
@@ -59,14 +59,19 @@ public abstract class DataAnalysisOperation extends Expression {
...
@@ -59,14 +59,19 @@ public abstract class DataAnalysisOperation extends Expression {
*/
*/
protected
SortOrder
overOrderBySort
;
protected
SortOrder
overOrderBySort
;
private
int
numFrameExpressions
;
private
int
lastGroupRowId
;
private
int
lastGroupRowId
;
/**
/**
* Create sort order.
* Create sort order.
*
*
* @param session database session
* @param session
* @param orderBy array of order by expressions
* database session
* @param offset index offset
* @param orderBy
* array of order by expressions
* @param offset
* index offset
* @return the SortOrder
* @return the SortOrder
*/
*/
protected
static
SortOrder
createOrder
(
Session
session
,
ArrayList
<
SelectOrderBy
>
orderBy
,
int
offset
)
{
protected
static
SortOrder
createOrder
(
Session
session
,
ArrayList
<
SelectOrderBy
>
orderBy
,
int
offset
)
{
...
@@ -131,9 +136,12 @@ public abstract class DataAnalysisOperation extends Expression {
...
@@ -131,9 +136,12 @@ public abstract class DataAnalysisOperation extends Expression {
/**
/**
* Map the columns of the resolver to expression columns.
* Map the columns of the resolver to expression columns.
*
*
* @param resolver the column resolver
* @param resolver
* @param level the subquery nesting level
* the column resolver
* @param innerState one of the Expression MAP_IN_* values
* @param level
* the subquery nesting level
* @param innerState
* one of the Expression MAP_IN_* values
*/
*/
protected
void
mapColumnsAnalysis
(
ColumnResolver
resolver
,
int
level
,
int
innerState
)
{
protected
void
mapColumnsAnalysis
(
ColumnResolver
resolver
,
int
level
,
int
innerState
)
{
if
(
over
!=
null
)
{
if
(
over
!=
null
)
{
...
@@ -151,6 +159,25 @@ public abstract class DataAnalysisOperation extends Expression {
...
@@ -151,6 +159,25 @@ public abstract class DataAnalysisOperation extends Expression {
}
else
if
(!
isAggregate
())
{
}
else
if
(!
isAggregate
())
{
overOrderBySort
=
new
SortOrder
(
session
.
getDatabase
(),
new
int
[
getNumExpressions
()],
new
int
[
0
],
null
);
overOrderBySort
=
new
SortOrder
(
session
.
getDatabase
(),
new
int
[
getNumExpressions
()],
new
int
[
0
],
null
);
}
}
WindowFrame
frame
=
over
.
getWindowFrame
();
if
(
frame
!=
null
)
{
int
index
=
getNumExpressions
();
if
(
orderBy
!=
null
)
{
index
+=
orderBy
.
size
();
}
int
n
=
0
;
WindowFrameBound
bound
=
frame
.
getStarting
();
if
(
bound
.
isVariable
())
{
bound
.
setExpressionIndex
(
index
);
n
++;
}
bound
=
frame
.
getFollowing
();
if
(
bound
!=
null
&&
bound
.
isVariable
())
{
bound
.
setExpressionIndex
(
index
+
n
);
n
++;
}
numFrameExpressions
=
n
;
}
}
}
return
this
;
return
this
;
}
}
...
@@ -200,9 +227,12 @@ public abstract class DataAnalysisOperation extends Expression {
...
@@ -200,9 +227,12 @@ public abstract class DataAnalysisOperation extends Expression {
/**
/**
* Update a row of an aggregate.
* Update a row of an aggregate.
*
*
* @param session the database session
* @param session
* @param groupData data for the aggregate group
* the database session
* @param groupRowId row id of group
* @param groupData
* data for the aggregate group
* @param groupRowId
* row id of group
*/
*/
protected
abstract
void
updateAggregate
(
Session
session
,
SelectGroups
groupData
,
int
groupRowId
);
protected
abstract
void
updateAggregate
(
Session
session
,
SelectGroups
groupData
,
int
groupRowId
);
...
@@ -222,12 +252,21 @@ public abstract class DataAnalysisOperation extends Expression {
...
@@ -222,12 +252,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
* @return the number of expressions
*/
*/
protected
abstract
int
getNumExpressions
();
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.
* Stores current values of expressions into the specified array.
*
*
...
@@ -241,9 +280,12 @@ public abstract class DataAnalysisOperation extends Expression {
...
@@ -241,9 +280,12 @@ public abstract class DataAnalysisOperation extends Expression {
/**
/**
* Get the aggregate data for a window clause.
* Get the aggregate data for a window clause.
*
*
* @param session database session
* @param session
* @param groupData aggregate group data
* database session
* @param forOrderBy true if this is for ORDER BY
* @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.
* @return the aggregate data object, specific to each kind of aggregate.
*/
*/
protected
Object
getWindowData
(
Session
session
,
SelectGroups
groupData
,
boolean
forOrderBy
)
{
protected
Object
getWindowData
(
Session
session
,
SelectGroups
groupData
,
boolean
forOrderBy
)
{
...
@@ -261,9 +303,12 @@ public abstract class DataAnalysisOperation extends Expression {
...
@@ -261,9 +303,12 @@ public abstract class DataAnalysisOperation extends Expression {
/**
/**
* Get the aggregate group data object from the collector object.
* 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,
* @param groupData
* if false, return new object if nothing found
* 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
* @return group data object
*/
*/
protected
Object
getGroupData
(
SelectGroups
groupData
,
boolean
ifExists
)
{
protected
Object
getGroupData
(
SelectGroups
groupData
,
boolean
ifExists
)
{
...
@@ -374,22 +419,38 @@ public abstract class DataAnalysisOperation extends Expression {
...
@@ -374,22 +419,38 @@ public abstract class DataAnalysisOperation extends Expression {
/**
/**
* Update a row of an ordered aggregate.
* Update a row of an ordered aggregate.
*
*
* @param session the database session
* @param session
* @param groupData data for the aggregate group
* the database session
* @param groupRowId row id of group
* @param groupData
* @param orderBy list of order by expressions
* 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
,
protected
void
updateOrderedAggregate
(
Session
session
,
SelectGroups
groupData
,
int
groupRowId
,
ArrayList
<
SelectOrderBy
>
orderBy
)
{
ArrayList
<
SelectOrderBy
>
orderBy
)
{
int
ne
=
getNumExpressions
();
int
ne
=
getNumExpressions
();
int
size
=
orderBy
!=
null
?
orderBy
.
size
()
:
0
;
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
);
rememberExpressions
(
session
,
array
);
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
@SuppressWarnings
(
"null"
)
@SuppressWarnings
(
"null"
)
SelectOrderBy
o
=
orderBy
.
get
(
i
);
SelectOrderBy
o
=
orderBy
.
get
(
i
);
array
[
ne
++]
=
o
.
expression
.
getValue
(
session
);
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
);
array
[
ne
]
=
ValueInt
.
get
(
groupRowId
);
@SuppressWarnings
(
"unchecked"
)
@SuppressWarnings
(
"unchecked"
)
ArrayList
<
Value
[]>
data
=
(
ArrayList
<
Value
[]>)
getWindowData
(
session
,
groupData
,
true
);
ArrayList
<
Value
[]>
data
=
(
ArrayList
<
Value
[]>)
getWindowData
(
session
,
groupData
,
true
);
...
@@ -408,6 +469,7 @@ public abstract class DataAnalysisOperation extends Expression {
...
@@ -408,6 +469,7 @@ public abstract class DataAnalysisOperation extends Expression {
rowIdColumn
+=
orderBy
.
size
();
rowIdColumn
+=
orderBy
.
size
();
Collections
.
sort
(
orderedData
,
overOrderBySort
);
Collections
.
sort
(
orderedData
,
overOrderBySort
);
}
}
rowIdColumn
+=
getNumFrameExpressions
();
getOrderedResultLoop
(
session
,
result
,
orderedData
,
rowIdColumn
);
getOrderedResultLoop
(
session
,
result
,
orderedData
,
rowIdColumn
);
partition
.
setOrderedResult
(
result
);
partition
.
setOrderedResult
(
result
);
}
}
...
@@ -433,7 +495,8 @@ public abstract class DataAnalysisOperation extends Expression {
...
@@ -433,7 +495,8 @@ public abstract class DataAnalysisOperation extends Expression {
/**
/**
* Used to create SQL for the OVER and FILTER clauses.
* Used to create SQL for the OVER and FILTER clauses.
*
*
* @param builder string builder
* @param builder
* string builder
* @return the builder object
* @return the builder object
*/
*/
protected
StringBuilder
appendTailConditions
(
StringBuilder
builder
)
{
protected
StringBuilder
appendTailConditions
(
StringBuilder
builder
)
{
...
...
h2/src/main/org/h2/expression/analysis/Window.java
浏览文件 @
a092ef8b
...
@@ -66,7 +66,7 @@ public final class Window {
...
@@ -66,7 +66,7 @@ public final class Window {
* @param orderBy
* @param orderBy
* ORDER BY clause, or null
* ORDER BY clause, or null
* @param frame
* @param frame
* window frame clause
* window frame clause
, or null
*/
*/
public
Window
(
String
parent
,
ArrayList
<
Expression
>
partitionBy
,
ArrayList
<
SelectOrderBy
>
orderBy
,
public
Window
(
String
parent
,
ArrayList
<
Expression
>
partitionBy
,
ArrayList
<
SelectOrderBy
>
orderBy
,
WindowFrame
frame
)
{
WindowFrame
frame
)
{
...
@@ -97,6 +97,9 @@ public final class Window {
...
@@ -97,6 +97,9 @@ public final class Window {
o
.
expression
.
mapColumns
(
resolver
,
level
,
Expression
.
MAP_IN_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
)
{
private
void
resolveWindows
(
ColumnResolver
resolver
)
{
...
@@ -136,6 +139,9 @@ public final class Window {
...
@@ -136,6 +139,9 @@ public final class Window {
o
.
expression
=
o
.
expression
.
optimize
(
session
);
o
.
expression
=
o
.
expression
.
optimize
(
session
);
}
}
}
}
if
(
frame
!=
null
)
{
frame
.
optimize
(
session
);
}
}
}
/**
/**
...
@@ -253,6 +259,9 @@ public final class Window {
...
@@ -253,6 +259,9 @@ public final class Window {
o
.
expression
.
updateAggregate
(
session
,
stage
);
o
.
expression
.
updateAggregate
(
session
,
stage
);
}
}
}
}
if
(
frame
!=
null
)
{
frame
.
updateAggregate
(
session
,
stage
);
}
}
}
@Override
@Override
...
...
h2/src/main/org/h2/expression/analysis/WindowFrame.java
浏览文件 @
a092ef8b
...
@@ -12,10 +12,12 @@ import java.util.NoSuchElementException;
...
@@ -12,10 +12,12 @@ import java.util.NoSuchElementException;
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.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
;
import
org.h2.table.ColumnResolver
;
import
org.h2.value.Value
;
import
org.h2.value.Value
;
/**
/**
...
@@ -204,7 +206,6 @@ public final class WindowFrame {
...
@@ -204,7 +206,6 @@ public final class WindowFrame {
* index of the current row
* index of the current row
* @param reverse
* @param reverse
* whether iterator should iterate in reverse order
* whether iterator should iterate in reverse order
*
* @return iterator
* @return iterator
*/
*/
public
static
Iterator
<
Value
[]>
iterator
(
Window
over
,
Session
session
,
ArrayList
<
Value
[]>
orderedRows
,
public
static
Iterator
<
Value
[]>
iterator
(
Window
over
,
Session
session
,
ArrayList
<
Value
[]>
orderedRows
,
...
@@ -286,8 +287,9 @@ public final class WindowFrame {
...
@@ -286,8 +287,9 @@ public final class WindowFrame {
return
offset
;
return
offset
;
}
}
private
static
int
getIntOffset
(
WindowFrameBound
bound
,
Session
session
)
{
private
static
int
getIntOffset
(
WindowFrameBound
bound
,
Value
[]
values
,
Session
session
)
{
int
value
=
bound
.
getValue
().
getValue
(
session
).
getInt
();
Value
v
=
bound
.
isVariable
()
?
values
[
bound
.
getExpressionIndex
()]
:
bound
.
getValue
().
getValue
(
session
);
int
value
=
v
.
getInt
();
if
(
value
<
0
)
{
if
(
value
<
0
)
{
throw
DbException
.
getInvalidValueException
(
"unsigned"
,
value
);
throw
DbException
.
getInvalidValueException
(
"unsigned"
,
value
);
}
}
...
@@ -301,13 +303,14 @@ public final class WindowFrame {
...
@@ -301,13 +303,14 @@ public final class WindowFrame {
Value
[]
row
=
orderedRows
.
get
(
currentRow
);
Value
[]
row
=
orderedRows
.
get
(
currentRow
);
Value
[]
newRow
=
row
.
clone
();
Value
[]
newRow
=
row
.
clone
();
newRow
[
sortIndex
]
=
new
BinaryOperation
(
opType
,
//
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
),
session
)))
//
.
optimize
(
session
).
getValue
(
session
);
.
optimize
(
session
).
getValue
(
session
);
return
newRow
;
return
newRow
;
}
}
private
static
Value
getValueOffset
(
WindowFrameBound
bound
,
Session
session
)
{
private
static
Value
getValueOffset
(
WindowFrameBound
bound
,
Value
[]
values
,
Session
session
)
{
Value
value
=
bound
.
getValue
().
getValue
(
session
);
Value
value
=
bound
.
isVariable
()
?
values
[
bound
.
getExpressionIndex
()]
:
bound
.
getValue
().
getValue
(
session
);
if
(
value
.
getSignum
()
<
0
)
{
if
(
value
.
getSignum
()
<
0
)
{
throw
DbException
.
getInvalidValueException
(
"unsigned"
,
value
.
getTraceSQL
());
throw
DbException
.
getInvalidValueException
(
"unsigned"
,
value
.
getTraceSQL
());
}
}
...
@@ -385,6 +388,68 @@ public final class WindowFrame {
...
@@ -385,6 +388,68 @@ public final class WindowFrame {
&&
s
.
compareTo
(
f
)
<=
0
;
&&
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.
* Returns iterator.
*
*
...
@@ -491,12 +556,12 @@ public final class WindowFrame {
...
@@ -491,12 +556,12 @@ public final class WindowFrame {
case
PRECEDING:
case
PRECEDING:
switch
(
units
)
{
switch
(
units
)
{
case
ROWS:
{
case
ROWS:
{
int
value
=
getIntOffset
(
bound
,
session
);
int
value
=
getIntOffset
(
bound
,
orderedRows
.
get
(
currentRow
),
session
);
index
=
value
>
currentRow
?
-
1
:
currentRow
-
value
;
index
=
value
>
currentRow
?
-
1
:
currentRow
-
value
;
break
;
break
;
}
}
case
GROUPS:
{
case
GROUPS:
{
int
value
=
getIntOffset
(
bound
,
session
);
int
value
=
getIntOffset
(
bound
,
orderedRows
.
get
(
currentRow
),
session
);
if
(!
forFollowing
)
{
if
(!
forFollowing
)
{
index
=
toGroupStart
(
orderedRows
,
sortOrder
,
currentRow
,
0
);
index
=
toGroupStart
(
orderedRows
,
sortOrder
,
currentRow
,
0
);
while
(
value
>
0
&&
index
>
0
)
{
while
(
value
>
0
&&
index
>
0
)
{
...
@@ -566,13 +631,13 @@ public final class WindowFrame {
...
@@ -566,13 +631,13 @@ public final class WindowFrame {
case
FOLLOWING:
case
FOLLOWING:
switch
(
units
)
{
switch
(
units
)
{
case
ROWS:
{
case
ROWS:
{
int
value
=
getIntOffset
(
bound
,
session
);
int
value
=
getIntOffset
(
bound
,
orderedRows
.
get
(
currentRow
),
session
);
int
rem
=
last
-
currentRow
;
int
rem
=
last
-
currentRow
;
index
=
value
>
rem
?
size
:
currentRow
+
value
;
index
=
value
>
rem
?
size
:
currentRow
+
value
;
break
;
break
;
}
}
case
GROUPS:
{
case
GROUPS:
{
int
value
=
getIntOffset
(
bound
,
session
);
int
value
=
getIntOffset
(
bound
,
orderedRows
.
get
(
currentRow
),
session
);
if
(
forFollowing
)
{
if
(
forFollowing
)
{
index
=
toGroupEnd
(
orderedRows
,
sortOrder
,
currentRow
,
last
);
index
=
toGroupEnd
(
orderedRows
,
sortOrder
,
currentRow
,
last
);
while
(
value
>
0
&&
index
<
last
)
{
while
(
value
>
0
&&
index
<
last
)
{
...
...
h2/src/main/org/h2/expression/analysis/WindowFrameBound.java
浏览文件 @
a092ef8b
...
@@ -5,7 +5,9 @@
...
@@ -5,7 +5,9 @@
*/
*/
package
org
.
h2
.
expression
.
analysis
;
package
org
.
h2
.
expression
.
analysis
;
import
org.h2.engine.Session
;
import
org.h2.expression.Expression
;
import
org.h2.expression.Expression
;
import
org.h2.table.ColumnResolver
;
/**
/**
* Window frame bound.
* Window frame bound.
...
@@ -14,7 +16,11 @@ public class WindowFrameBound {
...
@@ -14,7 +16,11 @@ public class WindowFrameBound {
private
final
WindowFrameBoundType
type
;
private
final
WindowFrameBoundType
type
;
private
final
Expression
value
;
private
Expression
value
;
private
boolean
isVariable
;
private
int
expressionIndex
=
-
1
;
/**
/**
* Creates new instance of window frame bound.
* Creates new instance of window frame bound.
...
@@ -51,6 +57,81 @@ public class WindowFrameBound {
...
@@ -51,6 +57,81 @@ public class WindowFrameBound {
return
value
;
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
;
}
/**
* Returns the index of preserved expression.
*
* @return the index of preserved expression, or -1
*/
public
int
getExpressionIndex
()
{
return
expressionIndex
;
}
/**
* Sets the index of preserved expression.
*
* @param expressionIndex
* the index to set
*/
void
setExpressionIndex
(
int
expressionIndex
)
{
this
.
expressionIndex
=
expressionIndex
;
}
/**
* 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.
* Appends SQL representation to the specified builder.
*
*
...
...
h2/src/test/org/h2/test/scripts/functions/aggregate/array-agg.sql
浏览文件 @
a092ef8b
...
@@ -596,5 +596,43 @@ SELECT ID, VALUE,
...
@@ -596,5 +596,43 @@ 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
]
>
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
>
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
SELECT
ID
,
VALUE
,
ARRAY_AGG
(
ID
ORDER
BY
ID
)
OVER
(
PARTITION
BY
VALUE
ORDER
BY
ID
ROWS
BETWEEN
VALUE
/
3
PRECEDING
AND
VALUE
/
3
FOLLOWING
)
A
,
ARRAY_AGG
(
ID
ORDER
BY
ID
)
OVER
(
PARTITION
BY
VALUE
ORDER
BY
ID
ROWS
BETWEEN
UNBOUNDED
PRECEDING
AND
VALUE
/
3
FOLLOWING
)
AP
,
ARRAY_AGG
(
ID
ORDER
BY
ID
)
OVER
(
PARTITION
BY
VALUE
ORDER
BY
ID
ROWS
BETWEEN
VALUE
/
3
PRECEDING
AND
UNBOUNDED
FOLLOWING
)
AF
FROM
TEST
;
>
ID
VALUE
A
AP
AF
>
-- ----- ------ ------ ------
>
1
1
[
1
]
[
1
]
[
1
,
2
]
>
2
1
[
2
]
[
1
,
2
]
[
2
]
>
3
2
[
3
]
[
3
]
[
3
,
4
]
>
4
2
[
4
]
[
3
,
4
]
[
4
]
>
5
3
[
5
,
6
]
[
5
,
6
]
[
5
,
6
]
>
6
3
[
5
,
6
]
[
5
,
6
]
[
5
,
6
]
>
7
4
[
7
,
8
]
[
7
,
8
]
[
7
,
8
]
>
8
4
[
7
,
8
]
[
7
,
8
]
[
7
,
8
]
>
rows
:
8
DROP
TABLE
TEST
;
DROP
TABLE
TEST
;
>
ok
>
ok
h2/src/test/org/h2/test/scripts/functions/window/nth_value.sql
浏览文件 @
a092ef8b
...
@@ -218,6 +218,28 @@ SELECT ID, CATEGORY,
...
@@ -218,6 +218,28 @@ SELECT ID, CATEGORY,
>
13
4
1
1
1
2
3
4
>
13
4
1
1
1
2
3
4
>
rows
(
ordered
):
13
>
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
;
DROP
TABLE
TEST
;
>
ok
>
ok
...
@@ -230,3 +252,13 @@ SELECT I, X, LAST_VALUE(I) OVER (ORDER BY X) L FROM VALUES (1, 1), (2, 1), (3, 2
...
@@ -230,3 +252,13 @@ SELECT I, X, LAST_VALUE(I) OVER (ORDER BY X) L FROM VALUES (1, 1), (2, 1), (3, 2
>
4
2
4
>
4
2
4
>
5
3
5
>
5
3
5
>
rows
:
5
>
rows
:
5
SELECT
A
,
MAX
(
B
)
M
,
FIRST_VALUE
(
A
)
OVER
(
ORDER
BY
A
ROWS
BETWEEN
MAX
(
B
)
-
1
FOLLOWING
AND
UNBOUNDED
FOLLOWING
)
F
FROM
VALUES
(
1
,
1
),
(
1
,
1
),
(
2
,
1
),
(
2
,
2
),
(
3
,
1
)
V
(
A
,
B
)
GROUP
BY
A
;
>
A
M
F
>
-
-
-
>
1
1
1
>
2
2
3
>
3
1
3
>
rows
:
3
h2/src/tools/org/h2/build/doc/dictionary.txt
浏览文件 @
a092ef8b
...
@@ -805,4 +805,4 @@ queryparser tokenized freeze factorings recompilation unenclosed rfe dsync
...
@@ -805,4 +805,4 @@ queryparser tokenized freeze factorings recompilation unenclosed rfe dsync
econd irst bcef ordinality nord unnest
econd irst bcef ordinality nord unnest
analyst occupation distributive josaph aor engineer sajeewa isuru randil kevin doctor businessman artist ashan
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
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
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论