Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
a921dc87
提交
a921dc87
authored
12月 12, 2012
作者:
Thomas Mueller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
MVStore: table engine
上级
3791fdca
隐藏空白字符变更
内嵌
并排
正在显示
20 个修改的文件
包含
2002 行增加
和
15 行删除
+2002
-15
changelog.html
h2/src/docsrc/html/changelog.html
+12
-3
Parser.java
h2/src/main/org/h2/command/Parser.java
+2
-0
DropDatabase.java
h2/src/main/org/h2/command/ddl/DropDatabase.java
+5
-0
Constants.java
h2/src/main/org/h2/engine/Constants.java
+5
-0
Session.java
h2/src/main/org/h2/engine/Session.java
+8
-6
BaseIndex.java
h2/src/main/org/h2/index/BaseIndex.java
+3
-2
Index.java
h2/src/main/org/h2/index/Index.java
+1
-1
MVDelegateIndex.java
h2/src/main/org/h2/mvstore/db/MVDelegateIndex.java
+121
-0
MVPrimaryIndex.java
h2/src/main/org/h2/mvstore/db/MVPrimaryIndex.java
+276
-0
MVSecondaryIndex.java
h2/src/main/org/h2/mvstore/db/MVSecondaryIndex.java
+223
-0
MVTable.java
h2/src/main/org/h2/mvstore/db/MVTable.java
+436
-0
MVTableEngine.java
h2/src/main/org/h2/mvstore/db/MVTableEngine.java
+89
-0
ValueArrayDataType.java
h2/src/main/org/h2/mvstore/db/ValueArrayDataType.java
+751
-0
ValueDataTypeFactory.java
h2/src/main/org/h2/mvstore/db/ValueDataTypeFactory.java
+45
-0
package.html
h2/src/main/org/h2/mvstore/db/package.html
+15
-0
DbContents.java
h2/src/main/org/h2/server/web/DbContents.java
+1
-1
Data.java
h2/src/main/org/h2/store/Data.java
+1
-1
FileLister.java
h2/src/main/org/h2/store/FileLister.java
+2
-0
RegularTable.java
h2/src/main/org/h2/table/RegularTable.java
+1
-1
Recover.java
h2/src/main/org/h2/tools/Recover.java
+5
-0
没有找到文件。
h2/src/docsrc/html/changelog.html
浏览文件 @
a921dc87
...
...
@@ -18,14 +18,23 @@ Change Log
<h1>
Change Log
</h1>
<h2>
Next Version (unreleased)
</h2>
<ul><li>
MVStore: store the file header also at the end of each chunk,
<ul><li>
New table engine "org.h2.mvstore.db.MVTableEngine"
that internally uses the MVStore to persist data.
To try it out, append ";DEFAULT_TABLE_ENGINE=org.h2.mvstore.db.MVTableEngine"
to the database URL.
This is still very experimental, and many features are not supported yet.
The data is stored in a file with the suffix ".mv.db".
</li><li>
New connection setting "DEFAULT_TABLE_ENGINE" to use a specific
table engine if none is set explicitly. This is to simplify testing
the MVStore table engine.
</li><li>
MVStore: store the file header also at the end of each chunk,
which results in a further reduced number of write operations.
</li><li>
MVStore: a map implementation that supports concurrent operations.
</li><li>
MVStore: unified exception handling; the version is included in the messages.
</li><li>
MVStore: old data is now retained for 45 seconds by default.
</ul><li>
MVStore: compress is now disabled by default, and can be enabled on request.
</ul><li>
Support ALTER TABLE ADD ... AFTER. Patch from Andrew Gaul
argaul@gmail.com
. Fixes issue 401.
</ul><li>
support "SELECT version()". Patch from Andrew Gaul
argaul@gmail.com
. Fixes issue 406.
</ul><li>
Support ALTER TABLE ADD ... AFTER. Patch from Andrew Gaul
(argaul at gmail.com)
. Fixes issue 401.
</ul><li>
support "SELECT version()". Patch from Andrew Gaul. Fixes issue 406.
</ul><li>
Improved OSGi support. H2 now registers itself as a DataSourceFactory service. Fixes issue 365.
</li></ul>
...
...
h2/src/main/org/h2/command/Parser.java
浏览文件 @
a921dc87
...
...
@@ -5278,6 +5278,8 @@ public class Parser {
}
if
(
readIf
(
"ENGINE"
))
{
command
.
setTableEngine
(
readUniqueIdentifier
());
}
else
if
(
database
.
getSettings
().
defaultTableEngine
!=
null
)
{
command
.
setTableEngine
(
database
.
getSettings
().
defaultTableEngine
);
}
if
(
temp
)
{
if
(
readIf
(
"ON"
))
{
...
...
h2/src/main/org/h2/command/ddl/DropDatabase.java
浏览文件 @
a921dc87
...
...
@@ -68,6 +68,11 @@ public class DropDatabase extends DefineCommand {
db
.
removeSchemaObject
(
session
,
t
);
}
}
for
(
Table
t
:
tables
)
{
if
(
t
.
getName
()
!=
null
&&
Table
.
EXTERNAL_TABLE_ENGINE
.
equals
(
t
.
getTableType
())
&&
!
t
.
isHidden
())
{
db
.
removeSchemaObject
(
session
,
t
);
}
}
session
.
findLocalTempTable
(
null
);
ArrayList
<
SchemaObject
>
list
=
New
.
arrayList
();
list
.
addAll
(
db
.
getAllSchemaObjects
(
DbObject
.
SEQUENCE
));
...
...
h2/src/main/org/h2/engine/Constants.java
浏览文件 @
a921dc87
...
...
@@ -423,6 +423,11 @@ public class Constants {
*/
public
static
final
String
SUFFIX_PAGE_FILE
=
".h2.db"
;
/**
* The file name suffix of a MVStore file.
*/
public
static
final
String
SUFFIX_MV_FILE
=
".mv.db"
;
/**
* The file name suffix of temporary files.
*/
...
...
h2/src/main/org/h2/engine/Session.java
浏览文件 @
a921dc87
...
...
@@ -606,13 +606,15 @@ public class Session extends SessionWithState {
}
undoLog
.
add
(
log
);
}
else
{
// see also UndoLogRecord.commit
ArrayList
<
Index
>
indexes
=
table
.
getIndexes
();
for
(
int
i
=
0
,
size
=
indexes
.
size
();
i
<
size
;
i
++)
{
Index
index
=
indexes
.
get
(
i
);
index
.
commit
(
operation
,
row
);
if
(
database
.
isMultiVersion
())
{
// see also UndoLogRecord.commit
ArrayList
<
Index
>
indexes
=
table
.
getIndexes
();
for
(
int
i
=
0
,
size
=
indexes
.
size
();
i
<
size
;
i
++)
{
Index
index
=
indexes
.
get
(
i
);
index
.
commit
(
operation
,
row
);
}
row
.
commit
();
}
row
.
commit
();
}
}
...
...
h2/src/main/org/h2/index/BaseIndex.java
浏览文件 @
a921dc87
...
...
@@ -72,11 +72,12 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index {
}
/**
* Create a duplicate key exception with a message that contains the index name
* Create a duplicate key exception with a message that contains the index
* name.
*
* @return the exception
*/
DbException
getDuplicateKeyException
()
{
protected
DbException
getDuplicateKeyException
()
{
String
sql
=
getName
()
+
" ON "
+
table
.
getSQL
()
+
"("
+
getColumnListSQL
()
+
")"
;
DbException
e
=
DbException
.
get
(
ErrorCode
.
DUPLICATE_KEY_1
,
sql
);
e
.
setSource
(
this
);
...
...
h2/src/main/org/h2/index/Index.java
浏览文件 @
a921dc87
...
...
@@ -203,7 +203,7 @@ public interface Index extends SchemaObject {
/**
* Commit the operation for a row. This is only important for multi-version
* indexes.
* indexes.
The method is only called if multi-version is enabled.
*
* @param operation the operation type
* @param row the row
...
...
h2/src/main/org/h2/mvstore/db/MVDelegateIndex.java
0 → 100644
浏览文件 @
a921dc87
/*
* 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
.
mvstore
.
db
;
import
org.h2.engine.Session
;
import
org.h2.index.BaseIndex
;
import
org.h2.index.Cursor
;
import
org.h2.index.IndexType
;
import
org.h2.message.DbException
;
import
org.h2.result.Row
;
import
org.h2.result.SearchRow
;
import
org.h2.table.Column
;
import
org.h2.table.IndexColumn
;
/**
* An index that delegates indexing to another index.
*/
public
class
MVDelegateIndex
extends
BaseIndex
{
private
final
MVPrimaryIndex
mainIndex
;
public
MVDelegateIndex
(
MVTable
table
,
int
id
,
String
name
,
MVPrimaryIndex
mainIndex
,
IndexType
indexType
)
{
IndexColumn
[]
cols
=
IndexColumn
.
wrap
(
new
Column
[]
{
table
.
getColumn
(
mainIndex
.
getMainIndexColumn
())});
this
.
initBaseIndex
(
table
,
id
,
name
,
cols
,
indexType
);
this
.
mainIndex
=
mainIndex
;
if
(!
database
.
isPersistent
()
||
id
<
0
)
{
throw
DbException
.
throwInternalError
(
""
+
name
);
}
}
public
void
add
(
Session
session
,
Row
row
)
{
// nothing to do
}
public
boolean
canFindNext
()
{
return
false
;
}
public
boolean
canGetFirstOrLast
()
{
return
false
;
// TODO
// return true;
}
public
void
close
(
Session
session
)
{
// nothing to do
}
public
Cursor
find
(
Session
session
,
SearchRow
first
,
SearchRow
last
)
{
long
min
=
mainIndex
.
getKey
(
first
,
Long
.
MIN_VALUE
,
Long
.
MIN_VALUE
);
// ifNull is MIN_VALUE as well, because the column is never NULL
// so avoid returning all rows (returning one row is OK)
long
max
=
mainIndex
.
getKey
(
last
,
Long
.
MAX_VALUE
,
Long
.
MIN_VALUE
);
return
mainIndex
.
find
(
session
,
min
,
max
);
}
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;
}
public
Cursor
findNext
(
Session
session
,
SearchRow
higherThan
,
SearchRow
last
)
{
throw
DbException
.
throwInternalError
();
}
public
int
getColumnIndex
(
Column
col
)
{
if
(
col
.
getColumnId
()
==
mainIndex
.
getMainIndexColumn
())
{
return
0
;
}
return
-
1
;
}
public
double
getCost
(
Session
session
,
int
[]
masks
)
{
return
10
*
getCostRangeIndex
(
masks
,
mainIndex
.
getRowCount
(
session
));
}
public
boolean
needRebuild
()
{
return
false
;
}
public
void
remove
(
Session
session
,
Row
row
)
{
// nothing to do
}
public
void
remove
(
Session
session
)
{
mainIndex
.
setMainIndexColumn
(-
1
);
// TODO remove map?
// session.getDatabase().getPageStore().removeMeta(this, session);
}
public
void
truncate
(
Session
session
)
{
// nothing to do
}
public
void
checkRename
()
{
// ok
}
public
long
getRowCount
(
Session
session
)
{
return
mainIndex
.
getRowCount
(
session
);
}
public
long
getRowCountApproximation
()
{
return
mainIndex
.
getRowCountApproximation
();
}
}
h2/src/main/org/h2/mvstore/db/MVPrimaryIndex.java
0 → 100644
浏览文件 @
a921dc87
/*
* 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
.
mvstore
.
db
;
import
java.util.Iterator
;
import
org.h2.constant.ErrorCode
;
import
org.h2.engine.Constants
;
import
org.h2.engine.Database
;
import
org.h2.engine.Session
;
import
org.h2.index.BaseIndex
;
import
org.h2.index.Cursor
;
import
org.h2.index.IndexType
;
import
org.h2.message.DbException
;
import
org.h2.mvstore.MVMap
;
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.IndexColumn
;
import
org.h2.value.Value
;
import
org.h2.value.ValueNull
;
/**
* A table stored in a MVStore.
*/
public
class
MVPrimaryIndex
extends
BaseIndex
{
protected
final
MVTable
mvTable
;
protected
MVMap
<
Long
,
Value
[]>
map
;
private
long
nextKey
;
private
int
mainIndexColumn
=
-
1
;
public
MVPrimaryIndex
(
Database
db
,
MVTable
table
,
int
id
,
IndexColumn
[]
columns
,
IndexType
indexType
)
{
this
.
mvTable
=
table
;
initBaseIndex
(
table
,
id
,
table
.
getName
()
+
"_DATA"
,
columns
,
indexType
);
int
[]
sortTypes
=
new
int
[
columns
.
length
];
for
(
int
i
=
0
;
i
<
columns
.
length
;
i
++)
{
sortTypes
[
i
]
=
SortOrder
.
ASCENDING
;
}
ValueArrayDataType
t
=
new
ValueArrayDataType
(
db
.
getCompareMode
(),
db
,
sortTypes
);
map
=
new
MVMap
<
Long
,
Value
[]>(
new
ObjectDataType
(),
t
);
map
=
table
.
getStore
().
openMap
(
getName
(),
map
);
Long
k
=
map
.
lastKey
();
nextKey
=
k
==
null
?
0
:
k
+
1
;
}
public
String
getCreateSQL
()
{
return
null
;
}
public
String
getPlanSQL
()
{
return
table
.
getSQL
()
+
".tableScan"
;
}
public
void
setMainIndexColumn
(
int
mainIndexColumn
)
{
this
.
mainIndexColumn
=
mainIndexColumn
;
}
public
int
getMainIndexColumn
()
{
return
mainIndexColumn
;
}
@Override
public
void
close
(
Session
session
)
{
// ok
}
@Override
public
void
add
(
Session
session
,
Row
row
)
{
if
(
mainIndexColumn
==
-
1
)
{
row
.
setKey
(
nextKey
++);
}
else
{
Long
c
=
row
.
getValue
(
mainIndexColumn
).
getLong
();
row
.
setKey
(
c
);
}
Value
[]
array
=
new
Value
[
columns
.
length
];
for
(
int
i
=
0
;
i
<
array
.
length
;
i
++)
{
array
[
i
]
=
row
.
getValue
(
i
);
}
if
(
map
.
containsKey
(
row
.
getKey
()))
{
String
sql
=
"PRIMARY KEY ON "
+
table
.
getSQL
();
if
(
mainIndexColumn
>=
0
&&
mainIndexColumn
<
indexColumns
.
length
)
{
sql
+=
"("
+
indexColumns
[
mainIndexColumn
].
getSQL
()
+
")"
;
}
DbException
e
=
DbException
.
get
(
ErrorCode
.
DUPLICATE_KEY_1
,
sql
);
e
.
setSource
(
this
);
throw
e
;
}
map
.
put
(
row
.
getKey
(),
array
);
}
@Override
public
void
remove
(
Session
session
,
Row
row
)
{
Value
[]
old
=
map
.
remove
(
row
.
getKey
());
if
(
old
==
null
)
{
throw
DbException
.
get
(
ErrorCode
.
ROW_NOT_FOUND_WHEN_DELETING_1
,
getSQL
()
+
": "
+
row
.
getKey
());
}
}
@Override
public
Cursor
find
(
Session
session
,
SearchRow
first
,
SearchRow
last
)
{
long
min
,
max
;
if
(
first
==
null
||
mainIndexColumn
<
0
)
{
min
=
Long
.
MIN_VALUE
;
}
else
{
Value
v
=
first
.
getValue
(
mainIndexColumn
);
if
(
v
==
null
)
{
min
=
0
;
}
else
{
min
=
v
.
getLong
();
}
}
if
(
last
==
null
||
mainIndexColumn
<
0
)
{
max
=
Long
.
MAX_VALUE
;
}
else
{
Value
v
=
last
.
getValue
(
mainIndexColumn
);
if
(
v
==
null
)
{
max
=
Long
.
MAX_VALUE
;
}
else
{
max
=
v
.
getLong
();
}
}
return
new
MVStoreCursor
(
session
,
map
.
keyIterator
(
min
),
max
);
}
public
MVTable
getTable
()
{
return
mvTable
;
}
public
Row
getRow
(
Session
session
,
long
key
)
{
Value
[]
array
=
map
.
get
(
key
);
Row
row
=
new
Row
(
array
,
0
);
row
.
setKey
(
key
);
return
row
;
}
@Override
public
double
getCost
(
Session
session
,
int
[]
masks
)
{
long
cost
=
10
*
(
map
.
getSize
()
+
Constants
.
COST_ROW_OFFSET
);
return
cost
;
}
@Override
public
void
remove
(
Session
session
)
{
if
(!
map
.
isClosed
())
{
map
.
removeMap
();
}
}
@Override
public
void
truncate
(
Session
session
)
{
map
.
clear
();
}
@Override
public
boolean
canGetFirstOrLast
()
{
return
false
;
}
@Override
public
Cursor
findFirstOrLast
(
Session
session
,
boolean
first
)
{
// return first ? map.firstKey() : map.lastKey();
// TODO get first / last
return
null
;
}
@Override
public
boolean
needRebuild
()
{
// TODO Auto-generated method stub
return
false
;
}
@Override
public
long
getRowCount
(
Session
session
)
{
return
map
.
getSize
();
}
@Override
public
long
getRowCountApproximation
()
{
return
map
.
getSize
();
}
@Override
public
void
checkRename
()
{
// ok
}
/**
* Get the key from the row.
*
* @param row the row
* @param ifEmpty the value to use if the row is empty
* @param ifNull the value to use if the column is NULL
* @return the key
*/
long
getKey
(
SearchRow
row
,
long
ifEmpty
,
long
ifNull
)
{
if
(
row
==
null
)
{
return
ifEmpty
;
}
Value
v
=
row
.
getValue
(
mainIndexColumn
);
if
(
v
==
null
)
{
throw
DbException
.
throwInternalError
(
row
.
toString
());
}
else
if
(
v
==
ValueNull
.
INSTANCE
)
{
return
ifNull
;
}
return
v
.
getLong
();
}
/**
* Search for a specific row or a set of rows.
*
* @param session the session
* @param first the key of the first row
* @param last the key of the last row
* @return the cursor
*/
Cursor
find
(
Session
session
,
long
first
,
long
last
)
{
return
new
MVStoreCursor
(
session
,
map
.
keyIterator
(
first
),
last
);
}
/**
* A cursor.
*/
class
MVStoreCursor
implements
Cursor
{
private
final
Session
session
;
private
final
Iterator
<
Long
>
it
;
private
final
long
last
;
private
Long
current
;
private
Row
row
;
public
MVStoreCursor
(
Session
session
,
Iterator
<
Long
>
it
,
long
last
)
{
this
.
session
=
session
;
this
.
it
=
it
;
this
.
last
=
last
;
}
@Override
public
Row
get
()
{
if
(
row
==
null
)
{
row
=
getRow
(
session
,
current
);
}
return
row
;
}
@Override
public
SearchRow
getSearchRow
()
{
return
get
();
}
@Override
public
boolean
next
()
{
current
=
it
.
next
();
if
(
current
!=
null
&&
current
>
last
)
{
current
=
null
;
}
row
=
null
;
return
current
!=
null
;
}
@Override
public
boolean
previous
()
{
// TODO previous
return
false
;
}
}
}
h2/src/main/org/h2/mvstore/db/MVSecondaryIndex.java
0 → 100644
浏览文件 @
a921dc87
/*
* 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
.
mvstore
.
db
;
import
java.util.Iterator
;
import
org.h2.constant.ErrorCode
;
import
org.h2.engine.Database
;
import
org.h2.engine.Session
;
import
org.h2.index.BaseIndex
;
import
org.h2.index.Cursor
;
import
org.h2.index.IndexType
;
import
org.h2.message.DbException
;
import
org.h2.mvstore.MVMap
;
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.ValueLong
;
/**
* A table stored in a MVStore.
*/
public
class
MVSecondaryIndex
extends
BaseIndex
{
protected
final
MVTable
mvTable
;
protected
final
int
keyColumns
;
protected
MVMap
<
Value
[],
Long
>
map
;
public
MVSecondaryIndex
(
Database
db
,
MVTable
table
,
int
id
,
String
indexName
,
IndexColumn
[]
columns
,
IndexType
indexType
)
{
this
.
mvTable
=
table
;
initBaseIndex
(
table
,
id
,
indexName
,
columns
,
indexType
);
// always store the row key in the map key,
// even for unique indexes, as some of the index columns could be null
keyColumns
=
columns
.
length
+
1
;
int
[]
sortTypes
=
new
int
[
keyColumns
];
for
(
int
i
=
0
;
i
<
columns
.
length
;
i
++)
{
sortTypes
[
i
]
=
columns
[
i
].
sortType
;
}
sortTypes
[
keyColumns
-
1
]
=
SortOrder
.
ASCENDING
;
ValueArrayDataType
t
=
new
ValueArrayDataType
(
db
.
getCompareMode
(),
db
,
sortTypes
);
map
=
new
MVMap
<
Value
[],
Long
>(
t
,
new
ObjectDataType
());
map
=
table
.
getStore
().
openMap
(
getName
(),
map
);
}
@Override
public
void
close
(
Session
session
)
{
// ok
}
@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
))
{
throw
getDuplicateKeyException
();
}
}
array
[
keyColumns
-
1
]
=
ValueLong
.
get
(
row
.
getKey
());
map
.
put
(
array
,
Long
.
valueOf
(
0
));
}
@Override
public
void
remove
(
Session
session
,
Row
row
)
{
Value
[]
array
=
getKey
(
row
);
Long
old
=
map
.
remove
(
array
);
if
(
old
==
null
)
{
if
(
old
==
null
)
{
throw
DbException
.
get
(
ErrorCode
.
ROW_NOT_FOUND_WHEN_DELETING_1
,
getSQL
()
+
": "
+
row
.
getKey
());
}
}
}
@Override
public
Cursor
find
(
Session
session
,
SearchRow
first
,
SearchRow
last
)
{
Value
[]
min
=
getKey
(
first
);
return
new
MVStoreCursor
(
session
,
map
.
keyIterator
(
min
),
last
);
}
private
Value
[]
getKey
(
SearchRow
r
)
{
if
(
r
==
null
)
{
return
null
;
}
Value
[]
array
=
new
Value
[
keyColumns
];
for
(
int
i
=
0
;
i
<
columns
.
length
;
i
++)
{
Column
c
=
columns
[
i
];
int
idx
=
c
.
getColumnId
();
if
(
r
!=
null
)
{
array
[
i
]
=
r
.
getValue
(
idx
);
}
}
array
[
keyColumns
-
1
]
=
ValueLong
.
get
(
r
.
getKey
());
return
array
;
}
public
MVTable
getTable
()
{
return
mvTable
;
}
@Override
public
double
getCost
(
Session
session
,
int
[]
masks
)
{
return
10
*
getCostRangeIndex
(
masks
,
map
.
getSize
());
}
@Override
public
void
remove
(
Session
session
)
{
if
(!
map
.
isClosed
())
{
map
.
removeMap
();
}
}
@Override
public
void
truncate
(
Session
session
)
{
map
.
clear
();
}
@Override
public
boolean
canGetFirstOrLast
()
{
return
false
;
}
@Override
public
Cursor
findFirstOrLast
(
Session
session
,
boolean
first
)
{
return
null
;
}
@Override
public
boolean
needRebuild
()
{
// TODO there should be a better way
return
map
.
getSize
()
==
0
;
}
@Override
public
long
getRowCount
(
Session
session
)
{
return
map
.
getSize
();
}
@Override
public
long
getRowCountApproximation
()
{
return
map
.
getSize
();
}
@Override
public
void
checkRename
()
{
// ok
}
/**
* A cursor.
*/
class
MVStoreCursor
implements
Cursor
{
private
final
Session
session
;
private
final
Iterator
<
Value
[]>
it
;
private
final
SearchRow
last
;
private
Value
[]
current
;
private
SearchRow
searchRow
;
private
Row
row
;
public
MVStoreCursor
(
Session
session
,
Iterator
<
Value
[]>
it
,
SearchRow
last
)
{
this
.
session
=
session
;
this
.
it
=
it
;
this
.
last
=
last
;
}
@Override
public
Row
get
()
{
if
(
row
==
null
)
{
row
=
mvTable
.
getRow
(
session
,
getSearchRow
().
getKey
());
}
return
row
;
}
@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
);
}
}
return
searchRow
;
}
@Override
public
boolean
next
()
{
current
=
it
.
next
();
searchRow
=
null
;
if
(
current
!=
null
)
{
if
(
last
!=
null
&&
compareRows
(
getSearchRow
(),
last
)
>
0
)
{
searchRow
=
null
;
current
=
null
;
}
}
row
=
null
;
return
current
!=
null
;
}
@Override
public
boolean
previous
()
{
// TODO previous
return
false
;
}
}
}
h2/src/main/org/h2/mvstore/db/MVTable.java
0 → 100644
浏览文件 @
a921dc87
/*
* 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
.
mvstore
.
db
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.Comparator
;
import
org.h2.api.DatabaseEventListener
;
import
org.h2.command.ddl.CreateTableData
;
import
org.h2.constant.ErrorCode
;
import
org.h2.constant.SysProperties
;
import
org.h2.constraint.Constraint
;
import
org.h2.constraint.ConstraintReferential
;
import
org.h2.engine.Constants
;
import
org.h2.engine.DbObject
;
import
org.h2.engine.Session
;
import
org.h2.index.Cursor
;
import
org.h2.index.Index
;
import
org.h2.index.IndexType
;
import
org.h2.index.MultiVersionIndex
;
import
org.h2.message.DbException
;
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.Table
;
import
org.h2.table.TableBase
;
import
org.h2.util.MathUtils
;
import
org.h2.util.New
;
import
org.h2.value.Value
;
/**
* A table stored in a MVStore.
*/
public
class
MVTable
extends
TableBase
{
private
final
String
storeName
;
private
final
MVStore
store
;
private
final
boolean
hidden
;
private
MVPrimaryIndex
primaryIndex
;
private
ArrayList
<
Index
>
indexes
=
New
.
arrayList
();
private
long
lastModificationId
;
private
long
rowCount
;
public
MVTable
(
CreateTableData
data
,
String
storeName
,
MVStore
store
)
{
super
(
data
);
this
.
storeName
=
storeName
;
this
.
store
=
store
;
this
.
hidden
=
data
.
isHidden
;
}
void
init
(
Session
session
)
{
primaryIndex
=
new
MVPrimaryIndex
(
session
.
getDatabase
(),
this
,
getId
(),
IndexColumn
.
wrap
(
getColumns
()),
IndexType
.
createScan
(
true
)
);
rowCount
=
primaryIndex
.
getRowCount
(
session
);
indexes
.
add
(
primaryIndex
);
}
@Override
public
void
lock
(
Session
session
,
boolean
exclusive
,
boolean
force
)
{
// TODO locking
}
@Override
public
boolean
isHidden
()
{
return
hidden
;
}
@Override
public
boolean
canTruncate
()
{
// TODO copy & pasted source code from RegularTable
if
(
getCheckForeignKeyConstraints
()
&&
database
.
getReferentialIntegrity
())
{
ArrayList
<
Constraint
>
constraints
=
getConstraints
();
if
(
constraints
!=
null
)
{
for
(
int
i
=
0
,
size
=
constraints
.
size
();
i
<
size
;
i
++)
{
Constraint
c
=
constraints
.
get
(
i
);
if
(!(
c
.
getConstraintType
().
equals
(
Constraint
.
REFERENTIAL
)))
{
continue
;
}
ConstraintReferential
ref
=
(
ConstraintReferential
)
c
;
if
(
ref
.
getRefTable
()
==
this
)
{
return
false
;
}
}
}
}
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
);
}
Row
getRow
(
Session
session
,
long
key
)
{
return
primaryIndex
.
getRow
(
session
,
key
);
}
@Override
public
Index
addIndex
(
Session
session
,
String
indexName
,
int
indexId
,
IndexColumn
[]
cols
,
IndexType
indexType
,
boolean
create
,
String
indexComment
)
{
if
(
indexType
.
isPrimaryKey
())
{
for
(
IndexColumn
c
:
cols
)
{
Column
column
=
c
.
column
;
if
(
column
.
isNullable
())
{
throw
DbException
.
get
(
ErrorCode
.
COLUMN_MUST_NOT_BE_NULLABLE_1
,
column
.
getName
());
}
column
.
setPrimaryKey
(
true
);
}
}
boolean
isSessionTemporary
=
isTemporary
()
&&
!
isGlobalTemporary
();
if
(!
isSessionTemporary
)
{
database
.
lockMeta
(
session
);
}
Index
index
;
// TODO support in-memory indexes
// if (isPersistIndexes() && indexType.isPersistent()) {
int
mainIndexColumn
;
mainIndexColumn
=
getMainIndexColumn
(
indexType
,
cols
);
// if (database.isStarting()) {
// mainIndexColumn = -1;
// } else if (!database.isStarting() && primaryIndex.getRowCount(session) != 0) {
// mainIndexColumn = -1;
// } else {
// }
if
(
mainIndexColumn
!=
-
1
)
{
primaryIndex
.
setMainIndexColumn
(
mainIndexColumn
);
index
=
new
MVDelegateIndex
(
this
,
indexId
,
indexName
,
primaryIndex
,
indexType
);
}
else
{
index
=
new
MVSecondaryIndex
(
session
.
getDatabase
(),
this
,
indexId
,
indexName
,
cols
,
indexType
);
}
// } else {
// index = new TreeIndex(this, indexId, indexName, cols, indexType);
// }
if
(
index
.
needRebuild
()
&&
rowCount
>
0
)
{
try
{
Index
scan
=
getScanIndex
(
session
);
long
remaining
=
scan
.
getRowCount
(
session
);
long
total
=
remaining
;
Cursor
cursor
=
scan
.
find
(
session
,
null
,
null
);
long
i
=
0
;
int
bufferSize
=
(
int
)
Math
.
min
(
rowCount
,
Constants
.
DEFAULT_MAX_MEMORY_ROWS
);
ArrayList
<
Row
>
buffer
=
New
.
arrayList
(
bufferSize
);
String
n
=
getName
()
+
":"
+
index
.
getName
();
int
t
=
MathUtils
.
convertLongToInt
(
total
);
while
(
cursor
.
next
())
{
database
.
setProgress
(
DatabaseEventListener
.
STATE_CREATE_INDEX
,
n
,
MathUtils
.
convertLongToInt
(
i
++),
t
);
Row
row
=
cursor
.
get
();
buffer
.
add
(
row
);
if
(
buffer
.
size
()
>=
bufferSize
)
{
addRowsToIndex
(
session
,
buffer
,
index
);
}
remaining
--;
}
addRowsToIndex
(
session
,
buffer
,
index
);
if
(
SysProperties
.
CHECK
&&
remaining
!=
0
)
{
DbException
.
throwInternalError
(
"rowcount remaining="
+
remaining
+
" "
+
getName
());
}
}
catch
(
DbException
e
)
{
getSchema
().
freeUniqueName
(
indexName
);
try
{
index
.
remove
(
session
);
}
catch
(
DbException
e2
)
{
// this could happen, for example on failure in the storage
// but if that is not the case it means
// there is something wrong with the database
trace
.
error
(
e2
,
"could not remove index"
);
throw
e2
;
}
throw
e
;
}
}
index
.
setTemporary
(
isTemporary
());
if
(
index
.
getCreateSQL
()
!=
null
)
{
index
.
setComment
(
indexComment
);
if
(
isSessionTemporary
)
{
session
.
addLocalTempTableIndex
(
index
);
}
else
{
database
.
addSchemaObject
(
session
,
index
);
}
}
indexes
.
add
(
index
);
setModified
();
return
index
;
}
private
int
getMainIndexColumn
(
IndexType
indexType
,
IndexColumn
[]
cols
)
{
if
(
primaryIndex
.
getMainIndexColumn
()
!=
-
1
)
{
return
-
1
;
}
if
(!
indexType
.
isPrimaryKey
()
||
cols
.
length
!=
1
)
{
return
-
1
;
}
IndexColumn
first
=
cols
[
0
];
if
(
first
.
sortType
!=
SortOrder
.
ASCENDING
)
{
return
-
1
;
}
switch
(
first
.
column
.
getType
())
{
case
Value
.
BYTE
:
case
Value
.
SHORT
:
case
Value
.
INT
:
case
Value
.
LONG
:
break
;
default
:
return
-
1
;
}
return
first
.
column
.
getColumnId
();
}
private
void
addRowsToIndex
(
Session
session
,
ArrayList
<
Row
>
list
,
Index
index
)
{
final
Index
idx
=
index
;
Collections
.
sort
(
list
,
new
Comparator
<
Row
>()
{
public
int
compare
(
Row
r1
,
Row
r2
)
{
return
idx
.
compareRows
(
r1
,
r2
);
}
});
for
(
Row
row
:
list
)
{
index
.
add
(
session
,
row
);
}
list
.
clear
();
storeIfRequired
();
}
@Override
public
void
removeRow
(
Session
session
,
Row
row
)
{
lastModificationId
=
database
.
getNextModificationDataId
();
int
i
=
indexes
.
size
()
-
1
;
try
{
for
(;
i
>=
0
;
i
--)
{
Index
index
=
indexes
.
get
(
i
);
index
.
remove
(
session
,
row
);
checkRowCount
(
session
,
index
,
-
1
);
}
rowCount
--;
}
catch
(
Throwable
e
)
{
try
{
while
(++
i
<
indexes
.
size
())
{
Index
index
=
indexes
.
get
(
i
);
index
.
add
(
session
,
row
);
checkRowCount
(
session
,
index
,
0
);
}
}
catch
(
DbException
e2
)
{
// this could happen, for example on failure in the storage
// but if that is not the case it means there is something wrong
// with the database
trace
.
error
(
e2
,
"could not undo operation"
);
throw
e2
;
}
throw
DbException
.
convert
(
e
);
}
analyzeIfRequired
(
session
);
storeIfRequired
();
}
@Override
public
void
truncate
(
Session
session
)
{
lastModificationId
=
database
.
getNextModificationDataId
();
for
(
int
i
=
indexes
.
size
()
-
1
;
i
>=
0
;
i
--)
{
Index
index
=
indexes
.
get
(
i
);
index
.
truncate
(
session
);
}
rowCount
=
0
;
storeIfRequired
();
}
@Override
public
void
addRow
(
Session
session
,
Row
row
)
{
lastModificationId
=
database
.
getNextModificationDataId
();
int
i
=
0
;
try
{
for
(
int
size
=
indexes
.
size
();
i
<
size
;
i
++)
{
Index
index
=
indexes
.
get
(
i
);
index
.
add
(
session
,
row
);
checkRowCount
(
session
,
index
,
1
);
}
rowCount
++;
}
catch
(
Throwable
e
)
{
try
{
while
(--
i
>=
0
)
{
Index
index
=
indexes
.
get
(
i
);
index
.
remove
(
session
,
row
);
checkRowCount
(
session
,
index
,
0
);
}
}
catch
(
DbException
e2
)
{
// this could happen, for example on failure in the storage
// but if that is not the case it means there is something wrong
// with the database
trace
.
error
(
e2
,
"could not undo operation"
);
throw
e2
;
}
DbException
de
=
DbException
.
convert
(
e
);
if
(
de
.
getErrorCode
()
==
ErrorCode
.
DUPLICATE_KEY_1
)
{
for
(
int
j
=
0
;
j
<
indexes
.
size
();
j
++)
{
Index
index
=
indexes
.
get
(
j
);
if
(
index
.
getIndexType
().
isUnique
()
&&
index
instanceof
MultiVersionIndex
)
{
MultiVersionIndex
mv
=
(
MultiVersionIndex
)
index
;
if
(
mv
.
isUncommittedFromOtherSession
(
session
,
row
))
{
throw
DbException
.
get
(
ErrorCode
.
CONCURRENT_UPDATE_1
,
index
.
getName
());
}
}
}
}
throw
de
;
}
analyzeIfRequired
(
session
);
storeIfRequired
();
}
private
void
checkRowCount
(
Session
session
,
Index
index
,
int
offset
)
{
// TODO verify
}
private
void
analyzeIfRequired
(
Session
session
)
{
// TODO analyze
}
@Override
public
void
checkSupportAlter
()
{
// ok
}
@Override
public
String
getTableType
()
{
return
Table
.
EXTERNAL_TABLE_ENGINE
;
}
@Override
public
Index
getScanIndex
(
Session
session
)
{
return
primaryIndex
;
}
@Override
public
Index
getUniqueIndex
()
{
return
primaryIndex
;
}
@Override
public
ArrayList
<
Index
>
getIndexes
()
{
return
indexes
;
}
@Override
public
long
getMaxDataModificationId
()
{
return
lastModificationId
;
}
@Override
public
boolean
isDeterministic
()
{
return
true
;
}
@Override
public
boolean
canGetRowCount
()
{
return
true
;
}
@Override
public
boolean
canDrop
()
{
return
true
;
}
public
void
removeChildrenAndResources
(
Session
session
)
{
super
.
removeChildrenAndResources
(
session
);
// go backwards because database.removeIndex will call table.removeIndex
while
(
indexes
.
size
()
>
1
)
{
Index
index
=
indexes
.
get
(
1
);
if
(
index
.
getName
()
!=
null
)
{
database
.
removeSchemaObject
(
session
,
index
);
}
}
if
(
SysProperties
.
CHECK
)
{
for
(
SchemaObject
obj
:
database
.
getAllSchemaObjects
(
DbObject
.
INDEX
))
{
Index
index
=
(
Index
)
obj
;
if
(
index
.
getTable
()
==
this
)
{
DbException
.
throwInternalError
(
"index not dropped: "
+
index
.
getName
());
}
}
}
primaryIndex
.
remove
(
session
);
database
.
removeMeta
(
session
,
getId
());
primaryIndex
=
null
;
close
(
session
);
invalidate
();
}
@Override
public
long
getRowCount
(
Session
session
)
{
return
primaryIndex
.
getRowCount
(
session
);
}
@Override
public
long
getRowCountApproximation
()
{
return
primaryIndex
.
getRowCountApproximation
();
}
@Override
public
void
checkRename
()
{
// ok
}
private
void
storeIfRequired
()
{
if
(
store
.
getUnsavedPageCount
()
>
1000
)
{
store
.
store
();
}
}
public
MVStore
getStore
()
{
return
store
;
}
}
h2/src/main/org/h2/mvstore/db/MVTableEngine.java
0 → 100644
浏览文件 @
a921dc87
/*
* 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
.
mvstore
.
db
;
import
java.util.ArrayList
;
import
java.util.Map
;
import
java.util.WeakHashMap
;
import
org.h2.api.TableEngine
;
import
org.h2.command.ddl.CreateTableData
;
import
org.h2.constant.ErrorCode
;
import
org.h2.engine.Constants
;
import
org.h2.engine.Database
;
import
org.h2.message.DbException
;
import
org.h2.mvstore.MVStore
;
import
org.h2.mvstore.MVStoreBuilder
;
import
org.h2.mvstore.type.DataTypeFactory
;
import
org.h2.table.TableBase
;
import
org.h2.upgrade.v1_1.util.New
;
/**
* A table engine that internally uses the MVStore.
*/
public
class
MVTableEngine
implements
TableEngine
{
static
final
Map
<
String
,
Store
>
STORES
=
new
WeakHashMap
<
String
,
Store
>();
@Override
public
TableBase
createTable
(
CreateTableData
data
)
{
Database
db
=
data
.
session
.
getDatabase
();
String
storeName
=
db
.
getDatabasePath
();
MVStoreBuilder
storeBuilder
;
Store
store
;
DataTypeFactory
f
=
new
ValueDataTypeFactory
(
db
.
getCompareMode
(),
db
);
if
(
storeName
==
null
)
{
storeBuilder
=
MVStoreBuilder
.
inMemory
();
storeBuilder
.
with
(
f
);
store
=
new
Store
(
db
,
storeBuilder
.
open
());
}
else
{
synchronized
(
STORES
)
{
store
=
STORES
.
get
(
storeName
);
if
(
store
==
null
)
{
storeBuilder
=
MVStoreBuilder
.
fileBased
(
storeName
+
Constants
.
SUFFIX_MV_FILE
);
storeBuilder
.
with
(
f
);
store
=
new
Store
(
db
,
storeBuilder
.
open
());
STORES
.
put
(
storeName
,
store
);
}
else
if
(
store
.
db
!=
db
)
{
throw
DbException
.
get
(
ErrorCode
.
DATABASE_ALREADY_OPEN_1
,
storeName
);
}
}
}
MVTable
table
=
new
MVTable
(
data
,
storeName
,
store
.
store
);
store
.
openTables
.
add
(
table
);
table
.
init
(
data
.
session
);
return
table
;
}
static
void
closeTable
(
String
storeName
,
MVTable
table
)
{
synchronized
(
STORES
)
{
Store
store
=
STORES
.
get
(
storeName
);
store
.
openTables
.
remove
(
table
);
if
(
store
.
openTables
.
size
()
==
0
)
{
store
.
store
.
store
();
store
.
store
.
close
();
STORES
.
remove
(
storeName
);
}
}
}
/**
* A store with open tables.
*/
static
class
Store
{
final
Database
db
;
final
MVStore
store
;
final
ArrayList
<
MVTable
>
openTables
=
New
.
arrayList
();
public
Store
(
Database
db
,
MVStore
store
)
{
this
.
db
=
db
;
this
.
store
=
store
;
}
}
}
h2/src/main/org/h2/mvstore/db/ValueArrayDataType.java
0 → 100644
浏览文件 @
a921dc87
/*
* 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
.
mvstore
.
db
;
import
java.math.BigDecimal
;
import
java.math.BigInteger
;
import
java.nio.ByteBuffer
;
import
java.sql.Date
;
import
java.sql.ResultSet
;
import
java.sql.ResultSetMetaData
;
import
java.sql.SQLException
;
import
java.sql.Time
;
import
java.sql.Timestamp
;
import
org.h2.constant.ErrorCode
;
import
org.h2.constant.SysProperties
;
import
org.h2.message.DbException
;
import
org.h2.mvstore.DataUtils
;
import
org.h2.mvstore.type.DataType
;
import
org.h2.result.SortOrder
;
import
org.h2.store.Data
;
import
org.h2.store.DataHandler
;
import
org.h2.store.LobStorage
;
import
org.h2.tools.SimpleResultSet
;
import
org.h2.util.DateTimeUtils
;
import
org.h2.util.StringUtils
;
import
org.h2.util.Utils
;
import
org.h2.value.CompareMode
;
import
org.h2.value.Value
;
import
org.h2.value.ValueArray
;
import
org.h2.value.ValueBoolean
;
import
org.h2.value.ValueByte
;
import
org.h2.value.ValueBytes
;
import
org.h2.value.ValueDate
;
import
org.h2.value.ValueDecimal
;
import
org.h2.value.ValueDouble
;
import
org.h2.value.ValueFloat
;
import
org.h2.value.ValueInt
;
import
org.h2.value.ValueJavaObject
;
import
org.h2.value.ValueLob
;
import
org.h2.value.ValueLobDb
;
import
org.h2.value.ValueLong
;
import
org.h2.value.ValueNull
;
import
org.h2.value.ValueResultSet
;
import
org.h2.value.ValueShort
;
import
org.h2.value.ValueString
;
import
org.h2.value.ValueStringFixed
;
import
org.h2.value.ValueStringIgnoreCase
;
import
org.h2.value.ValueTime
;
import
org.h2.value.ValueTimestamp
;
import
org.h2.value.ValueUuid
;
/**
* A row type.
*/
public
class
ValueArrayDataType
implements
DataType
{
static
final
String
PREFIX
=
ValueArrayDataType
.
class
.
getName
();
private
static
final
int
INT_0_15
=
32
;
private
static
final
int
LONG_0_7
=
48
;
private
static
final
int
DECIMAL_0_1
=
56
;
private
static
final
int
DECIMAL_SMALL_0
=
58
;
private
static
final
int
DECIMAL_SMALL
=
59
;
private
static
final
int
DOUBLE_0_1
=
60
;
private
static
final
int
FLOAT_0_1
=
62
;
private
static
final
int
BOOLEAN_FALSE
=
64
;
private
static
final
int
BOOLEAN_TRUE
=
65
;
private
static
final
int
INT_NEG
=
66
;
private
static
final
int
LONG_NEG
=
67
;
private
static
final
int
STRING_0_31
=
68
;
private
static
final
int
BYTES_0_31
=
100
;
private
static
final
int
LOCAL_TIME
=
132
;
private
static
final
int
LOCAL_DATE
=
133
;
private
static
final
int
LOCAL_TIMESTAMP
=
134
;
private
static
final
long
MILLIS_PER_MINUTE
=
1000
*
60
;
final
DataHandler
handler
;
final
CompareMode
compareMode
;
final
int
[]
sortTypes
;
ValueArrayDataType
(
CompareMode
compareMode
,
DataHandler
handler
,
int
[]
sortTypes
)
{
this
.
compareMode
=
compareMode
;
this
.
handler
=
handler
;
this
.
sortTypes
=
sortTypes
;
}
public
int
compare
(
Object
a
,
Object
b
)
{
if
(
a
==
b
)
{
return
0
;
}
Value
[]
ax
=
(
Value
[])
a
;
Value
[]
bx
=
(
Value
[])
b
;
int
al
=
ax
.
length
;
int
bl
=
bx
.
length
;
int
len
=
Math
.
min
(
al
,
bl
);
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
int
comp
=
compareValues
(
ax
[
i
],
bx
[
i
],
sortTypes
[
i
]);
if
(
comp
!=
0
)
{
return
comp
;
}
}
if
(
len
<
al
)
{
return
-
1
;
}
else
if
(
len
<
bl
)
{
return
1
;
}
return
0
;
}
private
int
compareValues
(
Value
a
,
Value
b
,
int
sortType
)
{
if
(
a
==
b
)
{
return
0
;
}
boolean
aNull
=
a
==
null
,
bNull
=
b
==
null
;
if
(
aNull
||
bNull
)
{
return
SortOrder
.
compareNull
(
aNull
,
sortType
);
}
int
comp
=
compareTypeSave
(
a
,
b
);
if
((
sortType
&
SortOrder
.
DESCENDING
)
!=
0
)
{
comp
=
-
comp
;
}
return
comp
;
}
public
int
compareTypeSave
(
Value
a
,
Value
b
)
{
if
(
a
==
b
)
{
return
0
;
}
int
dataType
=
Value
.
getHigherOrder
(
a
.
getType
(),
b
.
getType
());
a
=
a
.
convertTo
(
dataType
);
b
=
b
.
convertTo
(
dataType
);
return
a
.
compareTypeSave
(
b
,
compareMode
);
}
public
int
getMaxLength
(
Object
obj
)
{
Value
[]
x
=
(
Value
[])
obj
;
int
len
=
x
.
length
;
int
result
=
DataUtils
.
MAX_VAR_INT_LEN
;
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
result
+=
getMaxLength
(
x
[
i
]);
}
return
result
;
}
private
int
getMaxLength
(
Value
v
)
{
return
Data
.
getValueLen
(
v
,
handler
);
}
public
int
getMemory
(
Object
obj
)
{
Value
[]
x
=
(
Value
[])
obj
;
int
len
=
x
.
length
;
int
memory
=
0
;
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
memory
+=
getMemory
(
x
[
i
]);
}
return
memory
;
}
private
static
int
getMemory
(
Value
v
)
{
return
v
.
getMemory
();
}
public
Value
[]
read
(
ByteBuffer
buff
)
{
int
len
=
DataUtils
.
readVarInt
(
buff
);
Value
[]
x
=
new
Value
[
len
];
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
x
[
i
]
=
readValue
(
buff
);
}
return
x
;
}
public
void
write
(
ByteBuffer
buff
,
Object
obj
)
{
Value
[]
x
=
(
Value
[])
obj
;
int
len
=
x
.
length
;
DataUtils
.
writeVarInt
(
buff
,
len
);
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
writeValue
(
buff
,
x
[
i
]);
}
}
public
String
asString
()
{
StringBuilder
buff
=
new
StringBuilder
();
buff
.
append
(
PREFIX
);
buff
.
append
(
'('
);
for
(
int
i
=
0
;
i
<
sortTypes
.
length
;
i
++)
{
if
(
i
>
0
)
{
buff
.
append
(
','
);
}
buff
.
append
(
sortTypes
[
i
]);
}
buff
.
append
(
')'
);
return
buff
.
toString
();
}
/**
* Convert a row type to a row.
*
* @param t the type string
* @param factory the data type factory
* @return the row type
*/
static
ValueArrayDataType
fromString
(
CompareMode
compareMode
,
DataHandler
handler
,
String
t
)
{
if
(!
t
.
startsWith
(
PREFIX
)
||
!
t
.
endsWith
(
")"
))
{
throw
new
RuntimeException
(
"Unknown type: "
+
t
);
}
t
=
t
.
substring
(
PREFIX
.
length
(),
t
.
length
()
-
1
);
String
[]
array
=
StringUtils
.
arraySplit
(
t
,
','
,
false
);
int
[]
sortTypes
=
new
int
[
array
.
length
];
for
(
int
i
=
0
;
i
<
array
.
length
;
i
++)
{
sortTypes
[
i
]
=
Integer
.
parseInt
(
array
[
i
]);
}
return
new
ValueArrayDataType
(
compareMode
,
handler
,
sortTypes
);
}
private
void
writeValue
(
ByteBuffer
buff
,
Value
v
)
{
int
start
=
buff
.
position
();
if
(
v
==
ValueNull
.
INSTANCE
)
{
buff
.
put
((
byte
)
0
);
return
;
}
int
type
=
v
.
getType
();
switch
(
type
)
{
case
Value
.
BOOLEAN
:
buff
.
put
((
byte
)
(
v
.
getBoolean
().
booleanValue
()
?
BOOLEAN_TRUE
:
BOOLEAN_FALSE
));
break
;
case
Value
.
BYTE
:
buff
.
put
((
byte
)
type
);
buff
.
put
(
v
.
getByte
());
break
;
case
Value
.
SHORT
:
buff
.
put
((
byte
)
type
);
buff
.
putShort
(
v
.
getShort
());
break
;
case
Value
.
INT
:
{
int
x
=
v
.
getInt
();
if
(
x
<
0
)
{
buff
.
put
((
byte
)
INT_NEG
);
writeVarInt
(
buff
,
-
x
);
}
else
if
(
x
<
16
)
{
buff
.
put
((
byte
)
(
INT_0_15
+
x
));
}
else
{
buff
.
put
((
byte
)
type
);
writeVarInt
(
buff
,
x
);
}
break
;
}
case
Value
.
LONG
:
{
long
x
=
v
.
getLong
();
if
(
x
<
0
)
{
buff
.
put
((
byte
)
LONG_NEG
);
writeVarLong
(
buff
,
-
x
);
}
else
if
(
x
<
8
)
{
buff
.
put
((
byte
)
(
LONG_0_7
+
x
));
}
else
{
buff
.
put
((
byte
)
type
);
writeVarLong
(
buff
,
x
);
}
break
;
}
case
Value
.
DECIMAL
:
{
BigDecimal
x
=
v
.
getBigDecimal
();
if
(
BigDecimal
.
ZERO
.
equals
(
x
))
{
buff
.
put
((
byte
)
DECIMAL_0_1
);
}
else
if
(
BigDecimal
.
ONE
.
equals
(
x
))
{
buff
.
put
((
byte
)
(
DECIMAL_0_1
+
1
));
}
else
{
int
scale
=
x
.
scale
();
BigInteger
b
=
x
.
unscaledValue
();
int
bits
=
b
.
bitLength
();
if
(
bits
<=
63
)
{
if
(
scale
==
0
)
{
buff
.
put
((
byte
)
DECIMAL_SMALL_0
);
writeVarLong
(
buff
,
b
.
longValue
());
}
else
{
buff
.
put
((
byte
)
DECIMAL_SMALL
);
writeVarInt
(
buff
,
scale
);
writeVarLong
(
buff
,
b
.
longValue
());
}
}
else
{
buff
.
put
((
byte
)
type
);
writeVarInt
(
buff
,
scale
);
byte
[]
bytes
=
b
.
toByteArray
();
writeVarInt
(
buff
,
bytes
.
length
);
buff
.
put
(
bytes
,
0
,
bytes
.
length
);
}
}
break
;
}
case
Value
.
TIME
:
if
(
SysProperties
.
STORE_LOCAL_TIME
)
{
buff
.
put
((
byte
)
LOCAL_TIME
);
ValueTime
t
=
(
ValueTime
)
v
;
long
nanos
=
t
.
getNanos
();
long
millis
=
nanos
/
1000000
;
nanos
-=
millis
*
1000000
;
writeVarLong
(
buff
,
millis
);
writeVarLong
(
buff
,
nanos
);
}
else
{
buff
.
put
((
byte
)
type
);
writeVarLong
(
buff
,
DateTimeUtils
.
getTimeLocalWithoutDst
(
v
.
getTime
()));
}
break
;
case
Value
.
DATE
:
{
if
(
SysProperties
.
STORE_LOCAL_TIME
)
{
buff
.
put
((
byte
)
LOCAL_DATE
);
long
x
=
((
ValueDate
)
v
).
getDateValue
();
writeVarLong
(
buff
,
x
);
}
else
{
buff
.
put
((
byte
)
type
);
long
x
=
DateTimeUtils
.
getTimeLocalWithoutDst
(
v
.
getDate
());
writeVarLong
(
buff
,
x
/
MILLIS_PER_MINUTE
);
}
break
;
}
case
Value
.
TIMESTAMP
:
{
if
(
SysProperties
.
STORE_LOCAL_TIME
)
{
buff
.
put
((
byte
)
LOCAL_TIMESTAMP
);
ValueTimestamp
ts
=
(
ValueTimestamp
)
v
;
long
dateValue
=
ts
.
getDateValue
();
writeVarLong
(
buff
,
dateValue
);
long
nanos
=
ts
.
getNanos
();
long
millis
=
nanos
/
1000000
;
nanos
-=
millis
*
1000000
;
writeVarLong
(
buff
,
millis
);
writeVarLong
(
buff
,
nanos
);
}
else
{
Timestamp
ts
=
v
.
getTimestamp
();
buff
.
put
((
byte
)
type
);
writeVarLong
(
buff
,
DateTimeUtils
.
getTimeLocalWithoutDst
(
ts
));
writeVarInt
(
buff
,
ts
.
getNanos
());
}
break
;
}
case
Value
.
JAVA_OBJECT
:
{
buff
.
put
((
byte
)
type
);
byte
[]
b
=
v
.
getBytesNoCopy
();
writeVarInt
(
buff
,
b
.
length
);
buff
.
put
(
b
,
0
,
b
.
length
);
break
;
}
case
Value
.
BYTES
:
{
byte
[]
b
=
v
.
getBytesNoCopy
();
int
len
=
b
.
length
;
if
(
len
<
32
)
{
buff
.
put
((
byte
)
(
BYTES_0_31
+
len
));
buff
.
put
(
b
,
0
,
b
.
length
);
}
else
{
buff
.
put
((
byte
)
type
);
writeVarInt
(
buff
,
b
.
length
);
buff
.
put
(
b
,
0
,
b
.
length
);
}
break
;
}
case
Value
.
UUID
:
{
buff
.
put
((
byte
)
type
);
ValueUuid
uuid
=
(
ValueUuid
)
v
;
buff
.
putLong
(
uuid
.
getHigh
());
buff
.
putLong
(
uuid
.
getLow
());
break
;
}
case
Value
.
STRING
:
{
String
s
=
v
.
getString
();
int
len
=
s
.
length
();
if
(
len
<
32
)
{
buff
.
put
((
byte
)
(
STRING_0_31
+
len
));
writeStringWithoutLength
(
buff
,
s
,
len
);
}
else
{
buff
.
put
((
byte
)
type
);
writeString
(
buff
,
s
);
}
break
;
}
case
Value
.
STRING_IGNORECASE
:
case
Value
.
STRING_FIXED
:
buff
.
put
((
byte
)
type
);
writeString
(
buff
,
v
.
getString
());
break
;
case
Value
.
DOUBLE
:
{
double
x
=
v
.
getDouble
();
if
(
x
==
1.0d
)
{
buff
.
put
((
byte
)
(
DOUBLE_0_1
+
1
));
}
else
{
long
d
=
Double
.
doubleToLongBits
(
x
);
if
(
d
==
ValueDouble
.
ZERO_BITS
)
{
buff
.
put
((
byte
)
DOUBLE_0_1
);
}
else
{
buff
.
put
((
byte
)
type
);
writeVarLong
(
buff
,
Long
.
reverse
(
d
));
}
}
break
;
}
case
Value
.
FLOAT
:
{
float
x
=
v
.
getFloat
();
if
(
x
==
1.0f
)
{
buff
.
put
((
byte
)
(
FLOAT_0_1
+
1
));
}
else
{
int
f
=
Float
.
floatToIntBits
(
x
);
if
(
f
==
ValueFloat
.
ZERO_BITS
)
{
buff
.
put
((
byte
)
FLOAT_0_1
);
}
else
{
buff
.
put
((
byte
)
type
);
writeVarInt
(
buff
,
Integer
.
reverse
(
f
));
}
}
break
;
}
case
Value
.
BLOB
:
case
Value
.
CLOB
:
{
buff
.
put
((
byte
)
type
);
if
(
v
instanceof
ValueLob
)
{
ValueLob
lob
=
(
ValueLob
)
v
;
lob
.
convertToFileIfRequired
(
handler
);
byte
[]
small
=
lob
.
getSmall
();
if
(
small
==
null
)
{
int
t
=
-
1
;
if
(!
lob
.
isLinked
())
{
t
=
-
2
;
}
writeVarInt
(
buff
,
t
);
writeVarInt
(
buff
,
lob
.
getTableId
());
writeVarInt
(
buff
,
lob
.
getObjectId
());
writeVarLong
(
buff
,
lob
.
getPrecision
());
buff
.
put
((
byte
)
(
lob
.
useCompression
()
?
1
:
0
));
if
(
t
==
-
2
)
{
writeString
(
buff
,
lob
.
getFileName
());
}
}
else
{
writeVarInt
(
buff
,
small
.
length
);
buff
.
put
(
small
,
0
,
small
.
length
);
}
}
else
{
ValueLobDb
lob
=
(
ValueLobDb
)
v
;
byte
[]
small
=
lob
.
getSmall
();
if
(
small
==
null
)
{
writeVarInt
(
buff
,
-
3
);
writeVarInt
(
buff
,
lob
.
getTableId
());
writeVarLong
(
buff
,
lob
.
getLobId
());
writeVarLong
(
buff
,
lob
.
getPrecision
());
}
else
{
writeVarInt
(
buff
,
small
.
length
);
buff
.
put
(
small
,
0
,
small
.
length
);
}
}
break
;
}
case
Value
.
ARRAY
:
{
buff
.
put
((
byte
)
type
);
Value
[]
list
=
((
ValueArray
)
v
).
getList
();
writeVarInt
(
buff
,
list
.
length
);
for
(
Value
x
:
list
)
{
writeValue
(
buff
,
x
);
}
break
;
}
case
Value
.
RESULT_SET
:
{
buff
.
put
((
byte
)
type
);
try
{
ResultSet
rs
=
((
ValueResultSet
)
v
).
getResultSet
();
rs
.
beforeFirst
();
ResultSetMetaData
meta
=
rs
.
getMetaData
();
int
columnCount
=
meta
.
getColumnCount
();
writeVarInt
(
buff
,
columnCount
);
for
(
int
i
=
0
;
i
<
columnCount
;
i
++)
{
writeString
(
buff
,
meta
.
getColumnName
(
i
+
1
));
writeVarInt
(
buff
,
meta
.
getColumnType
(
i
+
1
));
writeVarInt
(
buff
,
meta
.
getPrecision
(
i
+
1
));
writeVarInt
(
buff
,
meta
.
getScale
(
i
+
1
));
}
while
(
rs
.
next
())
{
buff
.
put
((
byte
)
1
);
for
(
int
i
=
0
;
i
<
columnCount
;
i
++)
{
int
t
=
org
.
h2
.
value
.
DataType
.
convertSQLTypeToValueType
(
meta
.
getColumnType
(
i
+
1
));
Value
val
=
org
.
h2
.
value
.
DataType
.
readValue
(
null
,
rs
,
i
+
1
,
t
);
writeValue
(
buff
,
val
);
}
}
buff
.
put
((
byte
)
0
);
rs
.
beforeFirst
();
}
catch
(
SQLException
e
)
{
throw
DbException
.
convert
(
e
);
}
break
;
}
default
:
DbException
.
throwInternalError
(
"type="
+
v
.
getType
());
}
if
(
SysProperties
.
CHECK2
)
{
if
(
buff
.
position
()
-
start
!=
Data
.
getValueLen
(
v
,
handler
))
{
throw
DbException
.
throwInternalError
(
"value size error: got "
+
(
buff
.
position
()
-
start
)
+
" expected "
+
Data
.
getValueLen
(
v
,
handler
));
}
}
}
private
static
void
writeVarInt
(
ByteBuffer
buff
,
int
x
)
{
while
((
x
&
~
0x7f
)
!=
0
)
{
buff
.
put
((
byte
)
(
0x80
|
(
x
&
0x7f
)));
x
>>>=
7
;
}
buff
.
put
((
byte
)
x
);
}
private
static
void
writeVarLong
(
ByteBuffer
buff
,
long
x
)
{
while
((
x
&
~
0x7f
)
!=
0
)
{
buff
.
put
((
byte
)
((
x
&
0x7f
)
|
0x80
));
x
>>>=
7
;
}
buff
.
put
((
byte
)
x
);
}
private
static
void
writeString
(
ByteBuffer
buff
,
String
s
)
{
int
len
=
s
.
length
();
writeVarInt
(
buff
,
len
);
writeStringWithoutLength
(
buff
,
s
,
len
);
}
private
static
void
writeStringWithoutLength
(
ByteBuffer
buff
,
String
s
,
int
len
)
{
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
int
c
=
s
.
charAt
(
i
);
if
(
c
<
0x80
)
{
buff
.
put
((
byte
)
c
);
}
else
if
(
c
>=
0x800
)
{
buff
.
put
((
byte
)
(
0xe0
|
(
c
>>
12
)));
buff
.
put
((
byte
)
(((
c
>>
6
)
&
0x3f
)));
buff
.
put
((
byte
)
(
c
&
0x3f
));
}
else
{
buff
.
put
((
byte
)
(
0xc0
|
(
c
>>
6
)));
buff
.
put
((
byte
)
(
c
&
0x3f
));
}
}
}
// private void writeStringWithoutLength(char[] chars, int len) {
// int p = pos;
// byte[] buff = data;
// for (int i = 0; i < len; i++) {
// int c = chars[i];
// if (c < 0x80) {
// buff[p++] = (byte) c;
// } else if (c >= 0x800) {
// buff[p++] = (byte) (0xe0 | (c >> 12));
// buff[p++] = (byte) (((c >> 6) & 0x3f));
// buff[p++] = (byte) (c & 0x3f);
// } else {
// buff[p++] = (byte) (0xc0 | (c >> 6));
// buff[p++] = (byte) (c & 0x3f);
// }
// }
// pos = p;
// }
/**
* Read a value.
*
* @return the value
*/
private
Value
readValue
(
ByteBuffer
buff
)
{
int
type
=
buff
.
get
()
&
255
;
switch
(
type
)
{
case
Value
.
NULL
:
return
ValueNull
.
INSTANCE
;
case
BOOLEAN_TRUE:
return
ValueBoolean
.
get
(
true
);
case
BOOLEAN_FALSE:
return
ValueBoolean
.
get
(
false
);
case
INT_NEG:
return
ValueInt
.
get
(-
readVarInt
(
buff
));
case
Value
.
INT
:
return
ValueInt
.
get
(
readVarInt
(
buff
));
case
LONG_NEG:
return
ValueLong
.
get
(-
readVarLong
(
buff
));
case
Value
.
LONG
:
return
ValueLong
.
get
(
readVarLong
(
buff
));
case
Value
.
BYTE
:
return
ValueByte
.
get
(
buff
.
get
());
case
Value
.
SHORT
:
return
ValueShort
.
get
(
buff
.
getShort
());
case
DECIMAL_0_1:
return
(
ValueDecimal
)
ValueDecimal
.
ZERO
;
case
DECIMAL_0_1
+
1
:
return
(
ValueDecimal
)
ValueDecimal
.
ONE
;
case
DECIMAL_SMALL_0:
return
ValueDecimal
.
get
(
BigDecimal
.
valueOf
(
readVarLong
(
buff
)));
case
DECIMAL_SMALL:
{
int
scale
=
readVarInt
(
buff
);
return
ValueDecimal
.
get
(
BigDecimal
.
valueOf
(
readVarLong
(
buff
),
scale
));
}
case
Value
.
DECIMAL
:
{
int
scale
=
readVarInt
(
buff
);
int
len
=
readVarInt
(
buff
);
byte
[]
buff2
=
Utils
.
newBytes
(
len
);
buff
.
get
(
buff2
,
0
,
len
);
BigInteger
b
=
new
BigInteger
(
buff2
);
return
ValueDecimal
.
get
(
new
BigDecimal
(
b
,
scale
));
}
case
LOCAL_DATE:
{
return
ValueDate
.
fromDateValue
(
readVarLong
(
buff
));
}
case
Value
.
DATE
:
{
long
x
=
readVarLong
(
buff
)
*
MILLIS_PER_MINUTE
;
return
ValueDate
.
get
(
new
Date
(
DateTimeUtils
.
getTimeUTCWithoutDst
(
x
)));
}
case
LOCAL_TIME:
{
long
nanos
=
readVarLong
(
buff
)
*
1000000
+
readVarLong
(
buff
);
return
ValueTime
.
fromNanos
(
nanos
);
}
case
Value
.
TIME
:
// need to normalize the year, month and day
return
ValueTime
.
get
(
new
Time
(
DateTimeUtils
.
getTimeUTCWithoutDst
(
readVarLong
(
buff
))));
case
LOCAL_TIMESTAMP:
{
long
dateValue
=
readVarLong
(
buff
);
long
nanos
=
readVarLong
(
buff
)
*
1000000
+
readVarLong
(
buff
);
return
ValueTimestamp
.
fromDateValueAndNanos
(
dateValue
,
nanos
);
}
case
Value
.
TIMESTAMP
:
{
Timestamp
ts
=
new
Timestamp
(
DateTimeUtils
.
getTimeUTCWithoutDst
(
readVarLong
(
buff
)));
ts
.
setNanos
(
readVarInt
(
buff
));
return
ValueTimestamp
.
get
(
ts
);
}
case
Value
.
BYTES
:
{
int
len
=
readVarInt
(
buff
);
byte
[]
b
=
Utils
.
newBytes
(
len
);
buff
.
get
(
b
,
0
,
len
);
return
ValueBytes
.
getNoCopy
(
b
);
}
case
Value
.
JAVA_OBJECT
:
{
int
len
=
readVarInt
(
buff
);
byte
[]
b
=
Utils
.
newBytes
(
len
);
buff
.
get
(
b
,
0
,
len
);
return
ValueJavaObject
.
getNoCopy
(
null
,
b
);
}
case
Value
.
UUID
:
return
ValueUuid
.
get
(
buff
.
getLong
(),
buff
.
getLong
());
case
Value
.
STRING
:
return
ValueString
.
get
(
readString
(
buff
));
case
Value
.
STRING_IGNORECASE
:
return
ValueStringIgnoreCase
.
get
(
readString
(
buff
));
case
Value
.
STRING_FIXED
:
return
ValueStringFixed
.
get
(
readString
(
buff
));
case
FLOAT_0_1:
return
ValueFloat
.
get
(
0
);
case
FLOAT_0_1
+
1
:
return
ValueFloat
.
get
(
1
);
case
DOUBLE_0_1:
return
ValueDouble
.
get
(
0
);
case
DOUBLE_0_1
+
1
:
return
ValueDouble
.
get
(
1
);
case
Value
.
DOUBLE
:
return
ValueDouble
.
get
(
Double
.
longBitsToDouble
(
Long
.
reverse
(
readVarLong
(
buff
))));
case
Value
.
FLOAT
:
return
ValueFloat
.
get
(
Float
.
intBitsToFloat
(
Integer
.
reverse
(
readVarInt
(
buff
))));
case
Value
.
BLOB
:
case
Value
.
CLOB
:
{
int
smallLen
=
readVarInt
(
buff
);
if
(
smallLen
>=
0
)
{
byte
[]
small
=
Utils
.
newBytes
(
smallLen
);
buff
.
get
(
small
,
0
,
smallLen
);
return
LobStorage
.
createSmallLob
(
type
,
small
);
}
else
if
(
smallLen
==
-
3
)
{
int
tableId
=
readVarInt
(
buff
);
long
lobId
=
readVarLong
(
buff
);
long
precision
=
readVarLong
(
buff
);
LobStorage
lobStorage
=
handler
.
getLobStorage
();
ValueLobDb
lob
=
ValueLobDb
.
create
(
type
,
lobStorage
,
tableId
,
lobId
,
null
,
precision
);
return
lob
;
}
else
{
int
tableId
=
readVarInt
(
buff
);
int
objectId
=
readVarInt
(
buff
);
long
precision
=
0
;
boolean
compression
=
false
;
// -1: regular
// -2: regular, but not linked (in this case: including file name)
if
(
smallLen
==
-
1
||
smallLen
==
-
2
)
{
precision
=
readVarLong
(
buff
);
compression
=
buff
.
get
()
==
1
;
}
ValueLob
lob
=
ValueLob
.
open
(
type
,
handler
,
tableId
,
objectId
,
precision
,
compression
);
if
(
smallLen
==
-
2
)
{
lob
.
setFileName
(
readString
(
buff
),
false
);
}
return
lob
;
}
}
case
Value
.
ARRAY
:
{
int
len
=
readVarInt
(
buff
);
Value
[]
list
=
new
Value
[
len
];
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
list
[
i
]
=
readValue
(
buff
);
}
return
ValueArray
.
get
(
list
);
}
case
Value
.
RESULT_SET
:
{
SimpleResultSet
rs
=
new
SimpleResultSet
();
int
columns
=
readVarInt
(
buff
);
for
(
int
i
=
0
;
i
<
columns
;
i
++)
{
rs
.
addColumn
(
readString
(
buff
),
readVarInt
(
buff
),
readVarInt
(
buff
),
readVarInt
(
buff
));
}
while
(
true
)
{
if
(
buff
.
get
()
==
0
)
{
break
;
}
Object
[]
o
=
new
Object
[
columns
];
for
(
int
i
=
0
;
i
<
columns
;
i
++)
{
o
[
i
]
=
readValue
(
buff
).
getObject
();
}
rs
.
addRow
(
o
);
}
return
ValueResultSet
.
get
(
rs
);
}
default
:
if
(
type
>=
INT_0_15
&&
type
<
INT_0_15
+
16
)
{
return
ValueInt
.
get
(
type
-
INT_0_15
);
}
else
if
(
type
>=
LONG_0_7
&&
type
<
LONG_0_7
+
8
)
{
return
ValueLong
.
get
(
type
-
LONG_0_7
);
}
else
if
(
type
>=
BYTES_0_31
&&
type
<
BYTES_0_31
+
32
)
{
int
len
=
type
-
BYTES_0_31
;
byte
[]
b
=
Utils
.
newBytes
(
len
);
buff
.
get
(
b
,
0
,
len
);
return
ValueBytes
.
getNoCopy
(
b
);
}
else
if
(
type
>=
STRING_0_31
&&
type
<
STRING_0_31
+
32
)
{
return
ValueString
.
get
(
readString
(
buff
,
type
-
STRING_0_31
));
}
throw
DbException
.
get
(
ErrorCode
.
FILE_CORRUPTED_1
,
"type: "
+
type
);
}
}
private
static
int
readVarInt
(
ByteBuffer
buff
)
{
return
DataUtils
.
readVarInt
(
buff
);
}
private
static
long
readVarLong
(
ByteBuffer
buff
)
{
return
DataUtils
.
readVarLong
(
buff
);
}
private
static
String
readString
(
ByteBuffer
buff
,
int
len
)
{
return
DataUtils
.
readString
(
buff
,
len
);
}
private
static
String
readString
(
ByteBuffer
buff
)
{
int
len
=
readVarInt
(
buff
);
return
DataUtils
.
readString
(
buff
,
len
);
}
}
h2/src/main/org/h2/mvstore/db/ValueDataTypeFactory.java
0 → 100644
浏览文件 @
a921dc87
/*
* 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
.
mvstore
.
db
;
import
org.h2.mvstore.type.DataType
;
import
org.h2.mvstore.type.DataTypeFactory
;
import
org.h2.store.DataHandler
;
import
org.h2.value.CompareMode
;
/**
* A data type factory for rows.
*/
public
class
ValueDataTypeFactory
implements
DataTypeFactory
{
private
final
CompareMode
compareMode
;
private
final
DataHandler
handler
;
private
DataTypeFactory
parent
;
ValueDataTypeFactory
(
CompareMode
compareMode
,
DataHandler
handler
)
{
this
.
compareMode
=
compareMode
;
this
.
handler
=
handler
;
}
@Override
public
void
setParent
(
DataTypeFactory
parent
)
{
this
.
parent
=
parent
;
}
@Override
public
DataType
buildDataType
(
String
s
)
{
if
(
s
.
startsWith
(
ValueArrayDataType
.
PREFIX
))
{
return
ValueArrayDataType
.
fromString
(
compareMode
,
handler
,
s
);
}
return
parent
.
buildDataType
(
s
);
}
@Override
public
String
getDataType
(
Class
<?>
objectClass
)
{
return
parent
.
getDataType
(
objectClass
);
}
}
h2/src/main/org/h2/mvstore/db/package.html
0 → 100644
浏览文件 @
a921dc87
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!--
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
-->
<html
xmlns=
"http://www.w3.org/1999/xhtml"
lang=
"en"
xml:lang=
"en"
>
<head><meta
http-equiv=
"Content-Type"
content=
"text/html;charset=utf-8"
/><title>
Javadoc package documentation
</title></head><body
style=
"font: 9pt/130% Tahoma, Arial, Helvetica, sans-serif; font-weight: normal;"
><p>
Helper classes to use the MVStore in the H2 database.
</p></body></html>
\ No newline at end of file
h2/src/main/org/h2/server/web/DbContents.java
浏览文件 @
a921dc87
...
...
@@ -137,7 +137,7 @@ public class DbContents {
}
schemas
[
i
]
=
schema
;
String
[]
tableTypes
=
{
"TABLE"
,
"SYSTEM TABLE"
,
"VIEW"
,
"SYSTEM VIEW"
,
"TABLE LINK"
,
"SYNONYM"
};
"TABLE LINK"
,
"SYNONYM"
,
"EXTERNAL"
};
schema
.
readTables
(
meta
,
tableTypes
);
}
if
(
defaultSchema
==
null
)
{
...
...
h2/src/main/org/h2/store/Data.java
浏览文件 @
a921dc87
...
...
@@ -873,7 +873,7 @@ public class Data {
* @param handler the data handler for lobs
* @return the number of bytes required to store this value
*/
p
rivate
static
int
getValueLen
(
Value
v
,
DataHandler
handler
)
{
p
ublic
static
int
getValueLen
(
Value
v
,
DataHandler
handler
)
{
if
(
v
==
ValueNull
.
INSTANCE
)
{
return
1
;
}
...
...
h2/src/main/org/h2/store/FileLister.java
浏览文件 @
a921dc87
...
...
@@ -86,6 +86,8 @@ public class FileLister {
ok
=
true
;
}
else
if
(
f
.
endsWith
(
Constants
.
SUFFIX_PAGE_FILE
))
{
ok
=
true
;
}
else
if
(
f
.
endsWith
(
Constants
.
SUFFIX_MV_FILE
))
{
ok
=
true
;
}
else
if
(
all
)
{
if
(
f
.
endsWith
(
Constants
.
SUFFIX_LOCK_FILE
))
{
ok
=
true
;
...
...
h2/src/main/org/h2/table/RegularTable.java
浏览文件 @
a921dc87
...
...
@@ -111,11 +111,11 @@ public class RegularTable extends TableBase {
}
public
void
addRow
(
Session
session
,
Row
row
)
{
int
i
=
0
;
lastModificationId
=
database
.
getNextModificationDataId
();
if
(
database
.
isMultiVersion
())
{
row
.
setSessionId
(
session
.
getId
());
}
int
i
=
0
;
try
{
for
(
int
size
=
indexes
.
size
();
i
<
size
;
i
++)
{
Index
index
=
indexes
.
get
(
i
);
...
...
h2/src/main/org/h2/tools/Recover.java
浏览文件 @
a921dc87
...
...
@@ -28,6 +28,7 @@ import org.h2.engine.DbObject;
import
org.h2.engine.MetaRecord
;
import
org.h2.jdbc.JdbcConnection
;
import
org.h2.message.DbException
;
import
org.h2.mvstore.MVStoreTool
;
import
org.h2.result.Row
;
import
org.h2.result.SimpleRow
;
import
org.h2.security.SHA256
;
...
...
@@ -241,6 +242,10 @@ public class Recover extends Tool implements DataHandler {
dumpPageStore
(
fileName
);
}
else
if
(
fileName
.
endsWith
(
Constants
.
SUFFIX_LOB_FILE
))
{
dumpLob
(
fileName
,
false
);
}
else
if
(
fileName
.
endsWith
(
Constants
.
SUFFIX_MV_FILE
))
{
PrintWriter
writer
=
getWriter
(
fileName
,
".mv.txt"
);
MVStoreTool
.
dump
(
fileName
,
writer
);
writer
.
close
();
}
}
}
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论