Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
d4fb4c1c
提交
d4fb4c1c
authored
10月 28, 2017
作者:
Owner
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Fixed recursive and non-recursive persistent views with CTE's
上级
15f6d85b
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
8 个修改的文件
包含
291 行增加
和
162 行删除
+291
-162
Parser.java
h2/src/main/org/h2/command/Parser.java
+77
-32
CreateTable.java
h2/src/main/org/h2/command/ddl/CreateTable.java
+110
-100
Query.java
h2/src/main/org/h2/command/dml/Query.java
+0
-1
Database.java
h2/src/main/org/h2/engine/Database.java
+1
-0
Schema.java
h2/src/main/org/h2/schema/Schema.java
+34
-16
Table.java
h2/src/main/org/h2/table/Table.java
+10
-6
TableView.java
h2/src/main/org/h2/table/TableView.java
+21
-7
TestGeneralCommonTableQueries.java
...rc/test/org/h2/test/db/TestGeneralCommonTableQueries.java
+38
-0
没有找到文件。
h2/src/main/org/h2/command/Parser.java
浏览文件 @
d4fb4c1c
差异被折叠。
点击展开。
h2/src/main/org/h2/command/ddl/CreateTable.java
浏览文件 @
d4fb4c1c
...
...
@@ -100,6 +100,7 @@ public class CreateTable extends SchemaCommand {
@Override
public
int
update
()
{
boolean
metaLockAquired
=
false
;
if
(!
transactional
)
{
session
.
commit
(
true
);
}
...
...
@@ -108,122 +109,131 @@ public class CreateTable extends SchemaCommand {
data
.
persistIndexes
=
false
;
}
boolean
isSessionTemporary
=
data
.
temporary
&&
!
data
.
globalTemporary
;
if
(!
isSessionTemporary
)
{
db
.
lockMeta
(
session
);
}
if
(
getSchema
().
resolveTableOrView
(
session
,
data
.
tableName
)
!=
null
)
{
if
(
ifNotExists
)
{
return
0
;
}
throw
DbException
.
get
(
ErrorCode
.
TABLE_OR_VIEW_ALREADY_EXISTS_1
,
data
.
tableName
);
}
if
(
asQuery
!=
null
)
{
asQuery
.
prepare
();
if
(
data
.
columns
.
size
()
==
0
)
{
generateColumnsFromQuery
();
}
else
if
(
data
.
columns
.
size
()
!=
asQuery
.
getColumnCount
())
{
throw
DbException
.
get
(
ErrorCode
.
COLUMN_COUNT_DOES_NOT_MATCH
);
try
{
if
(!
isSessionTemporary
)
{
db
.
lockMeta
(
session
);
metaLockAquired
=
true
;
}
}
if
(
pkColumns
!=
null
)
{
for
(
Column
c
:
data
.
columns
)
{
for
(
IndexColumn
idxCol
:
pkColumns
)
{
if
(
c
.
getName
().
equals
(
idxCol
.
columnName
))
{
c
.
setNullable
(
false
);
}
if
(
getSchema
().
resolveTableOrView
(
session
,
data
.
tableName
)
!=
null
)
{
if
(
ifNotExists
)
{
return
0
;
}
throw
DbException
.
get
(
ErrorCode
.
TABLE_OR_VIEW_ALREADY_EXISTS_1
,
data
.
tableName
);
}
}
data
.
id
=
getObjectId
();
data
.
create
=
create
;
data
.
session
=
session
;
Table
table
=
getSchema
().
createTable
(
data
);
ArrayList
<
Sequence
>
sequences
=
New
.
arrayList
();
for
(
Column
c
:
data
.
columns
)
{
if
(
c
.
isAutoIncrement
())
{
int
objId
=
getObjectId
();
c
.
convertAutoIncrementToSequence
(
session
,
getSchema
(),
objId
,
data
.
temporary
);
if
(!
Constants
.
CLUSTERING_DISABLED
.
equals
(
session
.
getDatabase
().
getCluster
()))
{
throw
DbException
.
getUnsupportedException
(
"CLUSTERING && auto-increment columns"
);
if
(
asQuery
!=
null
)
{
asQuery
.
prepare
();
if
(
data
.
columns
.
size
()
==
0
)
{
generateColumnsFromQuery
();
}
else
if
(
data
.
columns
.
size
()
!=
asQuery
.
getColumnCount
())
{
throw
DbException
.
get
(
ErrorCode
.
COLUMN_COUNT_DOES_NOT_MATCH
);
}
}
Sequence
seq
=
c
.
getSequence
();
if
(
seq
!=
null
)
{
sequences
.
add
(
seq
);
}
}
table
.
setComment
(
comment
);
if
(
isSessionTemporary
)
{
if
(
onCommitDrop
)
{
table
.
setOnCommitDrop
(
true
);
}
if
(
onCommitTruncate
)
{
table
.
setOnCommitTruncate
(
true
);
if
(
pkColumns
!=
null
)
{
for
(
Column
c
:
data
.
columns
)
{
for
(
IndexColumn
idxCol
:
pkColumns
)
{
if
(
c
.
getName
().
equals
(
idxCol
.
columnName
))
{
c
.
setNullable
(
false
);
}
}
}
}
session
.
addLocalTempTable
(
table
);
}
else
{
db
.
lockMeta
(
session
);
db
.
addSchemaObject
(
session
,
table
);
}
try
{
data
.
id
=
getObjectId
();
data
.
create
=
create
;
data
.
session
=
session
;
Table
table
=
getSchema
().
createTable
(
data
);
ArrayList
<
Sequence
>
sequences
=
New
.
arrayList
();
for
(
Column
c
:
data
.
columns
)
{
c
.
prepareExpression
(
session
);
}
for
(
Sequence
sequence
:
sequences
)
{
table
.
addSequence
(
sequence
);
}
for
(
DefineCommand
command
:
constraintCommands
)
{
command
.
setTransactional
(
transactional
);
command
.
update
();
if
(
c
.
isAutoIncrement
())
{
int
objId
=
getObjectId
();
c
.
convertAutoIncrementToSequence
(
session
,
getSchema
(),
objId
,
data
.
temporary
);
if
(!
Constants
.
CLUSTERING_DISABLED
.
equals
(
session
.
getDatabase
().
getCluster
()))
{
throw
DbException
.
getUnsupportedException
(
"CLUSTERING && auto-increment columns"
);
}
}
Sequence
seq
=
c
.
getSequence
();
if
(
seq
!=
null
)
{
sequences
.
add
(
seq
);
}
}
if
(
asQuery
!=
null
)
{
boolean
old
=
session
.
isUndoLogEnabled
();
try
{
session
.
setUndoLogEnabled
(
false
);
session
.
startStatementWithinTransaction
();
Insert
insert
=
null
;
insert
=
new
Insert
(
session
);
insert
.
setSortedInsertMode
(
sortedInsertMode
);
insert
.
setQuery
(
asQuery
);
insert
.
setTable
(
table
);
insert
.
setInsertFromSelect
(
true
);
insert
.
prepare
();
insert
.
update
();
}
finally
{
session
.
setUndoLogEnabled
(
old
);
table
.
setComment
(
comment
);
if
(
isSessionTemporary
)
{
if
(
onCommitDrop
)
{
table
.
setOnCommitDrop
(
true
);
}
if
(
onCommitTruncate
)
{
table
.
setOnCommitTruncate
(
true
);
}
session
.
addLocalTempTable
(
table
);
}
else
{
db
.
lockMeta
(
session
);
db
.
addSchemaObject
(
session
,
table
);
}
HashSet
<
DbObject
>
set
=
New
.
hashSet
();
set
.
clear
();
table
.
addDependencies
(
set
);
for
(
DbObject
obj
:
set
)
{
if
(
obj
==
table
)
{
continue
;
try
{
for
(
Column
c
:
data
.
columns
)
{
c
.
prepareExpression
(
session
);
}
if
(
obj
.
getType
()
==
DbObject
.
TABLE_OR_VIEW
)
{
if
(
obj
instanceof
Table
)
{
Table
t
=
(
Table
)
obj
;
if
(
t
.
getId
()
>
table
.
getId
())
{
throw
DbException
.
get
(
ErrorCode
.
FEATURE_NOT_SUPPORTED_1
,
"Table depends on another table "
+
"with a higher ID: "
+
t
+
", this is currently not supported, "
+
"as it would prevent the database from "
+
"being re-opened"
);
for
(
Sequence
sequence
:
sequences
)
{
table
.
addSequence
(
sequence
);
}
for
(
DefineCommand
command
:
constraintCommands
)
{
command
.
setTransactional
(
transactional
);
command
.
update
();
}
if
(
asQuery
!=
null
)
{
boolean
old
=
session
.
isUndoLogEnabled
();
try
{
session
.
setUndoLogEnabled
(
false
);
session
.
startStatementWithinTransaction
();
Insert
insert
=
null
;
insert
=
new
Insert
(
session
);
insert
.
setSortedInsertMode
(
sortedInsertMode
);
insert
.
setQuery
(
asQuery
);
insert
.
setTable
(
table
);
insert
.
setInsertFromSelect
(
true
);
insert
.
prepare
();
insert
.
update
();
}
finally
{
session
.
setUndoLogEnabled
(
old
);
}
}
HashSet
<
DbObject
>
set
=
New
.
hashSet
();
set
.
clear
();
table
.
addDependencies
(
set
);
for
(
DbObject
obj
:
set
)
{
if
(
obj
==
table
)
{
continue
;
}
if
(
obj
.
getType
()
==
DbObject
.
TABLE_OR_VIEW
)
{
if
(
obj
instanceof
Table
)
{
Table
t
=
(
Table
)
obj
;
if
(
t
.
getId
()
>
table
.
getId
())
{
throw
DbException
.
get
(
ErrorCode
.
FEATURE_NOT_SUPPORTED_1
,
"Table depends on another table "
+
"with a higher ID: "
+
t
+
", this is currently not supported, "
+
"as it would prevent the database from "
+
"being re-opened"
);
}
}
}
}
}
catch
(
DbException
e
)
{
db
.
checkPowerOff
();
db
.
removeSchemaObject
(
session
,
table
);
if
(!
transactional
)
{
session
.
commit
(
true
);
}
throw
e
;
}
}
catch
(
DbException
e
)
{
db
.
checkPowerOff
();
db
.
removeSchemaObject
(
session
,
table
);
if
(!
transactional
)
{
session
.
commit
(
true
);
}
finally
{
if
(!
isSessionTemporary
&&
metaLockAquired
)
{
db
.
unlockMeta
(
session
);
}
throw
e
;
}
return
0
;
}
...
...
h2/src/main/org/h2/command/dml/Query.java
浏览文件 @
d4fb4c1c
...
...
@@ -7,7 +7,6 @@ package org.h2.command.dml;
import
java.util.ArrayList
;
import
java.util.HashSet
;
import
org.h2.api.ErrorCode
;
import
org.h2.command.Prepared
;
import
org.h2.engine.Database
;
...
...
h2/src/main/org/h2/engine/Database.java
浏览文件 @
d4fb4c1c
...
...
@@ -1843,6 +1843,7 @@ public class Database implements DataHandler {
int
type
=
obj
.
getType
();
if
(
type
==
DbObject
.
TABLE_OR_VIEW
)
{
Table
table
=
(
Table
)
obj
;
table
.
setBeingDropped
(
true
);
if
(
table
.
isTemporary
()
&&
!
table
.
isGlobalTemporary
())
{
session
.
removeLocalTempTable
(
table
);
return
;
...
...
h2/src/main/org/h2/schema/Schema.java
浏览文件 @
d4fb4c1c
...
...
@@ -639,26 +639,44 @@ public class Schema extends DbObjectBase {
* @return the created {@link Table} object
*/
public
Table
createTable
(
CreateTableData
data
)
{
synchronized
(
database
)
{
if
(!
data
.
temporary
||
data
.
globalTemporary
)
{
database
.
lockMeta
(
data
.
session
);
}
data
.
schema
=
this
;
if
(
data
.
tableEngine
==
null
)
{
DbSettings
s
=
database
.
getSettings
();
if
(
s
.
defaultTableEngine
!=
null
)
{
data
.
tableEngine
=
s
.
defaultTableEngine
;
}
else
if
(
s
.
mvStore
)
{
data
.
tableEngine
=
MVTableEngine
.
class
.
getName
();
Database
acquiredMetaLockDatabase
=
null
;
try
{
synchronized
(
database
)
{
if
(!
data
.
temporary
||
data
.
globalTemporary
)
{
database
.
lockMeta
(
data
.
session
);
// remember to unlock the meta lock before we leave this method
acquiredMetaLockDatabase
=
database
;
}
data
.
schema
=
this
;
if
(
data
.
tableEngine
==
null
)
{
DbSettings
s
=
database
.
getSettings
();
if
(
s
.
defaultTableEngine
!=
null
)
{
data
.
tableEngine
=
s
.
defaultTableEngine
;
}
else
if
(
s
.
mvStore
)
{
data
.
tableEngine
=
MVTableEngine
.
class
.
getName
();
}
}
if
(
data
.
tableEngine
!=
null
)
{
if
(
data
.
tableEngineParams
==
null
)
{
data
.
tableEngineParams
=
this
.
tableEngineParams
;
}
// the createTable method unlocks the meta - so turn off flag now
acquiredMetaLockDatabase
=
null
;
return
database
.
getTableEngine
(
data
.
tableEngine
).
createTable
(
data
);
}
// the RegularTable constructor unlocks the meta - so turn off flag now
acquiredMetaLockDatabase
=
null
;
return
new
RegularTable
(
data
);
}
if
(
data
.
tableEngine
!=
null
)
{
if
(
data
.
tableEngineParams
==
null
)
{
data
.
tableEngineParams
=
this
.
tableEngineParams
;
}
finally
{
if
(
acquiredMetaLockDatabase
!=
null
&&
data
.
session
!=
null
){
if
(
acquiredMetaLockDatabase
.
isSysTableLockedBy
(
data
.
session
)){
acquiredMetaLockDatabase
.
unlockMeta
(
data
.
session
);
}
return
database
.
getTableEngine
(
data
.
tableEngine
).
createTable
(
data
);
}
return
new
RegularTable
(
data
);
}
}
...
...
h2/src/main/org/h2/table/Table.java
浏览文件 @
d4fb4c1c
...
...
@@ -77,12 +77,13 @@ public abstract class Table extends SchemaObjectBase {
private
ArrayList
<
TriggerObject
>
triggers
;
private
ArrayList
<
Constraint
>
constraints
;
private
ArrayList
<
Sequence
>
sequences
;
private
ArrayList
<
TableView
>
views
;
private
ArrayList
<
TableView
>
views
;
// remember which views are using this object
private
ArrayList
<
TableSynonym
>
synonyms
;
private
boolean
checkForeignKeyConstraints
=
true
;
private
boolean
onCommitDrop
,
onCommitTruncate
;
private
volatile
Row
nullRow
;
private
boolean
tableExpression
;
private
boolean
isBeingDropped
;
public
Table
(
Schema
schema
,
int
id
,
String
name
,
boolean
persistIndexes
,
...
...
@@ -158,7 +159,6 @@ public abstract class Table extends SchemaObjectBase {
* @param key the primary key
* @return the row
*/
@SuppressWarnings
(
"unused"
)
public
Row
getRow
(
Session
session
,
long
key
)
{
return
null
;
}
...
...
@@ -193,7 +193,6 @@ public abstract class Table extends SchemaObjectBase {
* @param operation the operation
* @param row the row
*/
@SuppressWarnings
(
"unused"
)
public
void
commit
(
short
operation
,
Row
row
)
{
// nothing to do
}
...
...
@@ -231,7 +230,6 @@ public abstract class Table extends SchemaObjectBase {
* @param allColumnsSet all columns
* @return the scan index
*/
@SuppressWarnings
(
"unused"
)
public
Index
getScanIndex
(
Session
session
,
int
[]
masks
,
TableFilter
[]
filters
,
int
filter
,
SortOrder
sortOrder
,
HashSet
<
Column
>
allColumnsSet
)
{
...
...
@@ -464,7 +462,6 @@ public abstract class Table extends SchemaObjectBase {
* @param session the session
* @return true if it is
*/
@SuppressWarnings
(
"unused"
)
public
boolean
isLockedExclusivelyBy
(
Session
session
)
{
return
false
;
}
...
...
@@ -1168,7 +1165,6 @@ public abstract class Table extends SchemaObjectBase {
* @return an object array with the sessions involved in the deadlock, or
* null
*/
@SuppressWarnings
(
"unused"
)
public
ArrayList
<
Session
>
checkDeadlock
(
Session
session
,
Session
clash
,
Set
<
Session
>
visited
)
{
return
null
;
...
...
@@ -1252,5 +1248,13 @@ public abstract class Table extends SchemaObjectBase {
public
boolean
isTableExpression
()
{
return
tableExpression
;
}
public
boolean
isBeingDropped
(){
return
isBeingDropped
;
}
public
void
setBeingDropped
(
boolean
isBeingDropped
){
this
.
isBeingDropped
=
isBeingDropped
;
}
}
h2/src/main/org/h2/table/TableView.java
浏览文件 @
d4fb4c1c
...
...
@@ -58,6 +58,7 @@ public class TableView extends Table {
private
Query
topQuery
;
private
ResultInterface
recursiveResult
;
private
boolean
isRecursiveQueryDetected
;
private
Session
session
;
public
TableView
(
Schema
schema
,
int
id
,
String
name
,
String
querySQL
,
ArrayList
<
Parameter
>
params
,
Column
[]
columnTemplates
,
Session
session
,
...
...
@@ -98,6 +99,7 @@ public class TableView extends Table {
this
.
columnTemplates
=
columnTemplates
;
this
.
recursive
=
recursive
;
this
.
isRecursiveQueryDetected
=
false
;
this
.
session
=
session
;
index
=
new
ViewIndex
(
this
,
querySQL
,
params
,
recursive
);
initColumnsAndTables
(
session
,
literalsChecked
);
}
...
...
@@ -157,13 +159,13 @@ public class TableView extends Table {
Column
[]
cols
;
removeViewFromTables
();
try
{
Query
q
uery
=
compileViewQuery
(
session
,
querySQL
,
literalsChecked
);
this
.
querySQL
=
q
uery
.
getPlanSQL
();
tables
=
New
.
arrayList
(
q
uery
.
getTables
());
ArrayList
<
Expression
>
expressions
=
q
uery
.
getExpressions
();
Query
compiledQ
uery
=
compileViewQuery
(
session
,
querySQL
,
literalsChecked
);
this
.
querySQL
=
compiledQ
uery
.
getPlanSQL
();
tables
=
New
.
arrayList
(
compiledQ
uery
.
getTables
());
ArrayList
<
Expression
>
expressions
=
compiledQ
uery
.
getExpressions
();
ArrayList
<
Column
>
list
=
New
.
arrayList
();
ColumnNamer
columnNamer
=
new
ColumnNamer
(
session
);
for
(
int
i
=
0
,
count
=
q
uery
.
getColumnCount
();
i
<
count
;
i
++)
{
for
(
int
i
=
0
,
count
=
compiledQ
uery
.
getColumnCount
();
i
<
count
;
i
++)
{
Expression
expr
=
expressions
.
get
(
i
);
String
name
=
null
;
int
type
=
Value
.
UNKNOWN
;
...
...
@@ -205,7 +207,7 @@ public class TableView extends Table {
cols
=
new
Column
[
list
.
size
()];
list
.
toArray
(
cols
);
createException
=
null
;
viewQuery
=
q
uery
;
viewQuery
=
compiledQ
uery
;
}
catch
(
DbException
e
)
{
e
.
addSQL
(
getCreateSQL
());
createException
=
e
;
...
...
@@ -693,5 +695,17 @@ public class TableView extends Table {
}
return
true
;
}
@Override
public
void
removeView
(
TableView
view
){
super
.
removeView
(
view
);
// if this is a table expression and the last view to use it is
// being dropped - then remove itself from the schema
if
(
isTableExpression
()
&&
getViews
()!=
null
&&
view
.
isBeingDropped
()){
// check if any database objects are left using this view
if
(
getViews
().
size
()==
0
){
session
.
getDatabase
().
removeSchemaObject
(
session
,
this
);
}
}
}
}
h2/src/test/org/h2/test/db/TestGeneralCommonTableQueries.java
浏览文件 @
d4fb4c1c
...
...
@@ -44,6 +44,7 @@ public class TestGeneralCommonTableQueries extends TestBase {
testNestedSQL
();
testRecursiveTable
();
testRecursiveTableInCreateView
();
testNonRecursiveTableInCreateView
();
}
private
void
testSimpleSelect
()
throws
Exception
{
...
...
@@ -608,4 +609,41 @@ public class TestGeneralCommonTableQueries extends TestBase {
testRepeatedQueryWithSetup
(
maxRetries
,
expectedRowData
,
expectedColumnNames
,
expectedNumbeOfRows
,
SETUP_SQL
,
WITH_QUERY
);
}
private
void
testNonRecursiveTableInCreateView
()
throws
Exception
{
String
SETUP_SQL
=
""
+
"DROP VIEW IF EXISTS v_my_nr_tree; \n"
+
"DROP TABLE IF EXISTS my_table; \n"
+
"CREATE TABLE my_table ( \n"
+
" id INTEGER, \n"
+
" parent_fk INTEGER \n"
+
"); \n"
+
" \n"
+
"INSERT INTO my_table ( id, parent_fk) VALUES ( 1, NULL ); \n"
+
"INSERT INTO my_table ( id, parent_fk) VALUES ( 11, 1 ); \n"
+
"INSERT INTO my_table ( id, parent_fk) VALUES ( 111, 11 ); \n"
+
"INSERT INTO my_table ( id, parent_fk) VALUES ( 12, 1 ); \n"
+
"INSERT INTO my_table ( id, parent_fk) VALUES ( 121, 12 ); \n"
+
" \n"
+
"CREATE OR REPLACE VIEW v_my_nr_tree AS \n"
+
"WITH tree_cte_nr (sub_tree_root_id, tree_level, parent_fk, child_fk) AS ( \n"
+
" SELECT mt.ID AS sub_tree_root_id, CAST(0 AS INT) AS tree_level, mt.parent_fk, mt.id \n"
+
" FROM my_table mt \n"
+
") \n"
+
"SELECT sub_tree_root_id, tree_level, parent_fk, child_fk FROM tree_cte_nr; \n"
;
String
WITH_QUERY
=
"SELECT * FROM v_my_nr_tree"
;
int
maxRetries
=
4
;
String
[]
expectedRowData
=
new
String
[]{
"|1|0|null|1"
,
"|11|0|1|11"
,
"|111|0|11|111"
,
"|12|0|1|12"
,
"|121|0|12|121"
,
};
String
[]
expectedColumnNames
=
new
String
[]{
"SUB_TREE_ROOT_ID"
,
"TREE_LEVEL"
,
"PARENT_FK"
,
"CHILD_FK"
};
int
expectedNumbeOfRows
=
5
;
testRepeatedQueryWithSetup
(
maxRetries
,
expectedRowData
,
expectedColumnNames
,
expectedNumbeOfRows
,
SETUP_SQL
,
WITH_QUERY
);
}
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论