Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
f898ba35
提交
f898ba35
authored
12 年前
作者:
Thomas Mueller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
MVStore: table engine
上级
18808fa8
显示空白字符变更
内嵌
并排
正在显示
15 个修改的文件
包含
526 行增加
和
103 行删除
+526
-103
BaseIndex.java
h2/src/main/org/h2/index/BaseIndex.java
+1
-1
MVMap.java
h2/src/main/org/h2/mvstore/MVMap.java
+14
-7
MVStore.java
h2/src/main/org/h2/mvstore/MVStore.java
+53
-19
MVDelegateIndex.java
h2/src/main/org/h2/mvstore/db/MVDelegateIndex.java
+2
-13
MVPrimaryIndex.java
h2/src/main/org/h2/mvstore/db/MVPrimaryIndex.java
+32
-8
MVSecondaryIndex.java
h2/src/main/org/h2/mvstore/db/MVSecondaryIndex.java
+48
-17
MVTable.java
h2/src/main/org/h2/mvstore/db/MVTable.java
+240
-13
help.csv
h2/src/main/org/h2/res/help.csv
+4
-0
TableBase.java
h2/src/main/org/h2/table/TableBase.java
+1
-1
TestAll.java
h2/src/test/org/h2/test/TestAll.java
+23
-21
TestBase.java
h2/src/test/org/h2/test/TestBase.java
+3
-0
test.properties
h2/src/test/org/h2/test/bench/test.properties
+1
-0
TestMVStore.java
h2/src/test/org/h2/test/store/TestMVStore.java
+3
-3
TestMVTableEngine.java
h2/src/test/org/h2/test/store/TestMVTableEngine.java
+99
-0
test-1.3.txt
h2/src/test/org/h2/test/test-1.3.txt
+2
-0
没有找到文件。
h2/src/main/org/h2/index/BaseIndex.java
浏览文件 @
f898ba35
...
...
@@ -194,7 +194,7 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index {
* @return true if one of the columns is null and multiple nulls in unique
* indexes are allowed
*/
boolean
containsNullAndAllowMultipleNull
(
SearchRow
newRow
)
{
protected
boolean
containsNullAndAllowMultipleNull
(
SearchRow
newRow
)
{
Mode
mode
=
database
.
getMode
();
if
(
mode
.
uniqueIndexSingleNull
)
{
return
false
;
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/mvstore/MVMap.java
浏览文件 @
f898ba35
...
...
@@ -39,7 +39,6 @@ public class MVMap<K, V> extends AbstractMap<K, V>
protected
volatile
Page
root
;
private
int
id
;
private
String
name
;
private
long
createVersion
;
private
final
DataType
keyType
;
private
final
DataType
valueType
;
...
...
@@ -63,7 +62,6 @@ public class MVMap<K, V> extends AbstractMap<K, V>
public
void
open
(
MVStore
store
,
HashMap
<
String
,
String
>
config
)
{
this
.
store
=
store
;
this
.
id
=
Integer
.
parseInt
(
config
.
get
(
"id"
));
this
.
name
=
config
.
get
(
"name"
);
this
.
createVersion
=
Long
.
parseLong
(
config
.
get
(
"createVersion"
));
}
...
...
@@ -480,7 +478,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
if
(
this
!=
store
.
getMetaMap
())
{
checkWrite
();
root
.
removeAllRecursive
();
store
.
removeMap
(
name
);
store
.
removeMap
(
id
);
close
();
}
}
...
...
@@ -781,7 +779,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
* @return the name
*/
public
String
getName
()
{
return
name
;
return
store
.
getMapName
(
id
)
;
}
public
MVStore
getStore
()
{
...
...
@@ -891,6 +889,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
}
public
long
getSize
()
{
checkOpen
();
return
root
.
getTotalCount
();
}
...
...
@@ -933,7 +932,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
// not found
if
(
i
==
-
1
)
{
// smaller than all in-memory versions
return
store
.
openMapVersion
(
version
,
name
,
this
);
return
store
.
openMapVersion
(
version
,
id
,
this
);
}
i
=
-
i
-
2
;
}
...
...
@@ -954,7 +953,6 @@ public class MVMap<K, V> extends AbstractMap<K, V>
m
.
readOnly
=
true
;
HashMap
<
String
,
String
>
config
=
New
.
hashMap
();
config
.
put
(
"id"
,
String
.
valueOf
(
id
));
config
.
put
(
"name"
,
name
);
config
.
put
(
"createVersion"
,
String
.
valueOf
(
createVersion
));
m
.
open
(
store
,
config
);
m
.
root
=
root
;
...
...
@@ -1010,7 +1008,6 @@ public class MVMap<K, V> extends AbstractMap<K, V>
public
String
asString
()
{
StringBuilder
buff
=
new
StringBuilder
();
DataUtils
.
appendMap
(
buff
,
"id"
,
id
);
DataUtils
.
appendMap
(
buff
,
"name"
,
name
);
DataUtils
.
appendMap
(
buff
,
"type"
,
getType
());
DataUtils
.
appendMap
(
buff
,
"createVersion"
,
createVersion
);
if
(
keyType
!=
null
)
{
...
...
@@ -1022,6 +1019,16 @@ public class MVMap<K, V> extends AbstractMap<K, V>
return
buff
.
toString
();
}
/**
* Rename the map.
*
* @param newMapName the name name
*/
public
void
rename
(
String
newMapName
)
{
checkWrite
();
store
.
renameMap
(
this
,
newMapName
);
}
public
String
toString
()
{
return
asString
();
}
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/mvstore/MVStore.java
浏览文件 @
f898ba35
...
...
@@ -43,8 +43,13 @@ header:
H:3,...
TODO:
- automated 'kill process' and 'power failure' test
- after rollback: is a regular save ok?
- cache: change API to better match guava / Android
- rename a map
- MVStore: improved API thanks to Simo Tripodi
- implement table engine for H2
- automated 'kill process' and 'power failure' test
- maybe split database into multiple files, to speed up compact
- auto-compact from time to time and on close
- test and possibly improve compact operation (for large dbs)
...
...
@@ -150,6 +155,7 @@ public class MVStore {
private
MVMap
<
String
,
String
>
meta
;
private
final
HashMap
<
String
,
MVMap
<?,
?>>
maps
=
New
.
hashMap
();
private
final
HashMap
<
Integer
,
String
>
mapIdName
=
New
.
hashMap
();
/**
* The set of maps with potentially unsaved changes.
...
...
@@ -225,14 +231,14 @@ public class MVStore {
* Open an old, stored version of a map.
*
* @param version the version
* @param
name the map name
* @param
mapId the map id
* @param template the template map
* @return the read-only map
*/
@SuppressWarnings
(
"unchecked"
)
<
T
extends
MVMap
<?,
?>>
T
openMapVersion
(
long
version
,
String
name
,
MVMap
<?,
?>
template
)
{
<
T
extends
MVMap
<?,
?>>
T
openMapVersion
(
long
version
,
int
mapId
,
MVMap
<?,
?>
template
)
{
MVMap
<
String
,
String
>
oldMeta
=
getMetaMap
(
version
);
String
r
=
oldMeta
.
get
(
"root."
+
template
.
getId
()
);
String
r
=
oldMeta
.
get
(
"root."
+
mapId
);
long
rootPos
=
r
==
null
?
0
:
Long
.
parseLong
(
r
);
MVMap
<?,
?>
m
=
template
.
openReadOnly
();
m
.
setRootPos
(
rootPos
,
version
);
...
...
@@ -292,10 +298,12 @@ public class MVStore {
m
=
template
;
String
config
=
meta
.
get
(
"map."
+
name
);
long
root
;
int
id
;
HashMap
<
String
,
String
>
c
;
if
(
config
==
null
)
{
c
=
New
.
hashMap
();
c
.
put
(
"id"
,
Integer
.
toString
(++
lastMapId
));
id
=
++
lastMapId
;
c
.
put
(
"id"
,
Integer
.
toString
(
id
));
c
.
put
(
"name"
,
name
);
c
.
put
(
"createVersion"
,
Long
.
toString
(
currentVersion
));
m
.
open
(
this
,
c
);
...
...
@@ -303,11 +311,13 @@ public class MVStore {
root
=
0
;
}
else
{
c
=
DataUtils
.
parseMap
(
config
);
String
r
=
meta
.
get
(
"root."
+
c
.
get
(
"id"
));
id
=
Integer
.
parseInt
(
c
.
get
(
"id"
));
String
r
=
meta
.
get
(
"root."
+
id
);
root
=
r
==
null
?
0
:
Long
.
parseLong
(
r
);
}
m
.
open
(
this
,
c
);
m
.
setRootPos
(
root
,
-
1
);
mapIdName
.
put
(
id
,
name
);
maps
.
put
(
name
,
m
);
return
(
T
)
m
;
}
...
...
@@ -357,13 +367,15 @@ public class MVStore {
/**
* Remove a map.
*
* @param
name the map name
* @param
id the map id
*/
void
removeMap
(
String
name
)
{
MVMap
<?,
?>
map
=
maps
.
remove
(
name
);
void
removeMap
(
int
id
)
{
String
name
=
mapIdName
.
get
(
id
);
meta
.
remove
(
"map."
+
name
);
meta
.
remove
(
"root."
+
map
.
getId
());
mapsChanged
.
remove
(
map
.
getId
());
meta
.
remove
(
"root."
+
id
);
mapsChanged
.
remove
(
id
);
mapIdName
.
remove
(
id
);
maps
.
remove
(
name
);
}
private
DataType
getDataType
(
Class
<?>
clazz
)
{
...
...
@@ -560,6 +572,7 @@ public class MVStore {
chunks
.
clear
();
cache
.
clear
();
maps
.
clear
();
mapIdName
.
clear
();
mapsChanged
.
clear
();
}
catch
(
Exception
e
)
{
throw
DataUtils
.
illegalStateException
(
"Closing failed for file "
+
fileName
,
e
);
...
...
@@ -987,12 +1000,7 @@ public class MVStore {
if
(
mapId
==
0
)
{
return
meta
;
}
for
(
MVMap
<?,
?>
m
:
maps
.
values
())
{
if
(
m
.
getId
()
==
mapId
)
{
return
m
;
}
}
return
null
;
return
maps
.
get
(
mapIdName
.
get
(
mapId
));
}
/**
...
...
@@ -1274,13 +1282,15 @@ public class MVStore {
readMeta
();
}
}
int
todoRollbackMapNames
;
for
(
MVMap
<?,
?>
m
:
maps
.
values
())
{
int
id
=
m
.
getId
();
if
(
m
.
getCreateVersion
()
>=
version
)
{
m
.
close
();
removeMap
(
m
.
getName
()
);
removeMap
(
id
);
}
else
{
if
(
loadFromFile
)
{
String
r
=
meta
.
get
(
"root."
+
m
.
getId
()
);
String
r
=
meta
.
get
(
"root."
+
id
);
long
root
=
r
==
null
?
0
:
Long
.
parseLong
(
r
);
m
.
setRootPos
(
root
,
version
);
}
...
...
@@ -1367,4 +1377,28 @@ public class MVStore {
return
DataUtils
.
appendMap
(
new
StringBuilder
(),
config
).
toString
();
}
void
renameMap
(
MVMap
<?,
?>
map
,
String
newName
)
{
checkOpen
();
if
(
map
==
meta
)
{
throw
DataUtils
.
unsupportedOperationException
(
"Renaming the meta map is not allowed"
);
}
if
(
map
.
getName
().
equals
(
newName
))
{
return
;
}
if
(
meta
.
containsKey
(
"map."
+
newName
))
{
throw
DataUtils
.
illegalArgumentException
(
"A map named "
+
newName
+
" already exists"
);
}
int
id
=
map
.
getId
();
String
oldName
=
mapIdName
.
remove
(
id
);
maps
.
remove
(
oldName
);
String
value
=
meta
.
remove
(
"map."
+
oldName
);
meta
.
put
(
"map."
+
newName
,
value
);
maps
.
put
(
newName
,
map
);
mapIdName
.
put
(
id
,
newName
);
}
String
getMapName
(
int
id
)
{
return
mapIdName
.
get
(
id
);
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/mvstore/db/MVDelegateIndex.java
浏览文件 @
f898ba35
...
...
@@ -43,9 +43,7 @@ public class MVDelegateIndex extends BaseIndex {
}
public
boolean
canGetFirstOrLast
()
{
return
false
;
// TODO
// return true;
return
true
;
}
public
void
close
(
Session
session
)
{
...
...
@@ -61,16 +59,7 @@ public class MVDelegateIndex extends BaseIndex {
}
public
Cursor
findFirstOrLast
(
Session
session
,
boolean
first
)
{
return
null
;
// Cursor cursor;
// if (first) {
// cursor = mainIndex.find(session, Long.MIN_VALUE, Long.MAX_VALUE, false);
// } else {
// long x = mainIndex.getLastKey();
// cursor = mainIndex.find(session, x, x, false);
// }
// cursor.next();
// return cursor;
return
mainIndex
.
findFirstOrLast
(
session
,
first
);
}
public
Cursor
findNext
(
Session
session
,
SearchRow
higherThan
,
SearchRow
last
)
{
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/mvstore/db/MVPrimaryIndex.java
浏览文件 @
f898ba35
...
...
@@ -6,6 +6,8 @@
*/
package
org
.
h2
.
mvstore
.
db
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.Iterator
;
import
org.h2.constant.ErrorCode
;
import
org.h2.engine.Constants
;
...
...
@@ -20,6 +22,7 @@ import org.h2.mvstore.type.ObjectDataType;
import
org.h2.result.Row
;
import
org.h2.result.SearchRow
;
import
org.h2.result.SortOrder
;
import
org.h2.table.Column
;
import
org.h2.table.IndexColumn
;
import
org.h2.value.Value
;
import
org.h2.value.ValueNull
;
...
...
@@ -45,11 +48,16 @@ public class MVPrimaryIndex extends BaseIndex {
ValueArrayDataType
t
=
new
ValueArrayDataType
(
db
.
getCompareMode
(),
db
,
sortTypes
);
map
=
new
MVMap
<
Long
,
Value
[]>(
new
ObjectDataType
(),
t
);
map
=
table
.
getStore
().
openMap
(
getName
(),
map
);
map
=
table
.
getStore
().
openMap
(
getName
()
+
"_"
+
getId
()
,
map
);
Long
k
=
map
.
lastKey
();
nextKey
=
k
==
null
?
0
:
k
+
1
;
}
public
void
renameTable
(
String
newName
)
{
rename
(
newName
+
"_DATA"
);
map
.
rename
(
newName
+
"_DATA_"
+
getId
());
}
public
String
getCreateSQL
()
{
return
null
;
}
...
...
@@ -147,6 +155,12 @@ public class MVPrimaryIndex extends BaseIndex {
return
cost
;
}
public
int
getColumnIndex
(
Column
col
)
{
// can not use this index - use the delegate index instead
return
-
1
;
}
@Override
public
void
remove
(
Session
session
)
{
if
(!
map
.
isClosed
())
{
...
...
@@ -161,19 +175,22 @@ public class MVPrimaryIndex extends BaseIndex {
@Override
public
boolean
canGetFirstOrLast
()
{
return
fals
e
;
return
tru
e
;
}
@Override
public
Cursor
findFirstOrLast
(
Session
session
,
boolean
first
)
{
// return first ? map.firstKey() : map.lastKey();
// TODO get first / last
return
null
;
if
(
map
.
getSize
()
==
0
)
{
return
new
MVStoreCursor
(
session
,
Collections
.<
Long
>
emptyList
().
iterator
(),
0
);
}
long
key
=
first
?
map
.
firstKey
()
:
map
.
lastKey
();
MVStoreCursor
cursor
=
new
MVStoreCursor
(
session
,
Arrays
.
asList
(
key
).
iterator
(),
key
);
cursor
.
next
();
return
cursor
;
}
@Override
public
boolean
needRebuild
()
{
// TODO Auto-generated method stub
return
false
;
}
...
...
@@ -188,7 +205,8 @@ public class MVPrimaryIndex extends BaseIndex {
}
public
long
getDiskSpaceUsed
()
{
return
0
;
// TODO
// TODO estimate disk space usage
return
0
;
}
@Override
...
...
@@ -249,8 +267,10 @@ public class MVPrimaryIndex extends BaseIndex {
@Override
public
Row
get
()
{
if
(
row
==
null
)
{
if
(
current
!=
null
)
{
row
=
getRow
(
session
,
current
);
}
}
return
row
;
}
...
...
@@ -277,4 +297,8 @@ public class MVPrimaryIndex extends BaseIndex {
}
public
boolean
isRowIdIndex
()
{
return
true
;
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/mvstore/db/MVSecondaryIndex.java
浏览文件 @
f898ba35
...
...
@@ -6,6 +6,8 @@
*/
package
org
.
h2
.
mvstore
.
db
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.Iterator
;
import
org.h2.constant.ErrorCode
;
import
org.h2.engine.Database
;
...
...
@@ -21,6 +23,7 @@ import org.h2.result.SearchRow;
import
org.h2.result.SortOrder
;
import
org.h2.table.Column
;
import
org.h2.table.IndexColumn
;
import
org.h2.util.New
;
import
org.h2.value.Value
;
import
org.h2.value.ValueLong
;
...
...
@@ -48,7 +51,7 @@ public class MVSecondaryIndex extends BaseIndex {
ValueArrayDataType
t
=
new
ValueArrayDataType
(
db
.
getCompareMode
(),
db
,
sortTypes
);
map
=
new
MVMap
<
Value
[],
Long
>(
t
,
new
ObjectDataType
());
map
=
table
.
getStore
().
openMap
(
getName
(),
map
);
map
=
table
.
getStore
().
openMap
(
getName
()
+
"_"
+
getId
()
,
map
);
}
@Override
...
...
@@ -56,15 +59,26 @@ public class MVSecondaryIndex extends BaseIndex {
// ok
}
public
void
rename
(
String
newName
)
{
map
.
rename
(
newName
+
"_"
+
getId
());
super
.
rename
(
newName
);
}
@Override
public
void
add
(
Session
session
,
Row
row
)
{
Value
[]
array
=
getKey
(
row
);
if
(
indexType
.
isUnique
())
{
array
[
keyColumns
-
1
]
=
ValueLong
.
get
(
0
);
if
(
map
.
containsKey
(
array
))
{
Value
[]
key
=
map
.
ceilingKey
(
array
);
if
(
key
!=
null
)
{
SearchRow
r2
=
getRow
(
key
);
if
(
compareRows
(
row
,
r2
)
==
0
)
{
if
(!
containsNullAndAllowMultipleNull
(
r2
))
{
throw
getDuplicateKeyException
();
}
}
}
}
array
[
keyColumns
-
1
]
=
ValueLong
.
get
(
row
.
getKey
());
map
.
put
(
array
,
Long
.
valueOf
(
0
));
}
...
...
@@ -103,6 +117,19 @@ public class MVSecondaryIndex extends BaseIndex {
return
array
;
}
SearchRow
getRow
(
Value
[]
array
)
{
SearchRow
searchRow
=
mvTable
.
getTemplateRow
();
searchRow
.
setKey
((
array
[
array
.
length
-
1
]).
getLong
());
Column
[]
cols
=
getColumns
();
for
(
int
i
=
0
;
i
<
array
.
length
-
1
;
i
++)
{
Column
c
=
cols
[
i
];
int
idx
=
c
.
getColumnId
();
Value
v
=
array
[
i
];
searchRow
.
setValue
(
idx
,
v
);
}
return
searchRow
;
}
public
MVTable
getTable
()
{
return
mvTable
;
}
...
...
@@ -126,17 +153,24 @@ public class MVSecondaryIndex extends BaseIndex {
@Override
public
boolean
canGetFirstOrLast
()
{
return
fals
e
;
return
tru
e
;
}
@Override
public
Cursor
findFirstOrLast
(
Session
session
,
boolean
first
)
{
return
null
;
if
(
map
.
getSize
()
==
0
)
{
return
new
MVStoreCursor
(
session
,
Collections
.<
Value
[]>
emptyList
().
iterator
(),
null
);
}
Value
[]
key
=
first
?
map
.
firstKey
()
:
map
.
lastKey
();
ArrayList
<
Value
[]>
list
=
New
.
arrayList
();
list
.
add
(
key
);
MVStoreCursor
cursor
=
new
MVStoreCursor
(
session
,
list
.
iterator
(),
null
);
cursor
.
next
();
return
cursor
;
}
@Override
public
boolean
needRebuild
()
{
// TODO there should be a better way
return
map
.
getSize
()
==
0
;
}
...
...
@@ -151,7 +185,8 @@ public class MVSecondaryIndex extends BaseIndex {
}
public
long
getDiskSpaceUsed
()
{
return
0
;
// TODO
// TODO estimate disk space usage
return
0
;
}
@Override
...
...
@@ -180,7 +215,10 @@ public class MVSecondaryIndex extends BaseIndex {
@Override
public
Row
get
()
{
if
(
row
==
null
)
{
row
=
mvTable
.
getRow
(
session
,
getSearchRow
().
getKey
());
SearchRow
r
=
getSearchRow
();
if
(
r
!=
null
)
{
row
=
mvTable
.
getRow
(
session
,
r
.
getKey
());
}
}
return
row
;
}
...
...
@@ -188,15 +226,8 @@ public class MVSecondaryIndex extends BaseIndex {
@Override
public
SearchRow
getSearchRow
()
{
if
(
searchRow
==
null
)
{
Value
[]
array
=
current
;
Column
[]
cols
=
getColumns
();
searchRow
=
mvTable
.
getTemplateRow
();
searchRow
.
setKey
((
array
[
array
.
length
-
1
]).
getLong
());
for
(
int
i
=
0
;
i
<
array
.
length
-
1
;
i
++)
{
Column
c
=
cols
[
i
];
int
idx
=
c
.
getColumnId
();
Value
v
=
array
[
i
];
searchRow
.
setValue
(
idx
,
v
);
if
(
current
!=
null
)
{
searchRow
=
getRow
(
current
);
}
}
return
searchRow
;
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/mvstore/db/MVTable.java
浏览文件 @
f898ba35
...
...
@@ -9,6 +9,8 @@ package org.h2.mvstore.db;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.Comparator
;
import
java.util.HashSet
;
import
java.util.Set
;
import
org.h2.api.DatabaseEventListener
;
import
org.h2.command.ddl.CreateTableData
;
import
org.h2.constant.ErrorCode
;
...
...
@@ -23,12 +25,14 @@ import org.h2.index.Index;
import
org.h2.index.IndexType
;
import
org.h2.index.MultiVersionIndex
;
import
org.h2.message.DbException
;
import
org.h2.message.Trace
;
import
org.h2.mvstore.MVStore
;
import
org.h2.result.Row
;
import
org.h2.result.SortOrder
;
import
org.h2.schema.SchemaObject
;
import
org.h2.table.Column
;
import
org.h2.table.IndexColumn
;
import
org.h2.table.RegularTable
;
import
org.h2.table.Table
;
import
org.h2.table.TableBase
;
import
org.h2.util.MathUtils
;
...
...
@@ -47,12 +51,23 @@ public class MVTable extends TableBase {
private
ArrayList
<
Index
>
indexes
=
New
.
arrayList
();
private
long
lastModificationId
;
private
long
rowCount
;
private
volatile
Session
lockExclusive
;
private
HashSet
<
Session
>
lockShared
=
New
.
hashSet
();
private
final
Trace
traceLock
;
/**
* True if one thread ever was waiting to lock this table. This is to avoid
* calling notifyAll if no session was ever waiting to lock this table. If
* set, the flag stays. In theory, it could be reset, however not sure when.
*/
private
boolean
waitForLock
;
public
MVTable
(
CreateTableData
data
,
String
storeName
,
MVStore
store
)
{
super
(
data
);
this
.
storeName
=
storeName
;
this
.
store
=
store
;
this
.
hidden
=
data
.
isHidden
;
traceLock
=
database
.
getTrace
(
Trace
.
LOCK
);
}
void
init
(
Session
session
)
{
...
...
@@ -67,7 +82,227 @@ public class MVTable extends TableBase {
@Override
public
void
lock
(
Session
session
,
boolean
exclusive
,
boolean
force
)
{
// TODO locking
int
lockMode
=
database
.
getLockMode
();
if
(
lockMode
==
Constants
.
LOCK_MODE_OFF
)
{
return
;
}
if
(!
force
&&
database
.
isMultiVersion
())
{
// MVCC: update, delete, and insert use a shared lock.
// Select doesn't lock except when using FOR UPDATE and
// the system property h2.selectForUpdateMvcc
// is not enabled
if
(
exclusive
)
{
exclusive
=
false
;
}
else
{
if
(
lockExclusive
==
null
)
{
return
;
}
}
}
if
(
lockExclusive
==
session
)
{
return
;
}
synchronized
(
database
)
{
try
{
doLock
(
session
,
lockMode
,
exclusive
);
}
finally
{
session
.
setWaitForLock
(
null
);
}
}
}
public
void
rename
(
String
newName
)
{
super
.
rename
(
newName
);
primaryIndex
.
renameTable
(
newName
);
}
private
void
doLock
(
Session
session
,
int
lockMode
,
boolean
exclusive
)
{
traceLock
(
session
,
exclusive
,
"requesting for"
);
// don't get the current time unless necessary
long
max
=
0
;
boolean
checkDeadlock
=
false
;
while
(
true
)
{
if
(
lockExclusive
==
session
)
{
return
;
}
if
(
exclusive
)
{
if
(
lockExclusive
==
null
)
{
if
(
lockShared
.
isEmpty
())
{
traceLock
(
session
,
exclusive
,
"added for"
);
session
.
addLock
(
this
);
lockExclusive
=
session
;
return
;
}
else
if
(
lockShared
.
size
()
==
1
&&
lockShared
.
contains
(
session
))
{
traceLock
(
session
,
exclusive
,
"add (upgraded) for "
);
lockExclusive
=
session
;
return
;
}
}
}
else
{
if
(
lockExclusive
==
null
)
{
if
(
lockMode
==
Constants
.
LOCK_MODE_READ_COMMITTED
)
{
if
(!
database
.
isMultiThreaded
()
&&
!
database
.
isMultiVersion
())
{
// READ_COMMITTED: a read lock is acquired,
// but released immediately after the operation
// is complete.
// When allowing only one thread, no lock is
// required.
// Row level locks work like read committed.
return
;
}
}
if
(!
lockShared
.
contains
(
session
))
{
traceLock
(
session
,
exclusive
,
"ok"
);
session
.
addLock
(
this
);
lockShared
.
add
(
session
);
}
return
;
}
}
session
.
setWaitForLock
(
this
);
if
(
checkDeadlock
)
{
ArrayList
<
Session
>
sessions
=
checkDeadlock
(
session
,
null
,
null
);
if
(
sessions
!=
null
)
{
throw
DbException
.
get
(
ErrorCode
.
DEADLOCK_1
,
getDeadlockDetails
(
sessions
));
}
}
else
{
// check for deadlocks from now on
checkDeadlock
=
true
;
}
long
now
=
System
.
currentTimeMillis
();
if
(
max
==
0
)
{
// try at least one more time
max
=
now
+
session
.
getLockTimeout
();
}
else
if
(
now
>=
max
)
{
traceLock
(
session
,
exclusive
,
"timeout after "
+
session
.
getLockTimeout
());
throw
DbException
.
get
(
ErrorCode
.
LOCK_TIMEOUT_1
,
getName
());
}
try
{
traceLock
(
session
,
exclusive
,
"waiting for"
);
if
(
database
.
getLockMode
()
==
Constants
.
LOCK_MODE_TABLE_GC
)
{
for
(
int
i
=
0
;
i
<
20
;
i
++)
{
long
free
=
Runtime
.
getRuntime
().
freeMemory
();
System
.
gc
();
long
free2
=
Runtime
.
getRuntime
().
freeMemory
();
if
(
free
==
free2
)
{
break
;
}
}
}
// don't wait too long so that deadlocks are detected early
long
sleep
=
Math
.
min
(
Constants
.
DEADLOCK_CHECK
,
max
-
now
);
if
(
sleep
==
0
)
{
sleep
=
1
;
}
waitForLock
=
true
;
database
.
wait
(
sleep
);
}
catch
(
InterruptedException
e
)
{
// ignore
}
}
}
private
static
String
getDeadlockDetails
(
ArrayList
<
Session
>
sessions
)
{
StringBuilder
buff
=
new
StringBuilder
();
for
(
Session
s
:
sessions
)
{
Table
lock
=
s
.
getWaitForLock
();
buff
.
append
(
"\nSession "
).
append
(
s
.
toString
()).
append
(
" is waiting to lock "
).
append
(
lock
.
toString
()).
append
(
" while locking "
);
int
i
=
0
;
for
(
Table
t
:
s
.
getLocks
())
{
if
(
i
++
>
0
)
{
buff
.
append
(
", "
);
}
buff
.
append
(
t
.
toString
());
if
(
t
instanceof
RegularTable
)
{
if
(((
MVTable
)
t
).
lockExclusive
==
s
)
{
buff
.
append
(
" (exclusive)"
);
}
else
{
buff
.
append
(
" (shared)"
);
}
}
}
buff
.
append
(
'.'
);
}
return
buff
.
toString
();
}
public
ArrayList
<
Session
>
checkDeadlock
(
Session
session
,
Session
clash
,
Set
<
Session
>
visited
)
{
// only one deadlock check at any given time
synchronized
(
RegularTable
.
class
)
{
if
(
clash
==
null
)
{
// verification is started
clash
=
session
;
visited
=
New
.
hashSet
();
}
else
if
(
clash
==
session
)
{
// we found a circle where this session is involved
return
New
.
arrayList
();
}
else
if
(
visited
.
contains
(
session
))
{
// we have already checked this session.
// there is a circle, but the sessions in the circle need to
// find it out themselves
return
null
;
}
visited
.
add
(
session
);
ArrayList
<
Session
>
error
=
null
;
for
(
Session
s
:
lockShared
)
{
if
(
s
==
session
)
{
// it doesn't matter if we have locked the object already
continue
;
}
Table
t
=
s
.
getWaitForLock
();
if
(
t
!=
null
)
{
error
=
t
.
checkDeadlock
(
s
,
clash
,
visited
);
if
(
error
!=
null
)
{
error
.
add
(
session
);
break
;
}
}
}
if
(
error
==
null
&&
lockExclusive
!=
null
)
{
Table
t
=
lockExclusive
.
getWaitForLock
();
if
(
t
!=
null
)
{
error
=
t
.
checkDeadlock
(
lockExclusive
,
clash
,
visited
);
if
(
error
!=
null
)
{
error
.
add
(
session
);
}
}
}
return
error
;
}
}
private
void
traceLock
(
Session
session
,
boolean
exclusive
,
String
s
)
{
if
(
traceLock
.
isDebugEnabled
())
{
traceLock
.
debug
(
"{0} {1} {2} {3}"
,
session
.
getId
(),
exclusive
?
"exclusive write lock"
:
"shared read lock"
,
s
,
getName
());
}
}
public
boolean
isLockedExclusively
()
{
return
lockExclusive
!=
null
;
}
public
void
unlock
(
Session
s
)
{
if
(
database
!=
null
)
{
traceLock
(
s
,
lockExclusive
==
s
,
"unlock"
);
if
(
lockExclusive
==
s
)
{
lockExclusive
=
null
;
}
if
(
lockShared
.
size
()
>
0
)
{
lockShared
.
remove
(
s
);
}
// TODO lock: maybe we need we fifo-queue to make sure nobody
// starves. check what other databases do
synchronized
(
database
)
{
if
(
database
.
getSessionCount
()
>
1
&&
waitForLock
)
{
database
.
notifyAll
();
}
}
}
}
@Override
...
...
@@ -96,17 +331,6 @@ public class MVTable extends TableBase {
return
true
;
}
@Override
public
void
unlock
(
Session
s
)
{
// TODO locking
}
@Override
public
boolean
isLockedExclusively
()
{
// TODO locking
return
false
;
}
@Override
public
void
close
(
Session
session
)
{
MVTableEngine
.
closeTable
(
storeName
,
this
);
...
...
@@ -144,6 +368,9 @@ public class MVTable extends TableBase {
// mainIndexColumn = -1;
// } else {
// }
if
(!
database
.
isStarting
()
&&
primaryIndex
.
getRowCount
(
session
)
!=
0
)
{
mainIndexColumn
=
-
1
;
}
if
(
mainIndexColumn
!=
-
1
)
{
primaryIndex
.
setMainIndexColumn
(
mainIndexColumn
);
index
=
new
MVDelegateIndex
(
this
,
indexId
,
...
...
@@ -346,7 +573,7 @@ public class MVTable extends TableBase {
@Override
public
String
getTableType
()
{
return
Table
.
EXTERNAL_TABLE_ENGIN
E
;
return
Table
.
TABL
E
;
}
@Override
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/res/help.csv
浏览文件 @
f898ba35
...
...
@@ -1384,6 +1384,10 @@ Truncate a value to the required precision."
{ USER | CURRENT_USER } ()
","
Returns the name of the current user of this session."
"Functions (System)","VERSION","
VERSION()
","
Returns the H2 version as a String."
"System Tables","Information Schema","
INFORMATION_SCHEMA
","
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/table/TableBase.java
浏览文件 @
f898ba35
...
...
@@ -67,7 +67,7 @@ public abstract class TableBase extends Table {
buff
.
append
(
column
.
getCreateSQL
());
}
buff
.
append
(
"\n)"
);
if
(
tableEngine
!=
null
)
{
if
(
tableEngine
!=
null
&&
!
tableEngine
.
endsWith
(
getDatabase
().
getSettings
().
defaultTableEngine
)
)
{
buff
.
append
(
"\nENGINE \""
);
buff
.
append
(
tableEngine
);
buff
.
append
(
'\"'
);
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/TestAll.java
浏览文件 @
f898ba35
...
...
@@ -110,6 +110,7 @@ import org.h2.test.store.TestConcurrent;
import
org.h2.test.store.TestDataUtils
;
import
org.h2.test.store.TestMVStore
;
import
org.h2.test.store.TestMVRTree
;
import
org.h2.test.store.TestMVTableEngine
;
import
org.h2.test.store.TestObjectDataType
;
import
org.h2.test.store.TestStreamStore
;
import
org.h2.test.synth.TestBtreeIndex
;
...
...
@@ -555,23 +556,23 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
beforeTest
();
// db
new
TestScriptSimple
().
runTest
(
this
);
//
new TestScriptSimple().runTest(this);
new
TestScript
().
runTest
(
this
);
new
TestAlter
().
runTest
(
this
);
new
TestAlterSchemaRename
().
runTest
(
this
);
new
TestAutoRecompile
().
runTest
(
this
);
new
TestBitField
().
runTest
(
this
);
new
TestBackup
().
runTest
(
this
);
//
new TestBackup().runTest(this);
new
TestBigDb
().
runTest
(
this
);
new
TestBigResult
().
runTest
(
this
);
new
TestCases
().
runTest
(
this
);
// new TestCases().runTest(this); // <<=
new
TestCheckpoint
().
runTest
(
this
);
new
TestCluster
().
runTest
(
this
);
//
new TestCluster().runTest(this);
new
TestCompatibility
().
runTest
(
this
);
new
TestCsv
().
runTest
(
this
);
new
TestDateStorage
().
runTest
(
this
);
new
TestDeadlock
().
runTest
(
this
);
new
TestEncryptedDb
().
runTest
(
this
);
//
new TestEncryptedDb().runTest(this);
new
TestExclusive
().
runTest
(
this
);
new
TestFullText
().
runTest
(
this
);
new
TestFunctionOverload
().
runTest
(
this
);
...
...
@@ -580,33 +581,33 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
new
TestIndex
().
runTest
(
this
);
new
TestLargeBlob
().
runTest
(
this
);
new
TestLinkedTable
().
runTest
(
this
);
new
TestListener
().
runTest
(
this
);
new
TestLob
().
runTest
(
this
);
//
new TestListener().runTest(this);
//
new TestLob().runTest(this);
new
TestMemoryUsage
().
runTest
(
this
);
new
TestMultiConn
().
runTest
(
this
);
new
TestMultiDimension
().
runTest
(
this
);
new
TestMultiThread
().
runTest
(
this
);
new
TestMultiThreadedKernel
().
runTest
(
this
);
new
TestOpenClose
().
runTest
(
this
);
new
TestOptimizations
().
runTest
(
this
);
new
TestOutOfMemory
().
runTest
(
this
);
new
TestPowerOff
().
runTest
(
this
);
//
new TestOpenClose().runTest(this);
//
new TestOptimizations().runTest(this);
//
new TestOutOfMemory().runTest(this);
//
new TestPowerOff().runTest(this);
new
TestQueryCache
().
runTest
(
this
);
new
TestReadOnly
().
runTest
(
this
);
//
new TestReadOnly().runTest(this);
new
TestRecursiveQueries
().
runTest
(
this
);
new
TestRights
().
runTest
(
this
);
new
TestRunscript
().
runTest
(
this
);
//
new TestRunscript().runTest(this);
new
TestSQLInjection
().
runTest
(
this
);
new
TestSessionsLocks
().
runTest
(
this
);
//
new TestSessionsLocks().runTest(this);
new
TestSelectCountNonNullColumn
().
runTest
(
this
);
new
TestSequence
().
runTest
(
this
);
new
TestSpaceReuse
().
runTest
(
this
);
new
TestSpeed
().
runTest
(
this
);
new
TestTableEngines
().
runTest
(
this
);
new
TestTempTables
().
runTest
(
this
);
new
TestTransaction
().
runTest
(
this
);
//
new TestTransaction().runTest(this);
new
TestTriggersConstraints
().
runTest
(
this
);
new
TestTwoPhaseCommit
().
runTest
(
this
);
//
new TestTwoPhaseCommit().runTest(this);
new
TestView
().
runTest
(
this
);
new
TestViewAlterTable
().
runTest
(
this
);
new
TestViewDropView
().
runTest
(
this
);
...
...
@@ -623,13 +624,13 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
new
TestBatchUpdates
().
runTest
(
this
);
new
TestCallableStatement
().
runTest
(
this
);
new
TestCancel
().
runTest
(
this
);
new
TestDatabaseEventListener
().
runTest
(
this
);
//
new TestDatabaseEventListener().runTest(this);
new
TestDriver
().
runTest
(
this
);
new
TestJavaObject
().
runTest
(
this
);
new
TestLimitUpdates
().
runTest
(
this
);
new
TestLobApi
().
runTest
(
this
);
new
TestManyJdbcObjects
().
runTest
(
this
);
new
TestMetaData
().
runTest
(
this
);
// new TestMetaData().runTest(this); // <<=
new
TestNativeSQL
().
runTest
(
this
);
new
TestPreparedStatement
().
runTest
(
this
);
new
TestResultSet
().
runTest
(
this
);
...
...
@@ -642,10 +643,10 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
new
TestConnectionPool
().
runTest
(
this
);
new
TestDataSource
().
runTest
(
this
);
new
TestXA
().
runTest
(
this
);
new
TestXASimple
().
runTest
(
this
);
//
new TestXASimple().runTest(this);
// server
new
TestAutoServer
().
runTest
(
this
);
//
new TestAutoServer().runTest(this);
new
TestNestedLoop
().
runTest
(
this
);
new
TestWeb
().
runTest
(
this
);
...
...
@@ -654,7 +655,7 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
new
TestMvcc2
().
runTest
(
this
);
new
TestMvcc3
().
runTest
(
this
);
new
TestMvccMultiThreaded
().
runTest
(
this
);
new
TestRowLocks
().
runTest
(
this
);
//
new TestRowLocks().runTest(this);
// synth
new
TestBtreeIndex
().
runTest
(
this
);
...
...
@@ -682,6 +683,7 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
new
TestDataUtils
().
runTest
(
this
);
new
TestMVRTree
().
runTest
(
this
);
new
TestMVStore
().
runTest
(
this
);
new
TestMVTableEngine
().
runTest
(
this
);
new
TestObjectDataType
().
runTest
(
this
);
new
TestStreamStore
().
runTest
(
this
);
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/TestBase.java
浏览文件 @
f898ba35
...
...
@@ -31,6 +31,7 @@ import java.util.LinkedList;
import
org.h2.jdbc.JdbcConnection
;
import
org.h2.message.DbException
;
import
org.h2.message.TraceSystem
;
import
org.h2.mvstore.db.MVTableEngine
;
import
org.h2.store.FileLock
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.test.utils.ProxyCodeGenerator
;
...
...
@@ -265,6 +266,8 @@ public abstract class TestBase {
}
else
{
url
=
name
;
}
int
test
;
url
=
addOption
(
url
,
"DEFAULT_TABLE_ENGINE"
,
MVTableEngine
.
class
.
getName
());
if
(!
config
.
memory
)
{
if
(
config
.
smallLog
&&
admin
)
{
url
=
addOption
(
url
,
"MAX_LOG_SIZE"
,
"1"
);
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/bench/test.properties
浏览文件 @
f898ba35
db1
=
H2, org.h2.Driver, jdbc:h2:data/test;LOCK_TIMEOUT=10000;LOCK_MODE=3, sa, sa
#xdb1 = H2, org.h2.Driver, jdbc:h2:data/test;LOCK_TIMEOUT=10000;LOCK_MODE=3;DEFAULT_TABLE_ENGINE=org.h2.mvstore.db.MVTableEngine, sa, sa
#xdb1 = H2, org.h2.Driver, jdbc:h2:data/test;LOG=1;LOCK_TIMEOUT=10000;LOCK_MODE=3;ACCESS_MODE_DATA=rwd, sa, sa
#xdb2 = H2 (nio), org.h2.Driver, jdbc:h2:nio:data/test;LOCK_TIMEOUT=10000;LOCK_MODE=3, sa, sa
#xdb3 = H2 (nioMapped), org.h2.Driver, jdbc:h2:nioMapped:data/test;LOCK_TIMEOUT=10000;LOCK_MODE=3, sa, sa
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/store/TestMVStore.java
浏览文件 @
f898ba35
...
...
@@ -735,16 +735,16 @@ public class TestMVStore extends TestBase {
assertTrue
(
m
.
containsKey
(
"chunk.1"
));
assertFalse
(
m
.
containsKey
(
"chunk.2"
));
assertEquals
(
"id:1,
name:data,
type:btree,createVersion:0,key:,value:"
,
assertEquals
(
"id:1,type:btree,createVersion:0,key:,value:"
,
m
.
get
(
"map.data"
));
assertTrue
(
m
.
containsKey
(
"chunk.1"
));
assertEquals
(
"Hello"
,
data
.
put
(
"1"
,
"Hallo"
));
s
.
store
();
assertEquals
(
"id:1,
name:data,
type:btree,createVersion:0,key:,value:"
,
assertEquals
(
"id:1,type:btree,createVersion:0,key:,value:"
,
m
.
get
(
"map.data"
));
assertTrue
(
m
.
get
(
"root.1"
).
length
()
>
0
);
assertTrue
(
m
.
containsKey
(
"chunk.1"
));
assertEquals
(
"id:1,length:2
8
1,maxLength:288,maxLengthLive:0,"
+
assertEquals
(
"id:1,length:2
7
1,maxLength:288,maxLengthLive:0,"
+
"metaRoot:274877910924,pageCount:2,"
+
"start:8192,time:0,version:1"
,
m
.
get
(
"chunk.1"
));
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/store/TestMVTableEngine.java
0 → 100644
浏览文件 @
f898ba35
/*
* Copyright 2004-2011 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
.
store
;
import
java.sql.Connection
;
import
java.sql.ResultSet
;
import
java.sql.Statement
;
import
org.h2.mvstore.db.MVTableEngine
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.test.TestBase
;
/**
* Tests the MVStore in a database.
*/
public
class
TestMVTableEngine
extends
TestBase
{
/**
* Run just this test.
*
* @param a ignored
*/
public
static
void
main
(
String
...
a
)
throws
Exception
{
TestBase
.
createCaller
().
init
().
test
();
}
public
void
test
()
throws
Exception
{
// testCase();
testSimple
();
}
private
void
testCase
()
throws
Exception
{
FileUtils
.
deleteRecursive
(
getBaseDir
(),
true
);
deleteDb
(
"cases"
);
Connection
conn
=
getConnection
(
"cases"
);
Statement
stat
=
conn
.
createStatement
();
conn
=
getConnection
(
"cases"
);
stat
=
conn
.
createStatement
();
stat
.
execute
(
"set max_operation_memory 1"
);
stat
.
execute
(
"create table test(id int)"
);
stat
.
execute
(
"insert into test values(1), (2)"
);
stat
.
execute
(
"create index idx on test(id)"
);
conn
.
setAutoCommit
(
false
);
stat
.
execute
(
"update test set id = id where id=2"
);
stat
.
execute
(
"update test set id = id"
);
conn
.
rollback
();
conn
.
close
();
}
private
void
testSimple
()
throws
Exception
{
FileUtils
.
deleteRecursive
(
getBaseDir
(),
true
);
Connection
conn
=
getConnection
(
"mvstore"
);
Statement
stat
=
conn
.
createStatement
();
// create table test(id int, name varchar) engine "org.h2.mvstore.db.MVStoreTableEngine"
stat
.
execute
(
"create table test(id int primary key, name varchar) engine \""
+
MVTableEngine
.
class
.
getName
()
+
"\""
);
stat
.
execute
(
"insert into test values(1, 'Hello'), (2, 'World')"
);
ResultSet
rs
=
stat
.
executeQuery
(
"select * from test"
);
assertTrue
(
rs
.
next
());
assertEquals
(
1
,
rs
.
getInt
(
1
));
assertEquals
(
"Hello"
,
rs
.
getString
(
2
));
conn
.
close
();
conn
=
getConnection
(
"mvstore"
);
stat
=
conn
.
createStatement
();
rs
=
stat
.
executeQuery
(
"select * from test order by id"
);
assertTrue
(
rs
.
next
());
assertEquals
(
1
,
rs
.
getInt
(
1
));
assertEquals
(
"Hello"
,
rs
.
getString
(
2
));
assertTrue
(
rs
.
next
());
assertEquals
(
2
,
rs
.
getInt
(
1
));
assertEquals
(
"World"
,
rs
.
getString
(
2
));
assertFalse
(
rs
.
next
());
stat
.
execute
(
"delete from test where id = 2"
);
rs
=
stat
.
executeQuery
(
"select * from test order by id"
);
assertTrue
(
rs
.
next
());
assertEquals
(
1
,
rs
.
getInt
(
1
));
assertEquals
(
"Hello"
,
rs
.
getString
(
2
));
assertFalse
(
rs
.
next
());
stat
.
execute
(
"create index idx_name on test(name)"
);
rs
=
stat
.
executeQuery
(
"select * from test where name = 'Hello'"
);
assertTrue
(
rs
.
next
());
assertEquals
(
1
,
rs
.
getInt
(
1
));
assertEquals
(
"Hello"
,
rs
.
getString
(
2
));
assertFalse
(
rs
.
next
());
conn
.
close
();
}
}
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/test-1.3.txt
浏览文件 @
f898ba35
...
...
@@ -6,11 +6,13 @@ select char(nextval('seq')) as x;
> X
> -
> A
> rows: 1
select char(nextval('seq')) as x;
> X
> -
> B
> rows: 1
drop sequence seq;
> ok
...
...
This diff is collapsed.
Click to expand it.
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论