Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
1e25c068
提交
1e25c068
authored
6月 14, 2010
作者:
Thomas Mueller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Experimental feature to support nested joins.
上级
81de9e71
显示空白字符变更
内嵌
并排
正在显示
9 个修改的文件
包含
366 行增加
和
55 行删除
+366
-55
Parser.java
h2/src/main/org/h2/command/Parser.java
+30
-8
Optimizer.java
h2/src/main/org/h2/command/dml/Optimizer.java
+1
-1
Select.java
h2/src/main/org/h2/command/dml/Select.java
+12
-5
SysProperties.java
h2/src/main/org/h2/constant/SysProperties.java
+6
-0
PlanItem.java
h2/src/main/org/h2/table/PlanItem.java
+9
-0
TableFilter.java
h2/src/main/org/h2/table/TableFilter.java
+135
-24
TestAll.java
h2/src/test/org/h2/test/TestAll.java
+3
-0
TestNestedJoins.java
h2/src/test/org/h2/test/db/TestNestedJoins.java
+170
-0
todo.txt
h2/src/test/org/h2/test/todo/todo.txt
+0
-17
没有找到文件。
h2/src/main/org/h2/command/Parser.java
浏览文件 @
1e25c068
...
@@ -1229,7 +1229,7 @@ public class Parser {
...
@@ -1229,7 +1229,7 @@ public class Parser {
if
(
readIf
(
"ON"
))
{
if
(
readIf
(
"ON"
))
{
on
=
readExpression
();
on
=
readExpression
();
}
}
newTop
.
addJoin
(
top
,
true
,
on
);
newTop
.
addJoin
(
top
,
true
,
fromOuter
,
on
);
top
=
newTop
;
top
=
newTop
;
last
=
newTop
;
last
=
newTop
;
}
else
if
(
readIf
(
"LEFT"
))
{
}
else
if
(
readIf
(
"LEFT"
))
{
...
@@ -1241,10 +1241,10 @@ public class Parser {
...
@@ -1241,10 +1241,10 @@ public class Parser {
if
(
readIf
(
"ON"
))
{
if
(
readIf
(
"ON"
))
{
on
=
readExpression
();
on
=
readExpression
();
}
}
top
.
addJoin
(
join
,
true
,
on
);
top
.
addJoin
(
join
,
true
,
fromOuter
,
on
);
last
=
join
;
last
=
join
;
}
else
if
(
readIf
(
"FULL"
))
{
}
else
if
(
readIf
(
"FULL"
))
{
throw
this
.
getSyntaxError
();
throw
getSyntaxError
();
}
else
if
(
readIf
(
"INNER"
))
{
}
else
if
(
readIf
(
"INNER"
))
{
read
(
"JOIN"
);
read
(
"JOIN"
);
TableFilter
join
=
readTableFilter
(
fromOuter
);
TableFilter
join
=
readTableFilter
(
fromOuter
);
...
@@ -1253,7 +1253,11 @@ public class Parser {
...
@@ -1253,7 +1253,11 @@ public class Parser {
if
(
readIf
(
"ON"
))
{
if
(
readIf
(
"ON"
))
{
on
=
readExpression
();
on
=
readExpression
();
}
}
top
.
addJoin
(
join
,
fromOuter
,
on
);
if
(
SysProperties
.
NESTED_JOINS
)
{
top
.
addJoin
(
join
,
false
,
fromOuter
,
on
);
}
else
{
top
.
addJoin
(
join
,
fromOuter
,
fromOuter
,
on
);
}
last
=
join
;
last
=
join
;
}
else
if
(
readIf
(
"JOIN"
))
{
}
else
if
(
readIf
(
"JOIN"
))
{
TableFilter
join
=
readTableFilter
(
fromOuter
);
TableFilter
join
=
readTableFilter
(
fromOuter
);
...
@@ -1262,12 +1266,20 @@ public class Parser {
...
@@ -1262,12 +1266,20 @@ public class Parser {
if
(
readIf
(
"ON"
))
{
if
(
readIf
(
"ON"
))
{
on
=
readExpression
();
on
=
readExpression
();
}
}
top
.
addJoin
(
join
,
fromOuter
,
on
);
if
(
SysProperties
.
NESTED_JOINS
)
{
top
.
addJoin
(
join
,
false
,
fromOuter
,
on
);
}
else
{
top
.
addJoin
(
join
,
fromOuter
,
fromOuter
,
on
);
}
last
=
join
;
last
=
join
;
}
else
if
(
readIf
(
"CROSS"
))
{
}
else
if
(
readIf
(
"CROSS"
))
{
read
(
"JOIN"
);
read
(
"JOIN"
);
TableFilter
join
=
readTableFilter
(
fromOuter
);
TableFilter
join
=
readTableFilter
(
fromOuter
);
top
.
addJoin
(
join
,
fromOuter
,
null
);
if
(
SysProperties
.
NESTED_JOINS
)
{
top
.
addJoin
(
join
,
false
,
fromOuter
,
null
);
}
else
{
top
.
addJoin
(
join
,
fromOuter
,
fromOuter
,
null
);
}
last
=
join
;
last
=
join
;
}
else
if
(
readIf
(
"NATURAL"
))
{
}
else
if
(
readIf
(
"NATURAL"
))
{
read
(
"JOIN"
);
read
(
"JOIN"
);
...
@@ -1296,7 +1308,11 @@ public class Parser {
...
@@ -1296,7 +1308,11 @@ public class Parser {
}
}
}
}
}
}
top
.
addJoin
(
join
,
fromOuter
,
on
);
if
(
SysProperties
.
NESTED_JOINS
)
{
top
.
addJoin
(
join
,
false
,
fromOuter
,
on
);
}
else
{
top
.
addJoin
(
join
,
fromOuter
,
fromOuter
,
on
);
}
last
=
join
;
last
=
join
;
}
else
{
}
else
{
break
;
break
;
...
@@ -1543,6 +1559,12 @@ public class Parser {
...
@@ -1543,6 +1559,12 @@ public class Parser {
command
.
addTableFilter
(
top
,
true
);
command
.
addTableFilter
(
top
,
true
);
boolean
isOuter
=
false
;
boolean
isOuter
=
false
;
while
(
true
)
{
while
(
true
)
{
for
(
TableFilter
n
=
top
.
getNestedJoin
();
n
!=
null
;
n
=
n
.
getNestedJoin
())
{
command
.
addTableFilter
(
n
,
false
);
for
(
TableFilter
j
=
n
.
getJoin
();
j
!=
null
;
j
=
j
.
getJoin
())
{
command
.
addTableFilter
(
j
,
false
);
}
}
TableFilter
join
=
top
.
getJoin
();
TableFilter
join
=
top
.
getJoin
();
if
(
join
==
null
)
{
if
(
join
==
null
)
{
break
;
break
;
...
@@ -1810,7 +1832,7 @@ public class Parser {
...
@@ -1810,7 +1832,7 @@ public class Parser {
int
idx
=
filters
.
indexOf
(
rightFilter
);
int
idx
=
filters
.
indexOf
(
rightFilter
);
if
(
idx
>=
0
)
{
if
(
idx
>=
0
)
{
filters
.
remove
(
idx
);
filters
.
remove
(
idx
);
leftFilter
.
addJoin
(
rightFilter
,
true
,
r
);
leftFilter
.
addJoin
(
rightFilter
,
true
,
false
,
r
);
}
else
{
}
else
{
rightFilter
.
mapAndAddFilter
(
r
);
rightFilter
.
mapAndAddFilter
(
r
);
}
}
...
...
h2/src/main/org/h2/command/dml/Optimizer.java
浏览文件 @
1e25c068
...
@@ -232,7 +232,7 @@ public class Optimizer {
...
@@ -232,7 +232,7 @@ public class Optimizer {
TableFilter
[]
f2
=
bestPlan
.
getFilters
();
TableFilter
[]
f2
=
bestPlan
.
getFilters
();
topFilter
=
f2
[
0
];
topFilter
=
f2
[
0
];
for
(
int
i
=
0
;
i
<
f2
.
length
-
1
;
i
++)
{
for
(
int
i
=
0
;
i
<
f2
.
length
-
1
;
i
++)
{
f2
[
i
].
addJoin
(
f2
[
i
+
1
],
false
,
null
);
f2
[
i
].
addJoin
(
f2
[
i
+
1
],
false
,
false
,
null
);
}
}
for
(
TableFilter
f
:
f2
)
{
for
(
TableFilter
f
:
f2
)
{
PlanItem
item
=
bestPlan
.
getItem
(
f
);
PlanItem
item
=
bestPlan
.
getItem
(
f
);
...
...
h2/src/main/org/h2/command/dml/Select.java
浏览文件 @
1e25c068
...
@@ -846,8 +846,14 @@ public class Select extends Query {
...
@@ -846,8 +846,14 @@ public class Select extends Query {
topTableFilter
=
optimizer
.
getTopFilter
();
topTableFilter
=
optimizer
.
getTopFilter
();
double
planCost
=
optimizer
.
getCost
();
double
planCost
=
optimizer
.
getCost
();
TableFilter
f
=
topTableFilter
;
setEvaluatableRecursive
(
topTableFilter
);
while
(
f
!=
null
)
{
topTableFilter
.
prepare
();
return
planCost
;
}
private
void
setEvaluatableRecursive
(
TableFilter
f
)
{
for
(;
f
!=
null
;
f
=
f
.
getJoin
())
{
f
.
setEvaluatable
(
f
,
true
);
f
.
setEvaluatable
(
f
,
true
);
if
(
condition
!=
null
)
{
if
(
condition
!=
null
)
{
condition
.
setEvaluatable
(
f
,
true
);
condition
.
setEvaluatable
(
f
,
true
);
...
@@ -879,10 +885,11 @@ public class Select extends Query {
...
@@ -879,10 +885,11 @@ public class Select extends Query {
for
(
Expression
e
:
expressions
)
{
for
(
Expression
e
:
expressions
)
{
e
.
setEvaluatable
(
f
,
true
);
e
.
setEvaluatable
(
f
,
true
);
}
}
f
=
f
.
getJoin
();
TableFilter
n
=
f
.
getNestedJoin
();
if
(
n
!=
null
)
{
setEvaluatableRecursive
(
n
);
}
}
}
topTableFilter
.
prepare
();
return
planCost
;
}
}
public
String
getPlanSQL
()
{
public
String
getPlanSQL
()
{
...
...
h2/src/main/org/h2/constant/SysProperties.java
浏览文件 @
1e25c068
...
@@ -386,6 +386,12 @@ public class SysProperties {
...
@@ -386,6 +386,12 @@ public class SysProperties {
*/
*/
public
static
final
int
MIN_WRITE_DELAY
=
getIntSetting
(
"h2.minWriteDelay"
,
5
);
public
static
final
int
MIN_WRITE_DELAY
=
getIntSetting
(
"h2.minWriteDelay"
,
5
);
/**
* System property <code>h2.nestedJoins</code> (default: false).<br />
* Whether nested joins should be supported.
*/
public
static
final
boolean
NESTED_JOINS
=
getBooleanSetting
(
"h2.nestedJoins"
,
false
);
/**
/**
* System property <code>h2.nioLoadMapped</code> (default: false).<br />
* System property <code>h2.nioLoadMapped</code> (default: false).<br />
* If the mapped buffer should be loaded when the file is opened.
* If the mapped buffer should be loaded when the file is opened.
...
...
h2/src/main/org/h2/table/PlanItem.java
浏览文件 @
1e25c068
...
@@ -21,6 +21,7 @@ public class PlanItem {
...
@@ -21,6 +21,7 @@ public class PlanItem {
private
Index
index
;
private
Index
index
;
private
PlanItem
joinPlan
;
private
PlanItem
joinPlan
;
private
PlanItem
nestedJoinPlan
;
void
setIndex
(
Index
index
)
{
void
setIndex
(
Index
index
)
{
this
.
index
=
index
;
this
.
index
=
index
;
...
@@ -34,8 +35,16 @@ public class PlanItem {
...
@@ -34,8 +35,16 @@ public class PlanItem {
return
joinPlan
;
return
joinPlan
;
}
}
PlanItem
getNestedJoinPlan
()
{
return
nestedJoinPlan
;
}
void
setJoinPlan
(
PlanItem
joinPlan
)
{
void
setJoinPlan
(
PlanItem
joinPlan
)
{
this
.
joinPlan
=
joinPlan
;
this
.
joinPlan
=
joinPlan
;
}
}
void
setNestedJoinPlan
(
PlanItem
nestedJoinPlan
)
{
this
.
nestedJoinPlan
=
nestedJoinPlan
;
}
}
}
h2/src/main/org/h2/table/TableFilter.java
浏览文件 @
1e25c068
...
@@ -70,8 +70,22 @@ public class TableFilter implements ColumnResolver {
...
@@ -70,8 +70,22 @@ public class TableFilter implements ColumnResolver {
private
SearchRow
currentSearchRow
;
private
SearchRow
currentSearchRow
;
private
Row
current
;
private
Row
current
;
private
int
state
;
private
int
state
;
/**
* The joined table (if there is one).
*/
private
TableFilter
join
;
private
TableFilter
join
;
private
boolean
outerJoin
;
/**
* Whether this table is an outer join.
*/
private
boolean
joinOuter
;
/**
* The nested joined table (if there is one).
*/
private
TableFilter
nestedJoin
;
private
ArrayList
<
Column
>
naturalJoinColumns
;
private
ArrayList
<
Column
>
naturalJoinColumns
;
private
boolean
foundOne
;
private
boolean
foundOne
;
private
Expression
fullCondition
;
private
Expression
fullCondition
;
...
@@ -153,6 +167,14 @@ public class TableFilter implements ColumnResolver {
...
@@ -153,6 +167,14 @@ public class TableFilter implements ColumnResolver {
// x (x.a=10); y (x.b=y.b) - see issue 113
// x (x.a=10); y (x.b=y.b) - see issue 113
item
.
cost
-=
item
.
cost
*
indexConditions
.
size
()
/
100
/
level
;
item
.
cost
-=
item
.
cost
*
indexConditions
.
size
()
/
100
/
level
;
}
}
if
(
nestedJoin
!=
null
)
{
setEvaluatable
(
nestedJoin
);
item
.
setNestedJoinPlan
(
nestedJoin
.
getBestPlanItem
(
s
,
level
));
int
todoNestJoinCostWrong
;
// TODO optimizer: calculate cost of a join: should use separate
// expected row number and lookup cost
item
.
cost
+=
item
.
cost
*
item
.
getNestedJoinPlan
().
cost
;
}
if
(
join
!=
null
)
{
if
(
join
!=
null
)
{
setEvaluatable
(
join
);
setEvaluatable
(
join
);
item
.
setJoinPlan
(
join
.
getBestPlanItem
(
s
,
level
));
item
.
setJoinPlan
(
join
.
getBestPlanItem
(
s
,
level
));
...
@@ -170,6 +192,10 @@ public class TableFilter implements ColumnResolver {
...
@@ -170,6 +192,10 @@ public class TableFilter implements ColumnResolver {
if
(
e
!=
null
)
{
if
(
e
!=
null
)
{
e
.
setEvaluatable
(
this
,
true
);
e
.
setEvaluatable
(
this
,
true
);
}
}
TableFilter
n
=
join
.
getNestedJoin
();
if
(
n
!=
null
)
{
setEvaluatable
(
n
);
}
join
=
join
.
getJoin
();
join
=
join
.
getJoin
();
}
while
(
join
!=
null
);
}
while
(
join
!=
null
);
}
}
...
@@ -181,6 +207,11 @@ public class TableFilter implements ColumnResolver {
...
@@ -181,6 +207,11 @@ public class TableFilter implements ColumnResolver {
*/
*/
public
void
setPlanItem
(
PlanItem
item
)
{
public
void
setPlanItem
(
PlanItem
item
)
{
setIndex
(
item
.
getIndex
());
setIndex
(
item
.
getIndex
());
if
(
nestedJoin
!=
null
)
{
if
(
item
.
getNestedJoinPlan
()
!=
null
)
{
nestedJoin
.
setPlanItem
(
item
.
getNestedJoinPlan
());
}
}
if
(
join
!=
null
)
{
if
(
join
!=
null
)
{
if
(
item
.
getJoinPlan
()
!=
null
)
{
if
(
item
.
getJoinPlan
()
!=
null
)
{
join
.
setPlanItem
(
item
.
getJoinPlan
());
join
.
setPlanItem
(
item
.
getJoinPlan
());
...
@@ -204,6 +235,12 @@ public class TableFilter implements ColumnResolver {
...
@@ -204,6 +235,12 @@ public class TableFilter implements ColumnResolver {
}
}
}
}
}
}
if
(
nestedJoin
!=
null
)
{
if
(
SysProperties
.
CHECK
&&
nestedJoin
==
this
)
{
DbException
.
throwInternalError
(
"self join"
);
}
nestedJoin
.
prepare
();
}
if
(
join
!=
null
)
{
if
(
join
!=
null
)
{
if
(
SysProperties
.
CHECK
&&
join
==
this
)
{
if
(
SysProperties
.
CHECK
&&
join
==
this
)
{
DbException
.
throwInternalError
(
"self join"
);
DbException
.
throwInternalError
(
"self join"
);
...
@@ -226,6 +263,9 @@ public class TableFilter implements ColumnResolver {
...
@@ -226,6 +263,9 @@ public class TableFilter implements ColumnResolver {
public
void
startQuery
(
Session
s
)
{
public
void
startQuery
(
Session
s
)
{
this
.
session
=
s
;
this
.
session
=
s
;
scanCount
=
0
;
scanCount
=
0
;
if
(
nestedJoin
!=
null
)
{
nestedJoin
.
startQuery
(
s
);
}
if
(
join
!=
null
)
{
if
(
join
!=
null
)
{
join
.
startQuery
(
s
);
join
.
startQuery
(
s
);
}
}
...
@@ -235,6 +275,9 @@ public class TableFilter implements ColumnResolver {
...
@@ -235,6 +275,9 @@ public class TableFilter implements ColumnResolver {
* Reset to the current position.
* Reset to the current position.
*/
*/
public
void
reset
()
{
public
void
reset
()
{
if
(
nestedJoin
!=
null
)
{
nestedJoin
.
reset
();
}
if
(
join
!=
null
)
{
if
(
join
!=
null
)
{
join
.
reset
();
join
.
reset
();
}
}
...
@@ -253,17 +296,37 @@ public class TableFilter implements ColumnResolver {
...
@@ -253,17 +296,37 @@ public class TableFilter implements ColumnResolver {
}
else
if
(
state
==
BEFORE_FIRST
)
{
}
else
if
(
state
==
BEFORE_FIRST
)
{
cursor
.
find
(
session
,
indexConditions
);
cursor
.
find
(
session
,
indexConditions
);
if
(!
cursor
.
isAlwaysFalse
())
{
if
(!
cursor
.
isAlwaysFalse
())
{
if
(
nestedJoin
!=
null
)
{
nestedJoin
.
reset
();
}
if
(
join
!=
null
)
{
if
(
join
!=
null
)
{
join
.
reset
();
join
.
reset
();
}
}
}
}
}
else
{
}
else
{
// state == FOUND ||
LAST
_ROW
// state == FOUND ||
NULL
_ROW
// the last row was ok - try next row of the join
// the last row was ok - try next row of the join
if
(
nestedJoin
!=
null
)
{
if
(
join
==
null
)
{
if
(
nestedJoin
.
next
())
{
return
true
;
}
}
else
{
while
(
true
)
{
if
(
nestedJoin
.
next
())
{
if
(
join
.
next
())
{
return
true
;
}
join
.
reset
();
}
}
}
}
else
{
if
(
join
!=
null
&&
join
.
next
())
{
if
(
join
!=
null
&&
join
.
next
())
{
return
true
;
return
true
;
}
}
}
}
}
while
(
true
)
{
while
(
true
)
{
// go to the next row
// go to the next row
if
(
state
==
NULL_ROW
)
{
if
(
state
==
NULL_ROW
)
{
...
@@ -285,14 +348,18 @@ public class TableFilter implements ColumnResolver {
...
@@ -285,14 +348,18 @@ public class TableFilter implements ColumnResolver {
}
}
// if no more rows found, try the null row (for outer joins only)
// if no more rows found, try the null row (for outer joins only)
if
(
state
==
AFTER_LAST
)
{
if
(
state
==
AFTER_LAST
)
{
if
(
outerJoin
&&
!
foundOne
)
{
if
(
joinOuter
&&
!
foundOne
)
{
state
=
NULL_ROW
;
setNullRow
();
current
=
table
.
getNullRow
();
currentSearchRow
=
current
;
}
else
{
}
else
{
break
;
break
;
}
}
}
}
if
(
state
==
FOUND
&&
nestedJoin
!=
null
)
{
nestedJoin
.
reset
();
if
(!
nestedJoin
.
next
())
{
continue
;
}
}
if
(!
isOk
(
filterCondition
))
{
if
(!
isOk
(
filterCondition
))
{
continue
;
continue
;
}
}
...
@@ -319,6 +386,16 @@ public class TableFilter implements ColumnResolver {
...
@@ -319,6 +386,16 @@ public class TableFilter implements ColumnResolver {
return
false
;
return
false
;
}
}
private
void
setNullRow
()
{
state
=
NULL_ROW
;
current
=
table
.
getNullRow
();
currentSearchRow
=
current
;
if
(
nestedJoin
!=
null
)
{
int
todoRecurse
;
nestedJoin
.
setNullRow
();
}
}
private
void
checkTimeout
()
{
private
void
checkTimeout
()
{
session
.
checkCanceled
();
session
.
checkCanceled
();
// System.out.println(this.alias+ " " + table.getName() + ": " +
// System.out.println(this.alias+ " " + table.getName() + ": " +
...
@@ -407,26 +484,39 @@ public class TableFilter implements ColumnResolver {
...
@@ -407,26 +484,39 @@ public class TableFilter implements ColumnResolver {
* @param outer if this is an outer join
* @param outer if this is an outer join
* @param on the join condition
* @param on the join condition
*/
*/
public
void
addJoin
(
TableFilter
filter
,
boolean
outer
,
Expression
on
)
{
public
void
addJoin
(
TableFilter
filter
,
boolean
outer
,
boolean
nested
,
Expression
on
)
{
if
(
on
!=
null
)
{
if
(
on
!=
null
)
{
on
.
mapColumns
(
this
,
0
);
on
.
mapColumns
(
this
,
0
);
}
}
if
(
nested
&&
SysProperties
.
NESTED_JOINS
)
{
if
(
nestedJoin
!=
null
)
{
throw
DbException
.
throwInternalError
();
}
nestedJoin
=
filter
;
filter
.
joinOuter
=
outer
;
if
(
on
!=
null
)
{
filter
.
mapAndAddFilter
(
on
);
}
}
else
{
if
(
join
==
null
)
{
if
(
join
==
null
)
{
this
.
join
=
filter
;
join
=
filter
;
filter
.
outerJoin
=
outer
;
filter
.
joinOuter
=
outer
;
if
(!
SysProperties
.
NESTED_JOINS
)
{
if
(
outer
)
{
if
(
outer
)
{
// convert all inner joins on the right hand side to outer joins
// convert all inner joins on the right hand side to outer joins
TableFilter
f
=
filter
.
join
;
TableFilter
f
=
filter
.
join
;
while
(
f
!=
null
)
{
while
(
f
!=
null
)
{
f
.
outerJoin
=
true
;
f
.
joinOuter
=
true
;
f
=
f
.
join
;
f
=
f
.
join
;
}
}
}
}
}
if
(
on
!=
null
)
{
if
(
on
!=
null
)
{
filter
.
mapAndAddFilter
(
on
);
filter
.
mapAndAddFilter
(
on
);
}
}
}
else
{
}
else
{
join
.
addJoin
(
filter
,
outer
,
on
);
join
.
addJoin
(
filter
,
outer
,
nested
,
on
);
}
}
}
}
}
...
@@ -439,6 +529,9 @@ public class TableFilter implements ColumnResolver {
...
@@ -439,6 +529,9 @@ public class TableFilter implements ColumnResolver {
on
.
mapColumns
(
this
,
0
);
on
.
mapColumns
(
this
,
0
);
addFilterCondition
(
on
,
true
);
addFilterCondition
(
on
,
true
);
on
.
createIndexConditions
(
session
,
this
);
on
.
createIndexConditions
(
session
,
this
);
if
(
nestedJoin
!=
null
)
{
nestedJoin
.
mapAndAddFilter
(
on
);
}
if
(
join
!=
null
)
{
if
(
join
!=
null
)
{
join
.
mapAndAddFilter
(
on
);
join
.
mapAndAddFilter
(
on
);
}
}
...
@@ -454,7 +547,7 @@ public class TableFilter implements ColumnResolver {
...
@@ -454,7 +547,7 @@ public class TableFilter implements ColumnResolver {
* @return true if it is
* @return true if it is
*/
*/
public
boolean
isJoinOuter
()
{
public
boolean
isJoinOuter
()
{
return
outerJoin
;
return
joinOuter
;
}
}
/**
/**
...
@@ -466,12 +559,15 @@ public class TableFilter implements ColumnResolver {
...
@@ -466,12 +559,15 @@ public class TableFilter implements ColumnResolver {
public
String
getPlanSQL
(
boolean
isJoin
)
{
public
String
getPlanSQL
(
boolean
isJoin
)
{
StringBuilder
buff
=
new
StringBuilder
();
StringBuilder
buff
=
new
StringBuilder
();
if
(
isJoin
)
{
if
(
isJoin
)
{
if
(
outerJoin
)
{
if
(
joinOuter
)
{
buff
.
append
(
"LEFT OUTER JOIN "
);
buff
.
append
(
"LEFT OUTER JOIN "
);
}
else
{
}
else
{
buff
.
append
(
"INNER JOIN "
);
buff
.
append
(
"INNER JOIN "
);
}
}
}
}
if
(
nestedJoin
!=
null
)
{
buff
.
append
(
"("
);
}
buff
.
append
(
table
.
getSQL
());
buff
.
append
(
table
.
getSQL
());
if
(
alias
!=
null
)
{
if
(
alias
!=
null
)
{
buff
.
append
(
' '
).
append
(
Parser
.
quoteIdentifier
(
alias
));
buff
.
append
(
' '
).
append
(
Parser
.
quoteIdentifier
(
alias
));
...
@@ -490,6 +586,11 @@ public class TableFilter implements ColumnResolver {
...
@@ -490,6 +586,11 @@ public class TableFilter implements ColumnResolver {
String
plan
=
StringUtils
.
quoteRemarkSQL
(
planBuff
.
toString
());
String
plan
=
StringUtils
.
quoteRemarkSQL
(
planBuff
.
toString
());
buff
.
append
(
plan
).
append
(
" */"
);
buff
.
append
(
plan
).
append
(
" */"
);
}
}
if
(
nestedJoin
!=
null
)
{
buff
.
append
(
'\n'
);
buff
.
append
(
nestedJoin
.
getPlanSQL
(
true
));
buff
.
append
(
")"
);
}
if
(
isJoin
)
{
if
(
isJoin
)
{
buff
.
append
(
" ON "
);
buff
.
append
(
" ON "
);
if
(
joinCondition
==
null
)
{
if
(
joinCondition
==
null
)
{
...
@@ -594,9 +695,12 @@ public class TableFilter implements ColumnResolver {
...
@@ -594,9 +695,12 @@ public class TableFilter implements ColumnResolver {
*/
*/
void
optimizeFullCondition
(
boolean
fromOuterJoin
)
{
void
optimizeFullCondition
(
boolean
fromOuterJoin
)
{
if
(
fullCondition
!=
null
)
{
if
(
fullCondition
!=
null
)
{
fullCondition
.
addFilterConditions
(
this
,
fromOuterJoin
||
outerJoin
);
fullCondition
.
addFilterConditions
(
this
,
fromOuterJoin
||
joinOuter
);
if
(
nestedJoin
!=
null
)
{
nestedJoin
.
optimizeFullCondition
(
fromOuterJoin
||
joinOuter
);
}
if
(
join
!=
null
)
{
if
(
join
!=
null
)
{
join
.
optimizeFullCondition
(
fromOuterJoin
||
outerJoin
);
join
.
optimizeFullCondition
(
fromOuterJoin
||
joinOuter
);
}
}
}
}
}
}
...
@@ -615,6 +719,9 @@ public class TableFilter implements ColumnResolver {
...
@@ -615,6 +719,9 @@ public class TableFilter implements ColumnResolver {
if
(
joinCondition
!=
null
)
{
if
(
joinCondition
!=
null
)
{
joinCondition
.
setEvaluatable
(
filter
,
b
);
joinCondition
.
setEvaluatable
(
filter
,
b
);
}
}
if
(
nestedJoin
!=
null
)
{
nestedJoin
.
setEvaluatable
(
filter
,
b
);
}
if
(
join
!=
null
)
{
if
(
join
!=
null
)
{
join
.
setEvaluatable
(
filter
,
b
);
join
.
setEvaluatable
(
filter
,
b
);
}
}
...
@@ -744,4 +851,8 @@ public class TableFilter implements ColumnResolver {
...
@@ -744,4 +851,8 @@ public class TableFilter implements ColumnResolver {
}
}
}
}
public
TableFilter
getNestedJoin
()
{
return
nestedJoin
;
}
}
}
h2/src/test/org/h2/test/TestAll.java
浏览文件 @
1e25c068
...
@@ -38,6 +38,7 @@ import org.h2.test.db.TestMultiConn;
...
@@ -38,6 +38,7 @@ import org.h2.test.db.TestMultiConn;
import
org.h2.test.db.TestMultiDimension
;
import
org.h2.test.db.TestMultiDimension
;
import
org.h2.test.db.TestMultiThread
;
import
org.h2.test.db.TestMultiThread
;
import
org.h2.test.db.TestMultiThreadedKernel
;
import
org.h2.test.db.TestMultiThreadedKernel
;
import
org.h2.test.db.TestNestedJoins
;
import
org.h2.test.db.TestOpenClose
;
import
org.h2.test.db.TestOpenClose
;
import
org.h2.test.db.TestOptimizations
;
import
org.h2.test.db.TestOptimizations
;
import
org.h2.test.db.TestOutOfMemory
;
import
org.h2.test.db.TestOutOfMemory
;
...
@@ -302,6 +303,7 @@ java org.h2.test.TestAll timer
...
@@ -302,6 +303,7 @@ java org.h2.test.TestAll timer
// System.setProperty("h2.largeTransactions", "true");
// System.setProperty("h2.largeTransactions", "true");
// System.setProperty("h2.lobInDatabase", "true");
// System.setProperty("h2.lobInDatabase", "true");
// System.setProperty("h2.analyzeAuto", "100");
// System.setProperty("h2.analyzeAuto", "100");
// System.setProperty("h2.nestedJoins", "true");
int
speedup
;
int
speedup
;
// System.setProperty("h2.syncMethod", "");
// System.setProperty("h2.syncMethod", "");
...
@@ -516,6 +518,7 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
...
@@ -516,6 +518,7 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
new
TestMultiDimension
().
runTest
(
this
);
new
TestMultiDimension
().
runTest
(
this
);
new
TestMultiThread
().
runTest
(
this
);
new
TestMultiThread
().
runTest
(
this
);
new
TestMultiThreadedKernel
().
runTest
(
this
);
new
TestMultiThreadedKernel
().
runTest
(
this
);
new
TestNestedJoins
().
runTest
(
this
);
new
TestOpenClose
().
runTest
(
this
);
new
TestOpenClose
().
runTest
(
this
);
new
TestOptimizations
().
runTest
(
this
);
new
TestOptimizations
().
runTest
(
this
);
new
TestOutOfMemory
().
runTest
(
this
);
new
TestOutOfMemory
().
runTest
(
this
);
...
...
h2/src/test/org/h2/test/db/TestNestedJoins.java
0 → 100644
浏览文件 @
1e25c068
/*
* Copyright 2004-2010 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
test
.
db
;
import
java.io.StringReader
;
import
java.sql.Connection
;
import
java.sql.ResultSet
;
import
java.sql.SQLException
;
import
java.sql.Statement
;
import
org.h2.constant.SysProperties
;
import
org.h2.test.TestBase
;
import
org.h2.util.ScriptReader
;
/**
* Tests nested joins and right outer joins.
*/
public
class
TestNestedJoins
extends
TestBase
{
/**
* Run just this test.
*
* @param a ignored
*/
public
static
void
main
(
String
...
a
)
throws
Exception
{
System
.
setProperty
(
"h2.nestedJoins"
,
"true"
);
TestBase
.
createCaller
().
init
().
test
();
}
public
void
test
()
throws
Exception
{
if
(!
SysProperties
.
NESTED_JOINS
)
{
return
;
}
deleteDb
(
"nestedJoins"
);
Connection
conn
=
getConnection
(
"nestedJoins"
);
Statement
stat
=
conn
.
createStatement
();
ResultSet
rs
;
String
sql
;
// not yet supported:
/*
stat.execute("drop table a, b, c");
stat.execute("create table a(x int)");
stat.execute("create table b(x int)");
stat.execute("create table c(x int, y int)");
stat.execute("insert into a values(1), (2)");
stat.execute("insert into b values(3)");
stat.execute("insert into c values(1, 3)");
stat.execute("insert into c values(4, 5)");
rs = stat.executeQuery("explain select * from a left outer join (b left outer join c on b.x = c.y) on a.x = c.x");
assertTrue(rs.next());
sql = cleanRemarks(conn, rs.getString(1));
assertEquals("", sql);
rs = stat.executeQuery("select * from a left outer join (b left outer join c on b.x = c.y) on a.x = c.x");
// expected result: 1 3 1 3; 2 null null null
assertTrue(rs.next());
assertEquals("1", rs.getString(1));
assertEquals("3", rs.getString(2));
assertEquals("1", rs.getString(3));
assertEquals("3", rs.getString(4));
assertTrue(rs.next());
assertEquals("2", rs.getString(1));
assertEquals(null, rs.getString(2));
assertEquals(null, rs.getString(3));
assertEquals(null, rs.getString(4));
assertFalse(rs.next());
*/
stat
.
execute
(
"create table a(x int primary key)"
);
stat
.
execute
(
"insert into a values(0), (1)"
);
stat
.
execute
(
"create table b(x int primary key)"
);
stat
.
execute
(
"insert into b values(0)"
);
stat
.
execute
(
"create table c(x int primary key)"
);
rs
=
stat
.
executeQuery
(
"select a.*, b.*, c.* from a left outer join (b inner join c on b.x = c.x) on a.x = b.x"
);
// expected result: 0, null, null; 1, null, null
assertTrue
(
rs
.
next
());
assertEquals
(
"0"
,
rs
.
getString
(
1
));
assertEquals
(
null
,
rs
.
getString
(
2
));
assertEquals
(
null
,
rs
.
getString
(
3
));
assertTrue
(
rs
.
next
());
assertEquals
(
"1"
,
rs
.
getString
(
1
));
assertEquals
(
null
,
rs
.
getString
(
2
));
assertEquals
(
null
,
rs
.
getString
(
3
));
assertFalse
(
rs
.
next
());
rs
=
stat
.
executeQuery
(
"select * from a left outer join b on a.x = b.x inner join c on b.x = c.x"
);
// expected result: -
assertFalse
(
rs
.
next
());
rs
=
stat
.
executeQuery
(
"select * from a left outer join b on a.x = b.x left outer join c on b.x = c.x"
);
// expected result: 0 0 null; 1 null null
assertTrue
(
rs
.
next
());
assertEquals
(
"0"
,
rs
.
getString
(
1
));
assertEquals
(
"0"
,
rs
.
getString
(
2
));
assertEquals
(
null
,
rs
.
getString
(
3
));
assertTrue
(
rs
.
next
());
assertEquals
(
"1"
,
rs
.
getString
(
1
));
assertEquals
(
null
,
rs
.
getString
(
2
));
assertEquals
(
null
,
rs
.
getString
(
3
));
assertFalse
(
rs
.
next
());
rs
=
stat
.
executeQuery
(
"select * from a left outer join (b inner join c on b.x = c.x) on a.x = b.x"
);
// expected result: 0 null null; 1 null null
assertTrue
(
rs
.
next
());
assertEquals
(
"0"
,
rs
.
getString
(
1
));
assertEquals
(
null
,
rs
.
getString
(
2
));
assertEquals
(
null
,
rs
.
getString
(
3
));
assertTrue
(
rs
.
next
());
assertEquals
(
"1"
,
rs
.
getString
(
1
));
assertEquals
(
null
,
rs
.
getString
(
2
));
assertEquals
(
null
,
rs
.
getString
(
3
));
assertFalse
(
rs
.
next
());
rs
=
stat
.
executeQuery
(
"explain select * from a left outer join (b inner join c on c.x = 1) on a.x = b.x"
);
assertTrue
(
rs
.
next
());
sql
=
cleanRemarks
(
conn
,
rs
.
getString
(
1
));
assertEquals
(
"SELECT A.X, B.X, C.X FROM PUBLIC.A LEFT OUTER JOIN (PUBLIC.B INNER JOIN PUBLIC.C ON (C.X = 1) AND (A.X = B.X)) ON A.X = B.X"
,
sql
);
stat
.
execute
(
"create table test(id int primary key)"
);
stat
.
execute
(
"insert into test values(0), (1), (2)"
);
rs
=
stat
.
executeQuery
(
"select * from test a left outer join (test b inner join test c on b.id = c.id - 2) on a.id = b.id + 1"
);
// drop table test;
// create table test(id int primary key);
// insert into test values(0), (1), (2);
// select * from test a left outer join (test b inner join test c on b.id = c.id - 2) on a.id = b.id + 1;
// expected result: 0 null null; 1 0 2; 2 null null
assertTrue
(
rs
.
next
());
assertEquals
(
"0"
,
rs
.
getString
(
1
));
assertEquals
(
null
,
rs
.
getString
(
2
));
assertEquals
(
null
,
rs
.
getString
(
3
));
assertTrue
(
rs
.
next
());
assertEquals
(
"1"
,
rs
.
getString
(
1
));
assertEquals
(
"0"
,
rs
.
getString
(
2
));
assertEquals
(
"2"
,
rs
.
getString
(
3
));
assertTrue
(
rs
.
next
());
assertEquals
(
"2"
,
rs
.
getString
(
1
));
assertEquals
(
null
,
rs
.
getString
(
2
));
assertEquals
(
null
,
rs
.
getString
(
3
));
assertFalse
(
rs
.
next
());
// while (rs.next()) {
// for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
// System.out.print(rs.getString(i + 1) + " ");
// }
// System.out.println();
// }
conn
.
close
();
deleteDb
(
"nestedJoins"
);
}
private
String
cleanRemarks
(
Connection
conn
,
String
sql
)
throws
SQLException
{
ScriptReader
r
=
new
ScriptReader
(
new
StringReader
(
sql
));
r
.
setSkipRemarks
(
true
);
sql
=
r
.
readStatement
();
sql
=
sql
.
replaceAll
(
"\\n"
,
" "
);
// sql = sql.replaceAll("\\/\\*.*\\*\\/", "");
while
(
sql
.
indexOf
(
" "
)
>=
0
)
{
sql
=
sql
.
replaceAll
(
" "
,
" "
);
}
return
sql
;
}
}
h2/src/test/org/h2/test/todo/todo.txt
浏览文件 @
1e25c068
...
@@ -2,23 +2,6 @@ Nested Outer Joins
...
@@ -2,23 +2,6 @@ Nested Outer Joins
-----------------
-----------------
Example:
Example:
drop table a, b, c;
create table a(x int primary key);
insert into a values(0), (1);
create table b(x int primary key);
insert into b values(0);
create table c(x int primary key);
select * from a left outer join b on a.x = b.x inner join c on b.x = c.x;
select * from a left outer join b on a.x = b.x left outer join c on b.x = c.x;
select * from a left outer join (b inner join c on b.x = c.x) on a.x = b.x;
select a.x, b_x, c_x from a left outer join (select b.x b_x, c.x c_x from b inner join c on b.x = c.x) on a.x = b_x;
drop table test;
create table test(id int primary key);
insert into test values(0), (1), (2);
select * from test a left outer join (test b inner join test c on b.id = c.id - 2) on a.id = b.id + 1;
select a.id, b_id, c_id from test a left outer join (select b.id b_id, c.id c_id from test b inner join test c on b.id = c.id - 2) on a.id = b_id + 1;
create table a(x int);
create table a(x int);
create table b(x int);
create table b(x int);
create table c(x int, y int);
create table c(x int, y int);
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论