Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
c877fe32
Unverified
提交
c877fe32
authored
1月 11, 2018
作者:
Noel Grandin
提交者:
GitHub
1月 11, 2018
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #646 from stumc/Issue#645
Issue#646 NPE in CREATE VIEW WITH RECURSIVE & NON_RECURSIVE CTE
上级
3cc76947
2c485151
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
24 个修改的文件
包含
1065 行增加
和
473 行删除
+1065
-473
.gitignore
h2/.gitignore
+1
-0
Parser.java
h2/src/main/org/h2/command/Parser.java
+189
-175
CreateView.java
h2/src/main/org/h2/command/ddl/CreateView.java
+25
-5
DropView.java
h2/src/main/org/h2/command/ddl/DropView.java
+19
-0
Delete.java
h2/src/main/org/h2/command/dml/Delete.java
+4
-5
MergeUsing.java
h2/src/main/org/h2/command/dml/MergeUsing.java
+5
-3
Select.java
h2/src/main/org/h2/command/dml/Select.java
+20
-12
Database.java
h2/src/main/org/h2/engine/Database.java
+19
-17
Session.java
h2/src/main/org/h2/engine/Session.java
+19
-3
ViewIndex.java
h2/src/main/org/h2/index/ViewIndex.java
+23
-20
MVTable.java
h2/src/main/org/h2/mvstore/db/MVTable.java
+35
-11
Table.java
h2/src/main/org/h2/table/Table.java
+9
-5
TableView.java
h2/src/main/org/h2/table/TableView.java
+189
-40
TestAll.java
h2/src/test/org/h2/test/TestAll.java
+5
-0
TestBase.java
h2/src/test/org/h2/test/TestBase.java
+0
-1
AbstractBaseForCommonTableExpressions.java
...org/h2/test/db/AbstractBaseForCommonTableExpressions.java
+67
-0
TestGeneralCommonTableQueries.java
...rc/test/org/h2/test/db/TestGeneralCommonTableQueries.java
+115
-126
TestPersistentCommonTableExpressions.java
.../org/h2/test/db/TestPersistentCommonTableExpressions.java
+182
-0
TestMvccMultiThreaded2.java
h2/src/test/org/h2/test/mvcc/TestMvccMultiThreaded2.java
+45
-4
TestScript.java
h2/src/test/org/h2/test/scripts/TestScript.java
+3
-0
mergeUsing.sql
h2/src/test/org/h2/test/scripts/dml/mergeUsing.sql
+33
-0
with.sql
h2/src/test/org/h2/test/scripts/dml/with.sql
+55
-0
testScript.sql
h2/src/test/org/h2/test/scripts/testScript.sql
+0
-43
TestMathUtils.java
h2/src/test/org/h2/test/unit/TestMathUtils.java
+3
-3
没有找到文件。
h2/.gitignore
浏览文件 @
c877fe32
...
@@ -14,3 +14,4 @@ test.out.txt
...
@@ -14,3 +14,4 @@ test.out.txt
*.log
*.log
target/
target/
src/main/org/h2/res/help.csv
src/main/org/h2/res/help.csv
_tmp*
h2/src/main/org/h2/command/Parser.java
浏览文件 @
c877fe32
差异被折叠。
点击展开。
h2/src/main/org/h2/command/ddl/CreateView.java
浏览文件 @
c877fe32
...
@@ -34,6 +34,7 @@ public class CreateView extends SchemaCommand {
...
@@ -34,6 +34,7 @@ public class CreateView extends SchemaCommand {
private
String
comment
;
private
String
comment
;
private
boolean
orReplace
;
private
boolean
orReplace
;
private
boolean
force
;
private
boolean
force
;
private
boolean
isTableExpression
;
public
CreateView
(
Session
session
,
Schema
schema
)
{
public
CreateView
(
Session
session
,
Schema
schema
)
{
super
(
session
,
schema
);
super
(
session
,
schema
);
...
@@ -70,6 +71,10 @@ public class CreateView extends SchemaCommand {
...
@@ -70,6 +71,10 @@ public class CreateView extends SchemaCommand {
public
void
setForce
(
boolean
force
)
{
public
void
setForce
(
boolean
force
)
{
this
.
force
=
force
;
this
.
force
=
force
;
}
}
public
void
setTableExpression
(
boolean
isTableExpression
)
{
this
.
isTableExpression
=
isTableExpression
;
}
@Override
@Override
public
int
update
()
{
public
int
update
()
{
...
@@ -98,17 +103,27 @@ public class CreateView extends SchemaCommand {
...
@@ -98,17 +103,27 @@ public class CreateView extends SchemaCommand {
}
}
querySQL
=
select
.
getPlanSQL
();
querySQL
=
select
.
getPlanSQL
();
}
}
Column
[]
columnTemplates
=
null
;
Column
[]
columnTemplatesAsUnknowns
=
null
;
Column
[]
columnTemplatesAsStrings
=
null
;
if
(
columnNames
!=
null
)
{
if
(
columnNames
!=
null
)
{
columnTemplates
=
new
Column
[
columnNames
.
length
];
columnTemplatesAsUnknowns
=
new
Column
[
columnNames
.
length
];
columnTemplatesAsStrings
=
new
Column
[
columnNames
.
length
];
for
(
int
i
=
0
;
i
<
columnNames
.
length
;
++
i
)
{
for
(
int
i
=
0
;
i
<
columnNames
.
length
;
++
i
)
{
columnTemplates
[
i
]
=
new
Column
(
columnNames
[
i
],
Value
.
UNKNOWN
);
// non table expressions are fine to use unknown column type
columnTemplatesAsUnknowns
[
i
]
=
new
Column
(
columnNames
[
i
],
Value
.
UNKNOWN
);
// table expressions can't have unknown types - so we use string instead
columnTemplatesAsStrings
[
i
]
=
new
Column
(
columnNames
[
i
],
Value
.
STRING
);
}
}
}
}
if
(
view
==
null
)
{
if
(
view
==
null
)
{
view
=
new
TableView
(
getSchema
(),
id
,
viewName
,
querySQL
,
null
,
columnTemplates
,
session
,
false
,
false
);
if
(
isTableExpression
)
{
view
=
TableView
.
createTableViewMaybeRecursive
(
getSchema
(),
id
,
viewName
,
querySQL
,
null
,
columnTemplatesAsStrings
,
session
,
false
/* literalsChecked */
,
isTableExpression
,
true
/*isPersistent*/
,
db
);
}
else
{
view
=
new
TableView
(
getSchema
(),
id
,
viewName
,
querySQL
,
null
,
columnTemplatesAsUnknowns
,
session
,
false
/* allow recursive */
,
false
/* literalsChecked */
,
isTableExpression
,
true
);
}
}
else
{
}
else
{
view
.
replace
(
querySQL
,
columnTemplates
,
session
,
false
,
force
,
false
);
// TODO support isTableExpression in replace function...
view
.
replace
(
querySQL
,
columnTemplatesAsUnknowns
,
session
,
false
,
force
,
false
);
view
.
setModified
();
view
.
setModified
();
}
}
if
(
comment
!=
null
)
{
if
(
comment
!=
null
)
{
...
@@ -116,9 +131,14 @@ public class CreateView extends SchemaCommand {
...
@@ -116,9 +131,14 @@ public class CreateView extends SchemaCommand {
}
}
if
(
old
==
null
)
{
if
(
old
==
null
)
{
db
.
addSchemaObject
(
session
,
view
);
db
.
addSchemaObject
(
session
,
view
);
db
.
unlockMeta
(
session
);
}
else
{
}
else
{
db
.
updateMeta
(
session
,
view
);
db
.
updateMeta
(
session
,
view
);
}
}
// TODO: if we added any table expressions that aren't used by this view, detect them
// and drop them - otherwise they will leak and never get cleaned up.
return
0
;
return
0
;
}
}
...
...
h2/src/main/org/h2/command/ddl/DropView.java
浏览文件 @
c877fe32
...
@@ -5,6 +5,7 @@
...
@@ -5,6 +5,7 @@
*/
*/
package
org
.
h2
.
command
.
ddl
;
package
org
.
h2
.
command
.
ddl
;
import
java.util.ArrayList
;
import
org.h2.api.ErrorCode
;
import
org.h2.api.ErrorCode
;
import
org.h2.command.CommandInterface
;
import
org.h2.command.CommandInterface
;
import
org.h2.constraint.ConstraintReferential
;
import
org.h2.constraint.ConstraintReferential
;
...
@@ -67,9 +68,27 @@ public class DropView extends SchemaCommand {
...
@@ -67,9 +68,27 @@ public class DropView extends SchemaCommand {
}
}
}
}
}
}
// TODO: Where is the ConstraintReferential.CASCADE style drop processing ? It's
// supported from imported keys - but not for dependent db objects
TableView
tableView
=
(
TableView
)
view
;
ArrayList
<
Table
>
copyOfDependencies
=
new
ArrayList
<
Table
>(
tableView
.
getTables
());
view
.
lock
(
session
,
true
,
true
);
view
.
lock
(
session
,
true
,
true
);
session
.
getDatabase
().
removeSchemaObject
(
session
,
view
);
session
.
getDatabase
().
removeSchemaObject
(
session
,
view
);
// remove dependent table expressions
for
(
Table
childTable:
copyOfDependencies
)
{
if
(
TableType
.
VIEW
==
childTable
.
getTableType
())
{
TableView
childTableView
=
(
TableView
)
childTable
;
if
(
childTableView
.
isTableExpression
()
&&
childTableView
.
getName
()
!=
null
)
{
session
.
getDatabase
().
removeSchemaObject
(
session
,
childTableView
);
}
}
}
// make sure its all unlocked
session
.
getDatabase
().
unlockMeta
(
session
);
}
}
return
0
;
return
0
;
}
}
...
...
h2/src/main/org/h2/command/dml/Delete.java
浏览文件 @
c877fe32
...
@@ -53,7 +53,7 @@ public class Delete extends Prepared {
...
@@ -53,7 +53,7 @@ public class Delete extends Prepared {
this
.
condition
=
condition
;
this
.
condition
=
condition
;
}
}
public
Expression
getCondition
(
)
{
public
Expression
getCondition
()
{
return
this
.
condition
;
return
this
.
condition
;
}
}
...
@@ -136,17 +136,16 @@ public class Delete extends Prepared {
...
@@ -136,17 +136,16 @@ public class Delete extends Prepared {
public
void
prepare
()
{
public
void
prepare
()
{
if
(
condition
!=
null
)
{
if
(
condition
!=
null
)
{
condition
.
mapColumns
(
targetTableFilter
,
0
);
condition
.
mapColumns
(
targetTableFilter
,
0
);
if
(
sourceTableFilter
!=
null
)
{
if
(
sourceTableFilter
!=
null
)
{
condition
.
mapColumns
(
sourceTableFilter
,
0
);
condition
.
mapColumns
(
sourceTableFilter
,
0
);
}
}
condition
=
condition
.
optimize
(
session
);
condition
=
condition
.
optimize
(
session
);
condition
.
createIndexConditions
(
session
,
targetTableFilter
);
condition
.
createIndexConditions
(
session
,
targetTableFilter
);
}
}
TableFilter
[]
filters
;
TableFilter
[]
filters
;
if
(
sourceTableFilter
==
null
)
{
if
(
sourceTableFilter
==
null
)
{
filters
=
new
TableFilter
[]
{
targetTableFilter
};
filters
=
new
TableFilter
[]
{
targetTableFilter
};
}
}
else
{
else
{
filters
=
new
TableFilter
[]
{
targetTableFilter
,
sourceTableFilter
};
filters
=
new
TableFilter
[]
{
targetTableFilter
,
sourceTableFilter
};
}
}
PlanItem
item
=
targetTableFilter
.
getBestPlanItem
(
session
,
filters
,
0
,
PlanItem
item
=
targetTableFilter
.
getBestPlanItem
(
session
,
filters
,
0
,
...
...
h2/src/main/org/h2/command/dml/MergeUsing.java
浏览文件 @
c877fe32
...
@@ -79,7 +79,8 @@ import org.h2.value.Value;
...
@@ -79,7 +79,8 @@ import org.h2.value.Value;
* 4) Previously if neither UPDATE or DELETE clause is supplied, but INSERT is supplied - the INSERT
* 4) Previously if neither UPDATE or DELETE clause is supplied, but INSERT is supplied - the INSERT
* action is always triggered. This is because the embedded UPDATE and DELETE statement's
* action is always triggered. This is because the embedded UPDATE and DELETE statement's
* returned update row count is used to detect a matching join.
* returned update row count is used to detect a matching join.
* If neither of the two the statements are provided, no matching join is EVER detected.
* If neither of the two the statements are provided, no matching join is NEVER detected.
*
* A fix for this is now implemented as described below:
* A fix for this is now implemented as described below:
* We now generate a "matchSelect" query and use that to always detect
* We now generate a "matchSelect" query and use that to always detect
* a match join - rather than relying on UPDATE or DELETE statements.
* a match join - rather than relying on UPDATE or DELETE statements.
...
@@ -111,11 +112,12 @@ public class MergeUsing extends Prepared {
...
@@ -111,11 +112,12 @@ public class MergeUsing extends Prepared {
private
Delete
deleteCommand
;
private
Delete
deleteCommand
;
private
Insert
insertCommand
;
private
Insert
insertCommand
;
private
String
queryAlias
;
private
String
queryAlias
;
private
int
countUpdatedRows
=
0
;
private
int
countUpdatedRows
;
private
Column
[]
sourceKeys
;
private
Column
[]
sourceKeys
;
private
Select
targetMatchQuery
;
private
Select
targetMatchQuery
;
private
final
HashMap
<
Value
,
Integer
>
targetRowidsRemembered
=
new
HashMap
<>();
private
final
HashMap
<
Value
,
Integer
>
targetRowidsRemembered
=
new
HashMap
<>();
private
int
sourceQueryRowNumber
=
0
;
private
int
sourceQueryRowNumber
;
public
MergeUsing
(
Merge
merge
)
{
public
MergeUsing
(
Merge
merge
)
{
super
(
merge
.
getSession
());
super
(
merge
.
getSession
());
...
...
h2/src/main/org/h2/command/dml/Select.java
浏览文件 @
c877fe32
...
@@ -817,14 +817,14 @@ public class Select extends Query {
...
@@ -817,14 +817,14 @@ public class Select extends Query {
sort
=
prepareOrder
(
orderList
,
expressions
.
size
());
sort
=
prepareOrder
(
orderList
,
expressions
.
size
());
orderList
=
null
;
orderList
=
null
;
}
}
ColumnNamer
columnNamer
=
new
ColumnNamer
(
session
);
ColumnNamer
columnNamer
=
new
ColumnNamer
(
session
);
for
(
int
i
=
0
;
i
<
expressions
.
size
();
i
++)
{
for
(
int
i
=
0
;
i
<
expressions
.
size
();
i
++)
{
Expression
e
=
expressions
.
get
(
i
);
Expression
e
=
expressions
.
get
(
i
);
String
proposedColumnName
=
e
.
getAlias
();
String
proposedColumnName
=
e
.
getAlias
();
String
columnName
=
columnNamer
.
getColumnName
(
e
,
i
,
proposedColumnName
);
String
columnName
=
columnNamer
.
getColumnName
(
e
,
i
,
proposedColumnName
);
// if the name changed, create an alias
// if the name changed, create an alias
if
(!
columnName
.
equals
(
proposedColumnName
))
{
if
(!
columnName
.
equals
(
proposedColumnName
))
{
e
=
new
Alias
(
e
,
columnName
,
true
);
e
=
new
Alias
(
e
,
columnName
,
true
);
}
}
expressions
.
set
(
i
,
e
.
optimize
(
session
));
expressions
.
set
(
i
,
e
.
optimize
(
session
));
}
}
...
@@ -852,7 +852,7 @@ public class Select extends Query {
...
@@ -852,7 +852,7 @@ public class Select extends Query {
isQuickAggregateQuery
=
isEverything
(
optimizable
);
isQuickAggregateQuery
=
isEverything
(
optimizable
);
}
}
}
}
cost
=
preparePlan
(
session
.
isParsingView
());
cost
=
preparePlan
(
session
.
isParsing
Create
View
());
if
(
distinct
&&
session
.
getDatabase
().
getSettings
().
optimizeDistinct
&&
if
(
distinct
&&
session
.
getDatabase
().
getSettings
().
optimizeDistinct
&&
!
isGroupQuery
&&
filters
.
size
()
==
1
&&
!
isGroupQuery
&&
filters
.
size
()
==
1
&&
expressions
.
size
()
==
1
&&
condition
==
null
)
{
expressions
.
size
()
==
1
&&
condition
==
null
)
{
...
@@ -1060,14 +1060,22 @@ public class Select extends Query {
...
@@ -1060,14 +1060,22 @@ public class Select extends Query {
StatementBuilder
buff
=
new
StatementBuilder
();
StatementBuilder
buff
=
new
StatementBuilder
();
for
(
TableFilter
f
:
topFilters
)
{
for
(
TableFilter
f
:
topFilters
)
{
Table
t
=
f
.
getTable
();
Table
t
=
f
.
getTable
();
if
(
t
.
isView
()
&&
((
TableView
)
t
).
isRecursive
())
{
TableView
tableView
=
t
.
isView
()
?
(
TableView
)
t
:
null
;
buff
.
append
(
"WITH RECURSIVE "
).
append
(
t
.
getName
()).
append
(
'('
);
if
(
tableView
!=
null
&&
tableView
.
isRecursive
()
&&
tableView
.
isTableExpression
())
{
buff
.
resetCount
();
for
(
Column
c
:
t
.
getColumns
())
{
if
(
tableView
.
isPersistent
())
{
buff
.
appendExceptFirst
(
","
);
// skip the generation of plan SQL for this already recursive persistent ctes, since using a with
buff
.
append
(
c
.
getName
());
// statement will re-create the common table expression views.
continue
;
}
else
{
buff
.
append
(
"WITH RECURSIVE "
).
append
(
t
.
getName
()).
append
(
'('
);
buff
.
resetCount
();
for
(
Column
c
:
t
.
getColumns
())
{
buff
.
appendExceptFirst
(
","
);
buff
.
append
(
c
.
getName
());
}
buff
.
append
(
") AS "
).
append
(
t
.
getSQL
()).
append
(
"\n"
);
}
}
buff
.
append
(
") AS "
).
append
(
t
.
getSQL
()).
append
(
"\n"
);
}
}
}
}
buff
.
resetCount
();
buff
.
resetCount
();
...
...
h2/src/main/org/h2/engine/Database.java
浏览文件 @
c877fe32
...
@@ -90,6 +90,9 @@ import org.h2.value.ValueInt;
...
@@ -90,6 +90,9 @@ import org.h2.value.ValueInt;
public
class
Database
implements
DataHandler
{
public
class
Database
implements
DataHandler
{
private
static
int
initialPowerOffCount
;
private
static
int
initialPowerOffCount
;
private
static
final
ThreadLocal
<
Session
>
META_LOCK_DEBUGGING
=
new
ThreadLocal
<
Session
>();
private
static
final
ThreadLocal
<
Throwable
>
META_LOCK_DEBUGGING_STACK
=
new
ThreadLocal
<
Throwable
>();
/**
/**
* The default name of the system user. This name is only used as long as
* The default name of the system user. This name is only used as long as
...
@@ -296,7 +299,7 @@ public class Database implements DataHandler {
...
@@ -296,7 +299,7 @@ public class Database implements DataHandler {
e
.
fillInStackTrace
();
e
.
fillInStackTrace
();
}
}
boolean
alreadyOpen
=
e
instanceof
DbException
boolean
alreadyOpen
=
e
instanceof
DbException
&&
((
DbException
)
e
).
getErrorCode
()
==
ErrorCode
.
DATABASE_ALREADY_OPEN_1
;
&&
((
DbException
)
e
).
getErrorCode
()
==
ErrorCode
.
DATABASE_ALREADY_OPEN_1
;
if
(
alreadyOpen
)
{
if
(
alreadyOpen
)
{
stopServer
();
stopServer
();
}
}
...
@@ -765,7 +768,7 @@ public class Database implements DataHandler {
...
@@ -765,7 +768,7 @@ public class Database implements DataHandler {
Collections
.
sort
(
records
);
Collections
.
sort
(
records
);
synchronized
(
systemSession
)
{
synchronized
(
systemSession
)
{
for
(
MetaRecord
rec
:
records
)
{
for
(
MetaRecord
rec
:
records
)
{
rec
.
execute
(
this
,
systemSession
,
eventListener
);
rec
.
execute
(
this
,
systemSession
,
eventListener
);
}
}
}
}
if
(
mvStore
!=
null
)
{
if
(
mvStore
!=
null
)
{
...
@@ -899,10 +902,7 @@ public class Database implements DataHandler {
...
@@ -899,10 +902,7 @@ public class Database implements DataHandler {
}
}
}
}
private
static
final
ThreadLocal
<
Session
>
metaLockDebugging
=
new
ThreadLocal
<
Session
>();
/**
private
static
final
ThreadLocal
<
Throwable
>
metaLockDebuggingStack
=
new
ThreadLocal
<
Throwable
>();
/**
* Lock the metadata table for updates.
* Lock the metadata table for updates.
*
*
* @param session the session
* @param session the session
...
@@ -917,22 +917,23 @@ public class Database implements DataHandler {
...
@@ -917,22 +917,23 @@ public class Database implements DataHandler {
return
true
;
return
true
;
}
}
if
(
SysProperties
.
CHECK2
)
{
if
(
SysProperties
.
CHECK2
)
{
final
Session
prev
=
metaLockDebugging
.
get
();
final
Session
prev
=
META_LOCK_DEBUGGING
.
get
();
if
(
prev
==
null
)
{
if
(
prev
==
null
)
{
metaLockDebugging
.
set
(
session
);
META_LOCK_DEBUGGING
.
set
(
session
);
metaLockDebuggingStack
.
set
(
new
Throwable
());
META_LOCK_DEBUGGING_STACK
.
set
(
new
Throwable
(
"Last meta lock granted in this stack trace, "
+
"this is debug information for following IllegalStateException"
));
}
else
if
(
prev
!=
session
)
{
}
else
if
(
prev
!=
session
)
{
metaLockDebuggingStack
.
get
().
printStackTrace
();
META_LOCK_DEBUGGING_STACK
.
get
().
printStackTrace
();
throw
new
IllegalStateException
(
"meta currently locked by "
throw
new
IllegalStateException
(
"meta currently locked by "
+
prev
+
prev
+
", sessionid="
+
prev
.
getId
()
+
" and trying to be locked by different session, "
+
" and trying to be locked by different session, "
+
session
+
" on same thread"
);
+
session
+
", sessionid="
+
session
.
getId
()
+
" on same thread"
);
}
}
}
}
boolean
wasLocked
=
meta
.
lock
(
session
,
true
,
true
);
boolean
wasLocked
=
meta
.
lock
(
session
,
true
,
true
);
return
wasLocked
;
return
wasLocked
;
}
}
/**
/**
* Unlock the metadata table.
* Unlock the metadata table.
*
*
...
@@ -952,9 +953,9 @@ public class Database implements DataHandler {
...
@@ -952,9 +953,9 @@ public class Database implements DataHandler {
*/
*/
public
void
unlockMetaDebug
(
Session
session
)
{
public
void
unlockMetaDebug
(
Session
session
)
{
if
(
SysProperties
.
CHECK2
)
{
if
(
SysProperties
.
CHECK2
)
{
if
(
metaLockDebugging
.
get
()
==
session
)
{
if
(
META_LOCK_DEBUGGING
.
get
()
==
session
)
{
metaLockDebugging
.
set
(
null
);
META_LOCK_DEBUGGING
.
set
(
null
);
metaLockDebuggingStack
.
set
(
null
);
META_LOCK_DEBUGGING_STACK
.
set
(
null
);
}
}
}
}
}
}
...
@@ -1911,13 +1912,14 @@ public class Database implements DataHandler {
...
@@ -1911,13 +1912,14 @@ public class Database implements DataHandler {
t
.
getSQL
());
t
.
getSQL
());
}
}
obj
.
removeChildrenAndResources
(
session
);
obj
.
removeChildrenAndResources
(
session
);
}
}
removeMeta
(
session
,
id
);
removeMeta
(
session
,
id
);
}
}
}
}
/**
/**
* Check if this database disk-based.
* Check if this database
is
disk-based.
*
*
* @return true if it is disk-based, false it it is in-memory only.
* @return true if it is disk-based, false it it is in-memory only.
*/
*/
...
...
h2/src/main/org/h2/engine/Session.java
浏览文件 @
c877fe32
...
@@ -6,12 +6,14 @@
...
@@ -6,12 +6,14 @@
package
org
.
h2
.
engine
;
package
org
.
h2
.
engine
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.Deque
;
import
java.util.HashMap
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.HashSet
;
import
java.util.Iterator
;
import
java.util.Iterator
;
import
java.util.LinkedList
;
import
java.util.LinkedList
;
import
java.util.Map
;
import
java.util.Map
;
import
java.util.Random
;
import
java.util.Random
;
import
java.util.ArrayDeque
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.TimeUnit
;
import
org.h2.api.ErrorCode
;
import
org.h2.api.ErrorCode
;
import
org.h2.command.Command
;
import
org.h2.command.Command
;
...
@@ -121,6 +123,7 @@ public class Session extends SessionWithState {
...
@@ -121,6 +123,7 @@ public class Session extends SessionWithState {
private
long
modificationMetaID
=
-
1
;
private
long
modificationMetaID
=
-
1
;
private
SubQueryInfo
subQueryInfo
;
private
SubQueryInfo
subQueryInfo
;
private
int
parsingView
;
private
int
parsingView
;
private
Deque
<
String
>
viewNameStack
=
new
ArrayDeque
<
String
>();
private
int
preparingQueryExpression
;
private
int
preparingQueryExpression
;
private
volatile
SmallLRUCache
<
Object
,
ViewIndex
>
viewIndexCache
;
private
volatile
SmallLRUCache
<
Object
,
ViewIndex
>
viewIndexCache
;
private
HashMap
<
Object
,
ViewIndex
>
subQueryIndexCache
;
private
HashMap
<
Object
,
ViewIndex
>
subQueryIndexCache
;
...
@@ -226,13 +229,25 @@ public class Session extends SessionWithState {
...
@@ -226,13 +229,25 @@ public class Session extends SessionWithState {
return
subQueryInfo
;
return
subQueryInfo
;
}
}
public
void
setParsing
View
(
boolean
parsingView
)
{
public
void
setParsing
CreateView
(
boolean
parsingView
,
String
viewName
)
{
// It can be recursive, thus implemented as counter.
// It can be recursive, thus implemented as counter.
this
.
parsingView
+=
parsingView
?
1
:
-
1
;
this
.
parsingView
+=
parsingView
?
1
:
-
1
;
assert
this
.
parsingView
>=
0
;
assert
this
.
parsingView
>=
0
;
if
(
parsingView
)
{
viewNameStack
.
push
(
viewName
);
}
else
{
assert
viewName
.
equals
(
viewNameStack
.
peek
());
viewNameStack
.
pop
();
}
}
public
String
getParsingCreateViewName
()
{
if
(
viewNameStack
.
size
()
==
0
)
{
return
null
;
}
return
viewNameStack
.
peek
();
}
}
public
boolean
isParsingView
()
{
public
boolean
isParsing
Create
View
()
{
assert
parsingView
>=
0
;
assert
parsingView
>=
0
;
return
parsingView
!=
0
;
return
parsingView
!=
0
;
}
}
...
@@ -679,7 +694,8 @@ public class Session extends SessionWithState {
...
@@ -679,7 +694,8 @@ public class Session extends SessionWithState {
for
(
Table
table
:
tablesToAnalyze
)
{
for
(
Table
table
:
tablesToAnalyze
)
{
Analyze
.
analyzeTable
(
this
,
table
,
rows
,
false
);
Analyze
.
analyzeTable
(
this
,
table
,
rows
,
false
);
}
}
database
.
unlockMeta
(
this
);
// analyze can lock the meta
// analyze can lock the meta
database
.
unlockMeta
(
this
);
}
}
tablesToAnalyze
=
null
;
tablesToAnalyze
=
null
;
}
}
...
...
h2/src/main/org/h2/index/ViewIndex.java
浏览文件 @
c877fe32
...
@@ -8,7 +8,6 @@ package org.h2.index;
...
@@ -8,7 +8,6 @@ package org.h2.index;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.HashSet
;
import
java.util.HashSet
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.TimeUnit
;
import
org.h2.api.ErrorCode
;
import
org.h2.api.ErrorCode
;
import
org.h2.command.Parser
;
import
org.h2.command.Parser
;
import
org.h2.command.Prepared
;
import
org.h2.command.Prepared
;
...
@@ -182,10 +181,10 @@ public class ViewIndex extends BaseIndex implements SpatialIndex {
...
@@ -182,10 +181,10 @@ public class ViewIndex extends BaseIndex implements SpatialIndex {
private
Cursor
findRecursive
(
SearchRow
first
,
SearchRow
last
)
{
private
Cursor
findRecursive
(
SearchRow
first
,
SearchRow
last
)
{
assert
recursive
;
assert
recursive
;
ResultInterface
recResult
=
view
.
getRecursiveResult
();
ResultInterface
rec
ursive
Result
=
view
.
getRecursiveResult
();
if
(
recResult
!=
null
)
{
if
(
rec
ursive
Result
!=
null
)
{
recResult
.
reset
();
rec
ursive
Result
.
reset
();
return
new
ViewCursor
(
this
,
recResult
,
first
,
last
);
return
new
ViewCursor
(
this
,
rec
ursive
Result
,
first
,
last
);
}
}
if
(
query
==
null
)
{
if
(
query
==
null
)
{
Parser
parser
=
new
Parser
(
createSession
);
Parser
parser
=
new
Parser
(
createSession
);
...
@@ -200,35 +199,39 @@ public class ViewIndex extends BaseIndex implements SpatialIndex {
...
@@ -200,35 +199,39 @@ public class ViewIndex extends BaseIndex implements SpatialIndex {
}
}
SelectUnion
union
=
(
SelectUnion
)
query
;
SelectUnion
union
=
(
SelectUnion
)
query
;
Query
left
=
union
.
getLeft
();
Query
left
=
union
.
getLeft
();
left
.
setNeverLazy
(
true
);
// to ensure the last result is not closed
// to ensure the last result is not closed
left
.
disableCache
();
left
.
disableCache
();
ResultInterface
r
=
left
.
query
(
0
);
ResultInterface
r
esultInterface
=
left
.
query
(
0
);
LocalResult
r
esult
=
union
.
getEmptyResult
();
LocalResult
localR
esult
=
union
.
getEmptyResult
();
// ensure it is not written to disk,
// ensure it is not written to disk,
// because it is not closed normally
// because it is not closed normally
result
.
setMaxMemoryRows
(
Integer
.
MAX_VALUE
);
localResult
.
setMaxMemoryRows
(
Integer
.
MAX_VALUE
);
while
(
r
.
next
())
{
while
(
resultInterface
.
next
())
{
result
.
addRow
(
r
.
currentRow
());
Value
[]
cr
=
resultInterface
.
currentRow
();
localResult
.
addRow
(
cr
);
}
}
Query
right
=
union
.
getRight
();
Query
right
=
union
.
getRight
();
r
.
reset
();
right
.
setNeverLazy
(
true
);
view
.
setRecursiveResult
(
r
);
resultInterface
.
reset
();
view
.
setRecursiveResult
(
resultInterface
);
// to ensure the last result is not closed
// to ensure the last result is not closed
right
.
disableCache
();
right
.
disableCache
();
while
(
true
)
{
while
(
true
)
{
r
=
right
.
query
(
0
);
r
esultInterface
=
right
.
query
(
0
);
if
(!
r
.
hasNext
())
{
if
(!
r
esultInterface
.
hasNext
())
{
break
;
break
;
}
}
while
(
r
.
next
())
{
while
(
resultInterface
.
next
())
{
result
.
addRow
(
r
.
currentRow
());
Value
[]
cr
=
resultInterface
.
currentRow
();
localResult
.
addRow
(
cr
);
}
}
r
.
reset
();
r
esultInterface
.
reset
();
view
.
setRecursiveResult
(
r
);
view
.
setRecursiveResult
(
r
esultInterface
);
}
}
view
.
setRecursiveResult
(
null
);
view
.
setRecursiveResult
(
null
);
r
esult
.
done
();
localR
esult
.
done
();
return
new
ViewCursor
(
this
,
r
esult
,
first
,
last
);
return
new
ViewCursor
(
this
,
localR
esult
,
first
,
last
);
}
}
/**
/**
...
...
h2/src/main/org/h2/mvstore/db/MVTable.java
浏览文件 @
c877fe32
...
@@ -48,7 +48,6 @@ import org.h2.value.Value;
...
@@ -48,7 +48,6 @@ import org.h2.value.Value;
* A table stored in a MVStore.
* A table stored in a MVStore.
*/
*/
public
class
MVTable
extends
TableBase
{
public
class
MVTable
extends
TableBase
{
/**
/**
* The table name this thread is waiting to lock.
* The table name this thread is waiting to lock.
*/
*/
...
@@ -63,7 +62,32 @@ public class MVTable extends TableBase {
...
@@ -63,7 +62,32 @@ public class MVTable extends TableBase {
* The tables names this thread has a shared lock on.
* The tables names this thread has a shared lock on.
*/
*/
public
static
final
DebuggingThreadLocal
<
ArrayList
<
String
>>
SHARED_LOCKS
;
public
static
final
DebuggingThreadLocal
<
ArrayList
<
String
>>
SHARED_LOCKS
;
/**
* The type of trace lock events
*/
private
enum
TraceLockEvent
{
TRACE_LOCK_OK
(
"ok"
),
TRACE_LOCK_WAITING_FOR
(
"waiting for"
),
TRACE_LOCK_REQUESTING_FOR
(
"requesting for"
),
TRACE_LOCK_TIMEOUT_AFTER
(
"timeout after "
),
TRACE_LOCK_UNLOCK
(
"unlock"
),
TRACE_LOCK_ADDED_FOR
(
"added for"
),
TRACE_LOCK_ADD_UPGRADED_FOR
(
"add (upgraded) for "
);
private
final
String
eventText
;
TraceLockEvent
(
String
eventText
)
{
this
.
eventText
=
eventText
;
}
public
String
getEventText
()
{
return
eventText
;
}
}
private
static
final
String
NO_EXTRA_INFO
=
""
;
static
{
static
{
if
(
SysProperties
.
THREAD_DEADLOCK_DETECTOR
)
{
if
(
SysProperties
.
THREAD_DEADLOCK_DETECTOR
)
{
WAITING_FOR_LOCK
=
new
DebuggingThreadLocal
<>();
WAITING_FOR_LOCK
=
new
DebuggingThreadLocal
<>();
...
@@ -192,7 +216,7 @@ public class MVTable extends TableBase {
...
@@ -192,7 +216,7 @@ public class MVTable extends TableBase {
}
}
private
void
doLock1
(
Session
session
,
int
lockMode
,
boolean
exclusive
)
{
private
void
doLock1
(
Session
session
,
int
lockMode
,
boolean
exclusive
)
{
traceLock
(
session
,
exclusive
,
"requesting for"
);
traceLock
(
session
,
exclusive
,
TraceLockEvent
.
TRACE_LOCK_REQUESTING_FOR
,
NO_EXTRA_INFO
);
// don't get the current time unless necessary
// don't get the current time unless necessary
long
max
=
0
;
long
max
=
0
;
boolean
checkDeadlock
=
false
;
boolean
checkDeadlock
=
false
;
...
@@ -219,11 +243,11 @@ public class MVTable extends TableBase {
...
@@ -219,11 +243,11 @@ public class MVTable extends TableBase {
max
=
now
+
TimeUnit
.
MILLISECONDS
.
toNanos
(
session
.
getLockTimeout
());
max
=
now
+
TimeUnit
.
MILLISECONDS
.
toNanos
(
session
.
getLockTimeout
());
}
else
if
(
now
>=
max
)
{
}
else
if
(
now
>=
max
)
{
traceLock
(
session
,
exclusive
,
traceLock
(
session
,
exclusive
,
"timeout after "
+
session
.
getLockTimeout
());
TraceLockEvent
.
TRACE_LOCK_TIMEOUT_AFTER
,
NO_EXTRA_INFO
+
session
.
getLockTimeout
());
throw
DbException
.
get
(
ErrorCode
.
LOCK_TIMEOUT_1
,
getName
());
throw
DbException
.
get
(
ErrorCode
.
LOCK_TIMEOUT_1
,
getName
());
}
}
try
{
try
{
traceLock
(
session
,
exclusive
,
"waiting for"
);
traceLock
(
session
,
exclusive
,
TraceLockEvent
.
TRACE_LOCK_WAITING_FOR
,
NO_EXTRA_INFO
);
if
(
database
.
getLockMode
()
==
Constants
.
LOCK_MODE_TABLE_GC
)
{
if
(
database
.
getLockMode
()
==
Constants
.
LOCK_MODE_TABLE_GC
)
{
for
(
int
i
=
0
;
i
<
20
;
i
++)
{
for
(
int
i
=
0
;
i
<
20
;
i
++)
{
long
free
=
Runtime
.
getRuntime
().
freeMemory
();
long
free
=
Runtime
.
getRuntime
().
freeMemory
();
...
@@ -251,7 +275,7 @@ public class MVTable extends TableBase {
...
@@ -251,7 +275,7 @@ public class MVTable extends TableBase {
if
(
exclusive
)
{
if
(
exclusive
)
{
if
(
lockExclusiveSession
==
null
)
{
if
(
lockExclusiveSession
==
null
)
{
if
(
lockSharedSessions
.
isEmpty
())
{
if
(
lockSharedSessions
.
isEmpty
())
{
traceLock
(
session
,
exclusive
,
"added for"
);
traceLock
(
session
,
exclusive
,
TraceLockEvent
.
TRACE_LOCK_ADDED_FOR
,
NO_EXTRA_INFO
);
session
.
addLock
(
this
);
session
.
addLock
(
this
);
lockExclusiveSession
=
session
;
lockExclusiveSession
=
session
;
if
(
SysProperties
.
THREAD_DEADLOCK_DETECTOR
)
{
if
(
SysProperties
.
THREAD_DEADLOCK_DETECTOR
)
{
...
@@ -263,7 +287,7 @@ public class MVTable extends TableBase {
...
@@ -263,7 +287,7 @@ public class MVTable extends TableBase {
return
true
;
return
true
;
}
else
if
(
lockSharedSessions
.
size
()
==
1
&&
}
else
if
(
lockSharedSessions
.
size
()
==
1
&&
lockSharedSessions
.
containsKey
(
session
))
{
lockSharedSessions
.
containsKey
(
session
))
{
traceLock
(
session
,
exclusive
,
"add (upgraded) for "
);
traceLock
(
session
,
exclusive
,
TraceLockEvent
.
TRACE_LOCK_ADD_UPGRADED_FOR
,
NO_EXTRA_INFO
);
lockExclusiveSession
=
session
;
lockExclusiveSession
=
session
;
if
(
SysProperties
.
THREAD_DEADLOCK_DETECTOR
)
{
if
(
SysProperties
.
THREAD_DEADLOCK_DETECTOR
)
{
if
(
EXCLUSIVE_LOCKS
.
get
()
==
null
)
{
if
(
EXCLUSIVE_LOCKS
.
get
()
==
null
)
{
...
@@ -289,7 +313,7 @@ public class MVTable extends TableBase {
...
@@ -289,7 +313,7 @@ public class MVTable extends TableBase {
}
}
}
}
if
(!
lockSharedSessions
.
containsKey
(
session
))
{
if
(!
lockSharedSessions
.
containsKey
(
session
))
{
traceLock
(
session
,
exclusive
,
"ok"
);
traceLock
(
session
,
exclusive
,
TraceLockEvent
.
TRACE_LOCK_OK
,
NO_EXTRA_INFO
);
session
.
addLock
(
this
);
session
.
addLock
(
this
);
lockSharedSessions
.
put
(
session
,
session
);
lockSharedSessions
.
put
(
session
,
session
);
if
(
SysProperties
.
THREAD_DEADLOCK_DETECTOR
)
{
if
(
SysProperties
.
THREAD_DEADLOCK_DETECTOR
)
{
...
@@ -387,10 +411,10 @@ public class MVTable extends TableBase {
...
@@ -387,10 +411,10 @@ public class MVTable extends TableBase {
}
}
}
}
private
void
traceLock
(
Session
session
,
boolean
exclusive
,
String
s
)
{
private
void
traceLock
(
Session
session
,
boolean
exclusive
,
TraceLockEvent
eventEnum
,
String
extraInfo
)
{
if
(
traceLock
.
isDebugEnabled
())
{
if
(
traceLock
.
isDebugEnabled
())
{
traceLock
.
debug
(
"{0} {1} {2} {3}"
,
session
.
getId
(),
traceLock
.
debug
(
"{0} {1} {2} {3}"
,
session
.
getId
(),
exclusive
?
"exclusive write lock"
:
"shared read lock"
,
s
,
exclusive
?
"exclusive write lock"
:
"shared read lock"
,
eventEnum
.
getEventText
()
,
getName
());
getName
());
}
}
}
}
...
@@ -404,11 +428,11 @@ public class MVTable extends TableBase {
...
@@ -404,11 +428,11 @@ public class MVTable extends TableBase {
public
boolean
isLockedExclusivelyBy
(
Session
session
)
{
public
boolean
isLockedExclusivelyBy
(
Session
session
)
{
return
lockExclusiveSession
==
session
;
return
lockExclusiveSession
==
session
;
}
}
@Override
@Override
public
void
unlock
(
Session
s
)
{
public
void
unlock
(
Session
s
)
{
if
(
database
!=
null
)
{
if
(
database
!=
null
)
{
traceLock
(
s
,
lockExclusiveSession
==
s
,
"unlock"
);
traceLock
(
s
,
lockExclusiveSession
==
s
,
TraceLockEvent
.
TRACE_LOCK_UNLOCK
,
NO_EXTRA_INFO
);
if
(
lockExclusiveSession
==
s
)
{
if
(
lockExclusiveSession
==
s
)
{
lockExclusiveSession
=
null
;
lockExclusiveSession
=
null
;
if
(
SysProperties
.
THREAD_DEADLOCK_DETECTOR
)
{
if
(
SysProperties
.
THREAD_DEADLOCK_DETECTOR
)
{
...
...
h2/src/main/org/h2/table/Table.java
浏览文件 @
c877fe32
...
@@ -86,6 +86,7 @@ public abstract class Table extends SchemaObjectBase {
...
@@ -86,6 +86,7 @@ public abstract class Table extends SchemaObjectBase {
private
boolean
checkForeignKeyConstraints
=
true
;
private
boolean
checkForeignKeyConstraints
=
true
;
private
boolean
onCommitDrop
,
onCommitTruncate
;
private
boolean
onCommitDrop
,
onCommitTruncate
;
private
volatile
Row
nullRow
;
private
volatile
Row
nullRow
;
private
boolean
tableExpression
;
public
Table
(
Schema
schema
,
int
id
,
String
name
,
boolean
persistIndexes
,
public
Table
(
Schema
schema
,
int
id
,
String
name
,
boolean
persistIndexes
,
boolean
persistData
)
{
boolean
persistData
)
{
...
@@ -195,7 +196,6 @@ public abstract class Table extends SchemaObjectBase {
...
@@ -195,7 +196,6 @@ public abstract class Table extends SchemaObjectBase {
* @param operation the operation
* @param operation the operation
* @param row the row
* @param row the row
*/
*/
@SuppressWarnings
(
"unused"
)
public
void
commit
(
short
operation
,
Row
row
)
{
public
void
commit
(
short
operation
,
Row
row
)
{
// nothing to do
// nothing to do
}
}
...
@@ -233,7 +233,6 @@ public abstract class Table extends SchemaObjectBase {
...
@@ -233,7 +233,6 @@ public abstract class Table extends SchemaObjectBase {
* @param allColumnsSet all columns
* @param allColumnsSet all columns
* @return the scan index
* @return the scan index
*/
*/
@SuppressWarnings
(
"unused"
)
public
Index
getScanIndex
(
Session
session
,
int
[]
masks
,
public
Index
getScanIndex
(
Session
session
,
int
[]
masks
,
TableFilter
[]
filters
,
int
filter
,
SortOrder
sortOrder
,
TableFilter
[]
filters
,
int
filter
,
SortOrder
sortOrder
,
HashSet
<
Column
>
allColumnsSet
)
{
HashSet
<
Column
>
allColumnsSet
)
{
...
@@ -465,7 +464,6 @@ public abstract class Table extends SchemaObjectBase {
...
@@ -465,7 +464,6 @@ public abstract class Table extends SchemaObjectBase {
* @param session the session
* @param session the session
* @return true if it is
* @return true if it is
*/
*/
@SuppressWarnings
(
"unused"
)
public
boolean
isLockedExclusivelyBy
(
Session
session
)
{
public
boolean
isLockedExclusivelyBy
(
Session
session
)
{
return
false
;
return
false
;
}
}
...
@@ -836,7 +834,7 @@ public abstract class Table extends SchemaObjectBase {
...
@@ -836,7 +834,7 @@ public abstract class Table extends SchemaObjectBase {
}
}
/**
/**
* Remove the given view from the list.
* Remove the given view from the
dependent views
list.
*
*
* @param view the view to remove
* @param view the view to remove
*/
*/
...
@@ -1166,7 +1164,6 @@ public abstract class Table extends SchemaObjectBase {
...
@@ -1166,7 +1164,6 @@ public abstract class Table extends SchemaObjectBase {
* @return an object array with the sessions involved in the deadlock, or
* @return an object array with the sessions involved in the deadlock, or
* null
* null
*/
*/
@SuppressWarnings
(
"unused"
)
public
ArrayList
<
Session
>
checkDeadlock
(
Session
session
,
Session
clash
,
public
ArrayList
<
Session
>
checkDeadlock
(
Session
session
,
Session
clash
,
Set
<
Session
>
visited
)
{
Set
<
Session
>
visited
)
{
return
null
;
return
null
;
...
@@ -1242,5 +1239,12 @@ public abstract class Table extends SchemaObjectBase {
...
@@ -1242,5 +1239,12 @@ public abstract class Table extends SchemaObjectBase {
public
boolean
isMVStore
()
{
public
boolean
isMVStore
()
{
return
false
;
return
false
;
}
}
public
void
setTableExpression
(
boolean
tableExpression
)
{
this
.
tableExpression
=
tableExpression
;
}
public
boolean
isTableExpression
()
{
return
tableExpression
;
}
}
}
h2/src/main/org/h2/table/TableView.java
浏览文件 @
c877fe32
差异被折叠。
点击展开。
h2/src/test/org/h2/test/TestAll.java
浏览文件 @
c877fe32
...
@@ -54,6 +54,7 @@ import org.h2.test.db.TestOpenClose;
...
@@ -54,6 +54,7 @@ import org.h2.test.db.TestOpenClose;
import
org.h2.test.db.TestOptimizations
;
import
org.h2.test.db.TestOptimizations
;
import
org.h2.test.db.TestOptimizerHints
;
import
org.h2.test.db.TestOptimizerHints
;
import
org.h2.test.db.TestOutOfMemory
;
import
org.h2.test.db.TestOutOfMemory
;
import
org.h2.test.db.TestPersistentCommonTableExpressions
;
import
org.h2.test.db.TestPowerOff
;
import
org.h2.test.db.TestPowerOff
;
import
org.h2.test.db.TestQueryCache
;
import
org.h2.test.db.TestQueryCache
;
import
org.h2.test.db.TestReadOnly
;
import
org.h2.test.db.TestReadOnly
;
...
@@ -762,6 +763,10 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
...
@@ -762,6 +763,10 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
addTest
(
new
TestReadOnly
());
addTest
(
new
TestReadOnly
());
addTest
(
new
TestRecursiveQueries
());
addTest
(
new
TestRecursiveQueries
());
addTest
(
new
TestGeneralCommonTableQueries
());
addTest
(
new
TestGeneralCommonTableQueries
());
if
(!
memory
)
{
// requires persistent store for reconnection tests
addTest
(
new
TestPersistentCommonTableExpressions
());
}
addTest
(
new
TestRights
());
addTest
(
new
TestRights
());
addTest
(
new
TestRunscript
());
addTest
(
new
TestRunscript
());
addTest
(
new
TestSQLInjection
());
addTest
(
new
TestSQLInjection
());
...
...
h2/src/test/org/h2/test/TestBase.java
浏览文件 @
c877fe32
...
@@ -124,7 +124,6 @@ public abstract class TestBase {
...
@@ -124,7 +124,6 @@ public abstract class TestBase {
*
*
* @param seed the random seed value
* @param seed the random seed value
*/
*/
@SuppressWarnings
(
"unused"
)
public
void
testCase
(
int
seed
)
throws
Exception
{
public
void
testCase
(
int
seed
)
throws
Exception
{
// do nothing
// do nothing
}
}
...
...
h2/src/test/org/h2/test/db/AbstractBaseForCommonTableExpressions.java
0 → 100755
浏览文件 @
c877fe32
package
org
.
h2
.
test
.
db
;
import
java.sql.Connection
;
import
java.sql.PreparedStatement
;
import
java.sql.ResultSet
;
import
java.sql.SQLException
;
import
java.sql.Statement
;
import
org.h2.test.TestBase
;
/**
* Base class for common table expression tests
*/
public
abstract
class
AbstractBaseForCommonTableExpressions
extends
TestBase
{
protected
void
testRepeatedQueryWithSetup
(
int
maxRetries
,
String
[]
expectedRowData
,
String
[]
expectedColumnNames
,
int
expectedNumbeOfRows
,
String
setupSQL
,
String
withQuery
,
int
closeAndReopenDatabaseConnectionOnIteration
,
String
[]
expectedColumnTypes
)
throws
SQLException
{
deleteDb
(
"commonTableExpressionQueries"
);
Connection
conn
=
getConnection
(
"commonTableExpressionQueries"
);
PreparedStatement
prep
;
ResultSet
rs
;
for
(
int
queryRunTries
=
1
;
queryRunTries
<=
maxRetries
;
queryRunTries
++)
{
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
setupSQL
);
stat
.
close
();
// close and re-open connection for one iteration to make sure the query work between connections
if
(
queryRunTries
==
closeAndReopenDatabaseConnectionOnIteration
)
{
conn
.
close
();
conn
=
getConnection
(
"commonTableExpressionQueries"
);
}
prep
=
conn
.
prepareStatement
(
withQuery
);
rs
=
prep
.
executeQuery
();
for
(
int
columnIndex
=
1
;
columnIndex
<=
rs
.
getMetaData
().
getColumnCount
();
columnIndex
++)
{
assertTrue
(
rs
.
getMetaData
().
getColumnLabel
(
columnIndex
)
!=
null
);
assertEquals
(
expectedColumnNames
[
columnIndex
-
1
],
rs
.
getMetaData
().
getColumnLabel
(
columnIndex
));
assertEquals
(
"wrongly type column "
+
rs
.
getMetaData
().
getColumnLabel
(
columnIndex
)+
" on iteration#"
+
queryRunTries
,
expectedColumnTypes
[
columnIndex
-
1
],
rs
.
getMetaData
().
getColumnTypeName
(
columnIndex
));
}
int
rowNdx
=
0
;
while
(
rs
.
next
())
{
StringBuffer
buf
=
new
StringBuffer
();
for
(
int
columnIndex
=
1
;
columnIndex
<=
rs
.
getMetaData
().
getColumnCount
();
columnIndex
++)
{
buf
.
append
(
"|"
+
rs
.
getString
(
columnIndex
));
}
assertEquals
(
expectedRowData
[
rowNdx
],
buf
.
toString
());
rowNdx
++;
}
assertEquals
(
expectedNumbeOfRows
,
rowNdx
);
rs
.
close
();
prep
.
close
();
}
conn
.
close
();
deleteDb
(
"commonTableExpressionQueries"
);
}
}
h2/src/test/org/h2/test/db/TestGeneralCommonTableQueries.java
浏览文件 @
c877fe32
差异被折叠。
点击展开。
h2/src/test/org/h2/test/db/TestPersistentCommonTableExpressions.java
0 → 100755
浏览文件 @
c877fe32
差异被折叠。
点击展开。
h2/src/test/org/h2/test/mvcc/TestMvccMultiThreaded2.java
浏览文件 @
c877fe32
...
@@ -20,6 +20,10 @@ import org.h2.util.IOUtils;
...
@@ -20,6 +20,10 @@ import org.h2.util.IOUtils;
*/
*/
public
class
TestMvccMultiThreaded2
extends
TestBase
{
public
class
TestMvccMultiThreaded2
extends
TestBase
{
private
static
final
int
TEST_THREAD_COUNT
=
100
;
private
static
final
int
TEST_TIME_SECONDS
=
60
;
private
static
final
boolean
DISPLAY_STATS
=
false
;
private
static
final
String
URL
=
";MVCC=TRUE;LOCK_TIMEOUT=120000;MULTI_THREADED=TRUE"
;
private
static
final
String
URL
=
";MVCC=TRUE;LOCK_TIMEOUT=120000;MULTI_THREADED=TRUE"
;
/**
/**
...
@@ -62,21 +66,49 @@ public class TestMvccMultiThreaded2 extends TestBase {
...
@@ -62,21 +66,49 @@ public class TestMvccMultiThreaded2 extends TestBase {
conn
.
commit
();
conn
.
commit
();
ArrayList
<
SelectForUpdate
>
threads
=
new
ArrayList
<>();
ArrayList
<
SelectForUpdate
>
threads
=
new
ArrayList
<>();
for
(
int
i
=
0
;
i
<
100
;
i
++)
{
for
(
int
i
=
0
;
i
<
TEST_THREAD_COUNT
;
i
++)
{
SelectForUpdate
sfu
=
new
SelectForUpdate
();
SelectForUpdate
sfu
=
new
SelectForUpdate
();
sfu
.
setName
(
"Test SelectForUpdate Thread#"
+
i
);
threads
.
add
(
sfu
);
threads
.
add
(
sfu
);
sfu
.
start
();
sfu
.
start
();
}
}
// give any of the 100 threads a chance to start by yielding the processor to them
Thread
.
yield
();
// gather stats on threads after they finished
@SuppressWarnings
(
"unused"
)
int
minProcessed
=
Integer
.
MAX_VALUE
,
maxProcessed
=
0
,
totalProcessed
=
0
;
for
(
SelectForUpdate
sfu
:
threads
)
{
for
(
SelectForUpdate
sfu
:
threads
)
{
// make sure all threads have stopped by joining with them
sfu
.
join
();
sfu
.
join
();
totalProcessed
+=
sfu
.
iterationsProcessed
;
if
(
sfu
.
iterationsProcessed
>
maxProcessed
)
{
maxProcessed
=
sfu
.
iterationsProcessed
;
}
if
(
sfu
.
iterationsProcessed
<
minProcessed
)
{
minProcessed
=
sfu
.
iterationsProcessed
;
}
}
if
(
DISPLAY_STATS
)
{
System
.
out
.
println
(
String
.
format
(
"+ INFO: TestMvccMultiThreaded2 RUN STATS threads=%d, minProcessed=%d, maxProcessed=%d, "
+
"totalProcessed=%d, averagePerThread=%d, averagePerThreadPerSecond=%d\n"
,
TEST_THREAD_COUNT
,
minProcessed
,
maxProcessed
,
totalProcessed
,
totalProcessed
/
TEST_THREAD_COUNT
,
totalProcessed
/(
TEST_THREAD_COUNT
*
TEST_TIME_SECONDS
)));
}
}
IOUtils
.
closeSilently
(
conn
);
IOUtils
.
closeSilently
(
conn
);
deleteDb
(
getTestName
());
deleteDb
(
getTestName
());
}
}
/**
* Worker test thread selecting for update
*/
private
class
SelectForUpdate
extends
Thread
{
private
class
SelectForUpdate
extends
Thread
{
public
int
iterationsProcessed
;
@Override
@Override
public
void
run
()
{
public
void
run
()
{
...
@@ -86,6 +118,10 @@ public class TestMvccMultiThreaded2 extends TestBase {
...
@@ -86,6 +118,10 @@ public class TestMvccMultiThreaded2 extends TestBase {
try
{
try
{
conn
=
getConnection
(
getTestName
()
+
URL
);
conn
=
getConnection
(
getTestName
()
+
URL
);
conn
.
setAutoCommit
(
false
);
conn
.
setAutoCommit
(
false
);
// give the other threads a chance to start up before going into our work loop
Thread
.
yield
();
while
(!
done
)
{
while
(!
done
)
{
try
{
try
{
PreparedStatement
ps
=
conn
.
prepareStatement
(
PreparedStatement
ps
=
conn
.
prepareStatement
(
...
@@ -97,17 +133,22 @@ public class TestMvccMultiThreaded2 extends TestBase {
...
@@ -97,17 +133,22 @@ public class TestMvccMultiThreaded2 extends TestBase {
assertTrue
(
rs
.
getInt
(
2
)
==
100
);
assertTrue
(
rs
.
getInt
(
2
)
==
100
);
conn
.
commit
();
conn
.
commit
();
iterationsProcessed
++;
long
now
=
System
.
currentTimeMillis
();
long
now
=
System
.
currentTimeMillis
();
if
(
now
-
start
>
1000
*
60
)
if
(
now
-
start
>
1000
*
TEST_TIME_SECONDS
)
{
done
=
true
;
done
=
true
;
}
}
catch
(
JdbcSQLException
e1
)
{
}
catch
(
JdbcSQLException
e1
)
{
throw
e1
;
throw
e1
;
}
}
}
}
}
catch
(
SQLException
e
)
{
}
catch
(
SQLException
e
)
{
TestBase
.
logError
(
"error"
,
e
);
TestBase
.
logError
(
"SQL error from thread "
+
getName
(),
e
);
}
}
catch
(
Exception
e
)
{
TestBase
.
logError
(
"General error from thread "
+
getName
(),
e
);
throw
e
;
}
IOUtils
.
closeSilently
(
conn
);
IOUtils
.
closeSilently
(
conn
);
}
}
}
}
...
...
h2/src/test/org/h2/test/scripts/TestScript.java
浏览文件 @
c877fe32
...
@@ -133,6 +133,9 @@ public class TestScript extends TestBase {
...
@@ -133,6 +133,9 @@ public class TestScript extends TestBase {
"parsedatetime"
,
"quarter"
,
"second"
,
"week"
,
"year"
})
{
"parsedatetime"
,
"quarter"
,
"second"
,
"week"
,
"year"
})
{
testScript
(
"functions/timeanddate/"
+
s
+
".sql"
);
testScript
(
"functions/timeanddate/"
+
s
+
".sql"
);
}
}
for
(
String
s
:
new
String
[]
{
"with"
,
"mergeUsing"
})
{
testScript
(
"dml/"
+
s
+
".sql"
);
}
deleteDb
(
"script"
);
deleteDb
(
"script"
);
System
.
out
.
flush
();
System
.
out
.
flush
();
}
}
...
...
h2/src/test/org/h2/test/scripts/dml/mergeUsing.sql
0 → 100755
浏览文件 @
c877fe32
-- Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
-- and the EPL 1.0 (http://h2database.com/html/license.html).
-- Initial Developer: H2 Group
--
CREATE
TABLE
PARENT
(
ID
INT
,
NAME
VARCHAR
,
PRIMARY
KEY
(
ID
)
);
>
ok
MERGE
INTO
PARENT
AS
P
USING
(
SELECT
X
AS
ID
,
'Coco'
||
X
AS
NAME
FROM
SYSTEM_RANGE
(
1
,
2
)
)
AS
S
ON
(
P
.
ID
=
S
.
ID
AND
1
=
1
AND
S
.
ID
=
P
.
ID
)
WHEN
MATCHED
THEN
UPDATE
SET
P
.
NAME
=
S
.
NAME
WHERE
2
=
2
WHEN
NOT
MATCHED
THEN
INSERT
(
ID
,
NAME
)
VALUES
(
S
.
ID
,
S
.
NAME
);
>
update
count
:
2
SELECT
*
FROM
PARENT
;
>
ID
NAME
>
-- -----
>
1
Coco1
>
2
Coco2
EXPLAIN
PLAN
MERGE
INTO
PARENT
AS
P
USING
(
SELECT
X
AS
ID
,
'Coco'
||
X
AS
NAME
FROM
SYSTEM_RANGE
(
1
,
2
)
)
AS
S
ON
(
P
.
ID
=
S
.
ID
AND
1
=
1
AND
S
.
ID
=
P
.
ID
)
WHEN
MATCHED
THEN
UPDATE
SET
P
.
NAME
=
S
.
NAME
WHERE
2
=
2
WHEN
NOT
MATCHED
THEN
INSERT
(
ID
,
NAME
)
VALUES
(
S
.
ID
,
S
.
NAME
);
>
PLAN
>
---------------------------------------------------------------------------------------------------------------------------------
>
MERGE
INTO
PUBLIC
.
PARENT
(
ID
,
NAME
)
KEY
(
ID
)
SELECT
X
AS
ID
,
(
'Coco'
||
X
)
AS
NAME
FROM
SYSTEM_RANGE
(
1
,
2
)
/* PUBLIC.RANGE_INDEX */
\ No newline at end of file
h2/src/test/org/h2/test/scripts/dml/with.sql
0 → 100755
浏览文件 @
c877fe32
-- Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
-- and the EPL 1.0 (http://h2database.com/html/license.html).
-- Initial Developer: H2 Group
--
explain
with
recursive
r
(
n
)
as
(
(
select
1
)
union
all
(
select
n
+
1
from
r
where
n
<
3
)
)
select
n
from
r
;
>
PLAN
>
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
WITH
RECURSIVE
R
(
N
)
AS
(
(
SELECT
1
FROM
SYSTEM_RANGE
(
1
,
1
)
/* PUBLIC.RANGE_INDEX */
)
UNION
ALL
(
SELECT
(
N
+
1
)
FROM
PUBLIC
.
R
/* PUBLIC.R.tableScan */
WHERE
N
<
3
)
)
SELECT
N
FROM
R
R
/* null */
>
rows
:
1
select
sum
(
n
)
from
(
with
recursive
r
(
n
)
as
(
(
select
1
)
union
all
(
select
n
+
1
from
r
where
n
<
3
)
)
select
n
from
r
);
>
SUM
(
N
)
>
------
>
6
>
rows
:
1
select
sum
(
n
)
from
(
select
0
)
join
(
with
recursive
r
(
n
)
as
(
(
select
1
)
union
all
(
select
n
+
1
from
r
where
n
<
3
)
)
select
n
from
r
)
on
1
=
1
;
>
SUM
(
N
)
>
------
>
6
>
rows
:
1
select
0
from
(
select
0
where
0
in
(
with
recursive
r
(
n
)
as
(
(
select
1
)
union
all
(
select
n
+
1
from
r
where
n
<
3
)
)
select
n
from
r
)
);
>
0
>
-
>
rows
:
0
with
r0
(
n
,
k
)
as
(
select
-
1
,
0
),
r1
(
n
,
k
)
as
((
select
1
,
0
)
union
all
(
select
n
+
1
,
k
+
1
from
r1
where
n
<=
3
)),
r2
(
n
,
k
)
as
((
select
10
,
0
)
union
all
(
select
n
+
1
,
k
+
1
from
r2
where
n
<=
13
))
select
r1
.
k
,
r0
.
n
as
N0
,
r1
.
n
AS
N1
,
r2
.
n
AS
n2
from
r0
inner
join
r1
ON
r1
.
k
=
r0
.
k
inner
join
r2
ON
r1
.
k
=
r2
.
k
;
>
K
N0
N1
N2
>
-
-- -- --
>
0
-
1
1
10
>
rows
:
1
\ No newline at end of file
h2/src/test/org/h2/test/scripts/testScript.sql
浏览文件 @
c877fe32
...
@@ -9369,49 +9369,6 @@ select 0 from ((
...
@@ -9369,49 +9369,6 @@ select 0 from ((
}
;
}
;
>
update
count
:
0
>
update
count
:
0
explain
with
recursive
r
(
n
)
as
(
(
select
1
)
union
all
(
select
n
+
1
from
r
where
n
<
3
)
)
select
n
from
r
;
>
PLAN
>
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
WITH
RECURSIVE
R
(
N
)
AS
(
(
SELECT
1
FROM
SYSTEM_RANGE
(
1
,
1
)
/* PUBLIC.RANGE_INDEX */
)
UNION
ALL
(
SELECT
(
N
+
1
)
FROM
PUBLIC
.
R
/* PUBLIC.R.tableScan */
WHERE
N
<
3
)
)
SELECT
N
FROM
R
R
/* null */
>
rows
:
1
select
sum
(
n
)
from
(
with
recursive
r
(
n
)
as
(
(
select
1
)
union
all
(
select
n
+
1
from
r
where
n
<
3
)
)
select
n
from
r
);
>
SUM
(
N
)
>
------
>
6
>
rows
:
1
select
sum
(
n
)
from
(
select
0
)
join
(
with
recursive
r
(
n
)
as
(
(
select
1
)
union
all
(
select
n
+
1
from
r
where
n
<
3
)
)
select
n
from
r
)
on
1
=
1
;
>
SUM
(
N
)
>
------
>
6
>
rows
:
1
select
0
from
(
select
0
where
0
in
(
with
recursive
r
(
n
)
as
(
(
select
1
)
union
all
(
select
n
+
1
from
r
where
n
<
3
)
)
select
n
from
r
)
);
>
0
>
-
>
rows
:
0
create
table
x
(
id
int
not
null
);
create
table
x
(
id
int
not
null
);
>
ok
>
ok
...
...
h2/src/test/org/h2/test/unit/TestMathUtils.java
浏览文件 @
c877fe32
...
@@ -51,11 +51,11 @@ public class TestMathUtils extends TestBase {
...
@@ -51,11 +51,11 @@ public class TestMathUtils extends TestBase {
private
void
testNextPowerOf2Int
()
{
private
void
testNextPowerOf2Int
()
{
// the largest power of two that fits into an integer
// the largest power of two that fits into an integer
final
int
LARGEST_POW
2
=
0x40000000
;
final
int
largestPower
2
=
0x40000000
;
int
[]
testValues
=
{
0
,
1
,
2
,
3
,
4
,
12
,
17
,
500
,
1023
,
int
[]
testValues
=
{
0
,
1
,
2
,
3
,
4
,
12
,
17
,
500
,
1023
,
LARGEST_POW2
-
500
,
LARGEST_POW
2
};
largestPower2
-
500
,
largestPower
2
};
int
[]
resultValues
=
{
1
,
1
,
2
,
4
,
4
,
16
,
32
,
512
,
1024
,
int
[]
resultValues
=
{
1
,
1
,
2
,
4
,
4
,
16
,
32
,
512
,
1024
,
LARGEST_POW2
,
LARGEST_POW
2
};
largestPower2
,
largestPower
2
};
for
(
int
i
=
0
;
i
<
testValues
.
length
;
i
++)
{
for
(
int
i
=
0
;
i
<
testValues
.
length
;
i
++)
{
assertEquals
(
resultValues
[
i
],
MathUtils
.
nextPowerOf2
(
testValues
[
i
]));
assertEquals
(
resultValues
[
i
],
MathUtils
.
nextPowerOf2
(
testValues
[
i
]));
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论