Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
40de3268
提交
40de3268
authored
15 年前
作者:
Thomas Mueller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
New lob storage.
上级
8ffac30c
显示空白字符变更
内嵌
并排
正在显示
14 个修改的文件
包含
479 行增加
和
498 行删除
+479
-498
DropTable.java
h2/src/main/org/h2/command/ddl/DropTable.java
+1
-2
ScriptBase.java
h2/src/main/org/h2/command/dml/ScriptBase.java
+5
-0
SysProperties.java
h2/src/main/org/h2/constant/SysProperties.java
+7
-1
SessionRemote.java
h2/src/main/org/h2/engine/SessionRemote.java
+9
-0
JdbcConnection.java
h2/src/main/org/h2/jdbc/JdbcConnection.java
+16
-7
Data.java
h2/src/main/org/h2/store/Data.java
+83
-50
DataHandler.java
h2/src/main/org/h2/store/DataHandler.java
+13
-0
LobStorage.java
h2/src/main/org/h2/store/LobStorage.java
+120
-60
Recover.java
h2/src/main/org/h2/tools/Recover.java
+7
-0
DataType.java
h2/src/main/org/h2/value/DataType.java
+6
-6
Transfer.java
h2/src/main/org/h2/value/Transfer.java
+3
-4
Value.java
h2/src/main/org/h2/value/Value.java
+1
-0
ValueLob.java
h2/src/main/org/h2/value/ValueLob.java
+0
-3
ValueLob2.java
h2/src/main/org/h2/value/ValueLob2.java
+208
-365
没有找到文件。
h2/src/main/org/h2/command/ddl/DropTable.java
浏览文件 @
40de3268
...
...
@@ -12,7 +12,6 @@ import org.h2.engine.Right;
import
org.h2.engine.Session
;
import
org.h2.message.DbException
;
import
org.h2.schema.Schema
;
import
org.h2.store.LobStorage
;
import
org.h2.table.Table
;
/**
...
...
@@ -83,7 +82,7 @@ public class DropTable extends SchemaCommand {
table
.
setModified
();
Database
db
=
session
.
getDatabase
();
db
.
removeSchemaObject
(
session
,
table
);
LobStorage
.
removeAllForTable
(
db
,
dropTableId
);
db
.
getLobStorage
().
removeAllForTable
(
dropTableId
);
}
if
(
next
!=
null
)
{
next
.
executeDrop
();
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/command/dml/ScriptBase.java
浏览文件 @
40de3268
...
...
@@ -11,6 +11,7 @@ import java.io.BufferedOutputStream;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.sql.Connection
;
import
org.h2.command.Prepared
;
import
org.h2.constant.ErrorCode
;
import
org.h2.constant.SysProperties
;
...
...
@@ -228,4 +229,8 @@ public abstract class ScriptBase extends Prepared implements DataHandler {
return
null
;
}
public
Connection
getLobConnection
()
{
return
null
;
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/constant/SysProperties.java
浏览文件 @
40de3268
...
...
@@ -66,7 +66,7 @@ public class SysProperties {
public
static
final
String
LINE_SEPARATOR
=
getStringSetting
(
"line.separator"
,
"\n"
);
/**
* System property <code>user.home</code> (
default: empty string
).<br />
* System property <code>user.home</code> (
empty string if not set
).<br />
* It is usually set by the system, and used as a replacement for ~ in file
* names.
*/
...
...
@@ -437,6 +437,12 @@ public class SysProperties {
*/
public
static
final
String
PG_DEFAULT_CLIENT_ENCODING
=
getStringSetting
(
"h2.pgClientEncoding"
,
"UTF-8"
);
/**
* System property <code>h2.prefixTempFile</code> (default: h2.temp).<br />
* The prefix for temporary files in the temp directory.
*/
public
static
final
String
PREFIX_TEMP_FILE
=
getStringSetting
(
"h2.prefixTempFile"
,
"h2.temp"
);
/**
* System property <code>h2.recompileAlways</code> (default: false).<br />
* Always recompile prepared statements.
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/engine/SessionRemote.java
浏览文件 @
40de3268
...
...
@@ -8,6 +8,7 @@ package org.h2.engine;
import
java.io.IOException
;
import
java.net.Socket
;
import
java.sql.Connection
;
import
java.util.ArrayList
;
import
org.h2.api.DatabaseEventListener
;
import
org.h2.command.CommandInterface
;
...
...
@@ -80,6 +81,7 @@ public class SessionRemote extends SessionWithState implements SessionFactory, D
private
int
lastReconnect
;
private
SessionInterface
embedded
;
private
DatabaseEventListener
eventListener
;
private
LobStorage
lobStorage
;
public
SessionRemote
()
{
// nothing to do
...
...
@@ -620,6 +622,13 @@ public class SessionRemote extends SessionWithState implements SessionFactory, D
}
public
LobStorage
getLobStorage
()
{
if
(
lobStorage
==
null
)
{
lobStorage
=
new
LobStorage
(
this
);
}
return
lobStorage
;
}
public
Connection
getLobConnection
()
{
return
null
;
}
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/jdbc/JdbcConnection.java
浏览文件 @
40de3268
...
...
@@ -6,7 +6,9 @@
*/
package
org
.
h2
.
jdbc
;
import
java.io.ByteArrayInputStream
;
import
java.io.InputStream
;
import
java.io.InputStreamReader
;
import
java.io.Reader
;
import
java.sql.Blob
;
import
java.sql.CallableStatement
;
...
...
@@ -32,7 +34,6 @@ import org.h2.message.DbException;
import
org.h2.message.Trace
;
import
org.h2.message.TraceObject
;
import
org.h2.result.ResultInterface
;
import
org.h2.store.LobStorage
;
import
org.h2.util.Utils
;
import
org.h2.value.CompareMode
;
import
org.h2.value.Value
;
...
...
@@ -1438,7 +1439,9 @@ public class JdbcConnection extends TraceObject implements Connection {
debugCodeAssign
(
"Clob"
,
TraceObject
.
CLOB
,
id
,
"createClob()"
);
checkClosedForWrite
();
try
{
Value
v
=
LobStorage
.
createSmallLob
(
Value
.
CLOB
,
Utils
.
EMPTY_BYTES
);
Value
v
=
session
.
getDataHandler
().
getLobStorage
().
createClob
(
new
InputStreamReader
(
new
ByteArrayInputStream
(
Utils
.
EMPTY_BYTES
)),
0
);
return
new
JdbcClob
(
this
,
v
,
id
);
}
finally
{
afterWriting
();
...
...
@@ -1459,7 +1462,7 @@ public class JdbcConnection extends TraceObject implements Connection {
debugCodeAssign
(
"Blob"
,
TraceObject
.
BLOB
,
id
,
"createClob()"
);
checkClosedForWrite
();
try
{
Value
v
=
LobStorage
.
createSmallLob
(
Value
.
BLOB
,
Utils
.
EMPTY_BYTES
);
Value
v
=
session
.
getDataHandler
().
getLobStorage
().
createBlob
(
new
ByteArrayInputStream
(
Utils
.
EMPTY_BYTES
),
0
);
return
new
JdbcBlob
(
this
,
v
,
id
);
}
finally
{
afterWriting
();
...
...
@@ -1480,8 +1483,14 @@ public class JdbcConnection extends TraceObject implements Connection {
int id = getNextId(TraceObject.CLOB);
debugCodeAssign("NClob", TraceObject.CLOB, id, "createNClob()");
checkClosedForWrite();
Value v = LobStorage.createSmallLob(Value.CLOB, Utils.EMPTY_BYTES);
try {
Value v = session.getDataHandler().getLobStorage().createClob(
new InputStreamReader(
new ByteArrayInputStream(Utils.EMPTY_BYTES)), 0);
return new JdbcClob(this, v, id);
} finally {
afterWriting();
}
} catch (Exception e) {
throw logAndConvert(e);
}
...
...
@@ -1614,7 +1623,7 @@ public class JdbcConnection extends TraceObject implements Connection {
if
(
length
<=
0
)
{
length
=
-
1
;
}
Value
v
=
LobStorage
.
createClob
(
x
,
length
,
session
.
getDataHandler
()
);
Value
v
=
session
.
getDataHandler
().
getLobStorage
().
createClob
(
x
,
length
);
return
v
;
}
...
...
@@ -1633,7 +1642,7 @@ public class JdbcConnection extends TraceObject implements Connection {
if
(
length
<=
0
)
{
length
=
-
1
;
}
Value
v
=
LobStorage
.
createBlob
(
x
,
length
,
session
.
getDataHandler
()
);
Value
v
=
session
.
getDataHandler
().
getLobStorage
().
createBlob
(
x
,
length
);
return
v
;
}
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/Data.java
浏览文件 @
40de3268
...
...
@@ -32,6 +32,7 @@ import org.h2.value.ValueFloat;
import
org.h2.value.ValueInt
;
import
org.h2.value.ValueJavaObject
;
import
org.h2.value.ValueLob
;
import
org.h2.value.ValueLob2
;
import
org.h2.value.ValueLong
;
import
org.h2.value.ValueNull
;
import
org.h2.value.ValueShort
;
...
...
@@ -514,6 +515,7 @@ public class Data {
case
Value
.
BLOB
:
case
Value
.
CLOB
:
{
writeByte
((
byte
)
type
);
if
(
v
instanceof
ValueLob
)
{
ValueLob
lob
=
(
ValueLob
)
v
;
lob
.
convertToFileIfRequired
(
handler
);
byte
[]
small
=
lob
.
getSmall
();
...
...
@@ -534,6 +536,18 @@ public class Data {
writeVarInt
(
small
.
length
);
write
(
small
,
0
,
small
.
length
);
}
}
else
{
ValueLob2
lob
=
(
ValueLob2
)
v
;
byte
[]
small
=
lob
.
getSmall
();
if
(
small
==
null
)
{
writeVarInt
(-
3
);
writeVarLong
(
lob
.
getLobId
());
writeVarLong
(
lob
.
getPrecision
());
}
else
{
writeVarInt
(
small
.
length
);
write
(
small
,
0
,
small
.
length
);
}
}
break
;
}
case
Value
.
ARRAY
:
{
...
...
@@ -654,12 +668,17 @@ public class Data {
byte
[]
small
=
Utils
.
newBytes
(
smallLen
);
read
(
small
,
0
,
smallLen
);
return
LobStorage
.
createSmallLob
(
type
,
small
);
}
}
else
if
(
smallLen
==
-
3
)
{
long
lobId
=
readVarLong
();
long
precision
=
readVarLong
();
LobStorage
lobStorage
=
handler
.
getLobStorage
();
ValueLob2
lob
=
ValueLob2
.
create
(
type
,
lobStorage
,
null
,
lobId
,
precision
);
return
lob
;
}
else
{
int
tableId
=
readVarInt
();
int
objectId
=
readVarInt
();
long
precision
=
0
;
boolean
compression
=
false
;
// TODO simplify
// -1: regular
// -2: regular, but not linked (in this case: including file name)
if
(
smallLen
==
-
1
||
smallLen
==
-
2
)
{
...
...
@@ -672,6 +691,7 @@ public class Data {
}
return
lob
;
}
}
case
Value
.
ARRAY
:
{
int
len
=
readVarInt
();
Value
[]
list
=
new
Value
[
len
];
...
...
@@ -809,6 +829,7 @@ public class Data {
case
Value
.
BLOB
:
case
Value
.
CLOB
:
{
int
len
=
1
;
if
(
v
instanceof
ValueLob
)
{
ValueLob
lob
=
(
ValueLob
)
v
;
lob
.
convertToFileIfRequired
(
handler
);
byte
[]
small
=
lob
.
getSmall
();
...
...
@@ -829,6 +850,18 @@ public class Data {
len
+=
getVarIntLen
(
small
.
length
);
len
+=
small
.
length
;
}
}
else
{
ValueLob2
lob
=
(
ValueLob2
)
v
;
byte
[]
small
=
lob
.
getSmall
();
if
(
small
==
null
)
{
len
+=
getVarIntLen
(-
3
);
len
+=
getVarLongLen
(
lob
.
getLobId
());
len
+=
getVarLongLen
(
lob
.
getPrecision
());
}
else
{
len
+=
getVarIntLen
(
small
.
length
);
len
+=
small
.
length
;
}
}
return
len
;
}
case
Value
.
ARRAY
:
{
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/DataHandler.java
浏览文件 @
40de3268
...
...
@@ -6,6 +6,7 @@
*/
package
org
.
h2
.
store
;
import
java.sql.Connection
;
import
org.h2.util.SmallLRUCache
;
import
org.h2.util.TempFileDeleter
;
...
...
@@ -91,6 +92,18 @@ public interface DataHandler {
*/
SmallLRUCache
<
String
,
String
[]>
getLobFileListCache
();
/**
* Get the lob storage mechanism to use.
*
* @return the lob storage mechanism
*/
LobStorage
getLobStorage
();
/**
* Get a database connection to be used for LOB access.
*
* @return the connection or null
*/
Connection
getLobConnection
();
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/LobStorage.java
浏览文件 @
40de3268
...
...
@@ -22,16 +22,17 @@ import org.h2.engine.Constants;
import
org.h2.message.DbException
;
import
org.h2.util.IOUtils
;
import
org.h2.util.New
;
import
org.h2.util.StringUtils
;
import
org.h2.util.Utils
;
import
org.h2.value.Value
;
import
org.h2.value.ValueLob
;
import
org.h2.value.ValueLob2
;
/**
* This class stores LOB objects in the database.
*/
public
class
LobStorage
{
/**
* The 'table id' to use for session variables.
*/
public
static
final
int
TABLE_ID_SESSION_VARIABLE
=
-
1
;
private
static
final
String
LOBS
=
"INFORMATION_SCHEMA.LOBS"
;
...
...
@@ -46,15 +47,33 @@ public class LobStorage {
private
long
nextLob
;
private
long
nextBlock
;
public
LobStorage
(
Connection
newConn
)
{
private
final
DataHandler
handler
;
private
boolean
init
;
public
LobStorage
(
DataHandler
handler
)
{
this
.
handler
=
handler
;
}
/**
* Initialize the lob storage.
*/
public
void
init
()
{
if
(
init
)
{
return
;
}
conn
=
handler
.
getLobConnection
();
init
=
true
;
if
(
conn
==
null
)
{
return
;
}
int
todoDatabaseGetFirstUserTable
;
try
{
this
.
conn
=
newConn
;
Statement
stat
=
conn
.
createStatement
();
// stat.execute("SET UNDO_LOG 0");
// stat.execute("SET REDO_LOG_BINARY 0");
stat
.
execute
(
"CREATE TABLE IF NOT EXISTS "
+
LOBS
+
"(ID BIGINT PRIMARY KEY, LENGTH BIGINT, TABLE INT)"
);
stat
.
execute
(
"CREATE TABLE IF NOT EXISTS "
+
LOB_MAP
+
"(LOB BIGINT, SEQ INT, BLOCK BIGINT, PRIMARY KEY(LOB, SEQ))"
);
stat
.
execute
(
"CREATE INDEX INFORMATION_SCHEMA.INDEX_LOB_MAP_DATA_LOB ON "
+
LOB_MAP
+
"(BLOCK, LOB)"
);
stat
.
execute
(
"CREATE INDEX I
F NOT EXISTS I
NFORMATION_SCHEMA.INDEX_LOB_MAP_DATA_LOB ON "
+
LOB_MAP
+
"(BLOCK, LOB)"
);
stat
.
execute
(
"CREATE TABLE IF NOT EXISTS "
+
LOB_DATA
+
"(BLOCK BIGINT PRIMARY KEY, DATA BINARY)"
);
ResultSet
rs
;
rs
=
stat
.
executeQuery
(
"SELECT MAX(BLOCK) FROM "
+
LOB_DATA
);
...
...
@@ -77,8 +96,10 @@ public class LobStorage {
* @param handler the data handler
* @param tableId the table id
*/
public
static
void
removeAllForTable
(
DataHandler
handler
,
int
tableId
)
{
public
void
removeAllForTable
(
int
tableId
)
{
if
(
SysProperties
.
LOB_IN_DATABASE
)
{
init
();
int
todo
;
// remove both lobs in the database as well as in the file system
}
ValueLob
.
removeAllForTable
(
handler
,
tableId
);
...
...
@@ -91,50 +112,19 @@ public class LobStorage {
* @param small the byte array
* @return the LOB
*/
public
static
Value
Lob
createSmallLob
(
int
type
,
byte
[]
small
)
{
public
static
Value
createSmallLob
(
int
type
,
byte
[]
small
)
{
if
(
SysProperties
.
LOB_IN_DATABASE
)
{
return
null
;
return
ValueLob2
.
createSmallLob
(
type
,
small
)
;
}
return
ValueLob
.
createSmallLob
(
type
,
small
);
}
/**
* Create a BLOB object.
*
* @param in the input stream
* @param maxLength the maximum length (-1 if not known)
* @param handler the data handler
* @return the LOB
*/
public
static
ValueLob
createBlob
(
InputStream
in
,
long
maxLength
,
DataHandler
handler
)
{
if
(
SysProperties
.
LOB_IN_DATABASE
)
{
handler
.
getLobStorage
().
addLob
(
in
,
maxLength
,
LobStorage
.
TABLE_ID_SESSION_VARIABLE
);
}
return
ValueLob
.
createBlob
(
in
,
maxLength
,
handler
);
}
/**
* Create a CLOB object.
*
* @param reader the reader
* @param maxLength the maximum length (-1 if not known)
* @param handler the data handler
* @return the LOB
*/
public
static
ValueLob
createClob
(
Reader
reader
,
long
maxLength
,
DataHandler
handler
)
{
if
(
SysProperties
.
LOB_IN_DATABASE
)
{
CountingReaderInputStream
in
=
new
CountingReaderInputStream
(
reader
);
handler
.
getLobStorage
().
addLob
(
in
,
maxLength
,
LobStorage
.
TABLE_ID_SESSION_VARIABLE
);
}
return
ValueLob
.
createClob
(
reader
,
maxLength
,
handler
);
}
/**
* An input stream that reads from a LOB.
*/
public
static
class
LobInputStream
extends
InputStream
{
private
Connection
conn
;
private
final
Connection
conn
;
private
PreparedStatement
prepSelect
;
private
byte
[]
buffer
;
private
int
pos
;
...
...
@@ -143,6 +133,7 @@ public class LobStorage {
private
int
seq
;
public
LobInputStream
(
Connection
conn
,
long
lob
)
throws
IOException
{
this
.
conn
=
conn
;
try
{
this
.
lob
=
lob
;
PreparedStatement
prep
=
conn
.
prepareStatement
(
...
...
@@ -151,8 +142,9 @@ public class LobStorage {
ResultSet
rs
=
prep
.
executeQuery
();
if
(!
rs
.
next
())
{
throw
DbException
.
get
(
ErrorCode
.
IO_EXCEPTION_1
,
"lob: "
+
lob
+
" seq: "
+
seq
).
getSQLException
();
}
remaining
=
rs
.
getLong
(
1
);
rs
.
close
();
}
catch
(
SQLException
e
)
{
throw
DbException
.
convertToIOException
(
e
);
}
...
...
@@ -257,21 +249,18 @@ public class LobStorage {
prep
.
execute
();
}
/**
* Store the LOB in the database.
*
* @param in the input stream
* @param maxLength the maximum length (-1 for unknown)
* @param table the table
* @return the LOB id
*/
public
long
addLob
(
InputStream
in
,
long
maxLength
,
int
table
)
{
public
InputStream
getInputStream
(
long
lobId
)
throws
IOException
{
init
();
return
new
LobInputStream
(
conn
,
lobId
);
}
private
ValueLob2
addLob
(
InputStream
in
,
long
maxLength
,
int
type
)
{
byte
[]
buff
=
new
byte
[
BLOCK_LENGTH
];
if
(
maxLength
<
0
)
{
maxLength
=
Long
.
MAX_VALUE
;
}
long
length
=
0
;
long
lob
=
nextLob
++;
long
lob
Id
=
nextLob
++;
try
{
try
{
for
(
int
seq
=
0
;
maxLength
>
0
;
seq
++)
{
...
...
@@ -281,7 +270,6 @@ public class LobStorage {
}
length
+=
len
;
maxLength
-=
len
;
byte
[]
b
;
if
(
len
!=
buff
.
length
)
{
b
=
new
byte
[
len
];
...
...
@@ -319,20 +307,21 @@ public class LobStorage {
}
PreparedStatement
prep
=
prepare
(
"INSERT INTO "
+
LOB_MAP
+
"(LOB, SEQ, BLOCK) VALUES(?, ?, ?)"
);
prep
.
setLong
(
1
,
lob
);
prep
.
setLong
(
1
,
lob
Id
);
prep
.
setInt
(
2
,
seq
);
prep
.
setLong
(
3
,
block
);
prep
.
execute
();
}
PreparedStatement
prep
=
prepare
(
"INSERT INTO "
+
LOBS
+
"(ID, LENGTH, TABLE) VALUES(?, ?, ?)"
);
prep
.
setLong
(
1
,
lob
);
prep
.
setLong
(
1
,
lob
Id
);
prep
.
setLong
(
2
,
length
);
prep
.
setInt
(
3
,
table
);
prep
.
setInt
(
3
,
TABLE_ID_SESSION_VARIABLE
);
prep
.
execute
();
return
lob
;
ValueLob2
v
=
ValueLob2
.
create
(
type
,
this
,
null
,
lobId
,
length
);
return
v
;
}
catch
(
IOException
e
)
{
deleteLob
(
lob
);
deleteLob
(
lob
Id
);
throw
DbException
.
convertIOException
(
e
,
"adding blob"
);
}
}
catch
(
SQLException
e
)
{
...
...
@@ -347,16 +336,87 @@ public class LobStorage {
private
final
Reader
reader
;
private
long
length
;
private
char
[]
buffer
=
new
char
[
Constants
.
IO_BUFFER_SIZE
];
private
int
pos
;
private
char
[]
charBuffer
=
new
char
[
Constants
.
IO_BUFFER_SIZE
];
private
byte
[]
buffer
;
CountingReaderInputStream
(
Reader
reader
)
{
this
.
reader
=
reader
;
buffer
=
Utils
.
EMPTY_BYTES
;
}
public
int
read
(
byte
[]
buff
,
int
offset
,
int
len
)
throws
IOException
{
if
(
pos
>=
buffer
.
length
)
{
fillBuffer
();
if
(
buffer
==
null
)
{
return
-
1
;
}
}
len
=
Math
.
min
(
len
,
buffer
.
length
-
pos
);
System
.
arraycopy
(
buffer
,
pos
,
buff
,
offset
,
len
);
return
len
;
}
public
int
read
()
throws
IOException
{
return
0
;
if
(
pos
>=
buffer
.
length
)
{
fillBuffer
();
if
(
buffer
==
null
)
{
return
-
1
;
}
}
return
buffer
[
pos
++];
}
private
void
fillBuffer
()
throws
IOException
{
int
len
=
reader
.
read
(
charBuffer
);
if
(
len
<
0
)
{
buffer
=
null
;
}
else
{
buffer
=
StringUtils
.
utf8Encode
(
new
String
(
charBuffer
,
0
,
len
));
length
+=
len
;
}
}
public
long
getLength
()
{
return
length
;
}
public
void
close
()
throws
IOException
{
reader
.
close
();
}
}
/**
* Create a BLOB object.
*
* @param in the input stream
* @param maxLength the maximum length (-1 if not known)
* @return the LOB
*/
public
Value
createBlob
(
InputStream
in
,
long
maxLength
)
{
if
(
SysProperties
.
LOB_IN_DATABASE
)
{
init
();
if
(
conn
==
null
)
{
return
ValueLob2
.
createTempBlob
(
in
,
maxLength
,
handler
);
}
return
addLob
(
in
,
maxLength
,
Value
.
BLOB
);
}
return
ValueLob
.
createBlob
(
in
,
maxLength
,
handler
);
}
public
Value
createClob
(
Reader
reader
,
long
maxLength
)
{
if
(
SysProperties
.
LOB_IN_DATABASE
)
{
init
();
if
(
conn
==
null
)
{
return
ValueLob2
.
createTempClob
(
reader
,
maxLength
,
handler
);
}
CountingReaderInputStream
in
=
new
CountingReaderInputStream
(
reader
);
ValueLob2
lob
=
addLob
(
in
,
maxLength
,
Value
.
BLOB
);
lob
.
setPrecision
(
in
.
getLength
());
return
lob
;
}
return
ValueLob
.
createClob
(
reader
,
maxLength
,
handler
);
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/tools/Recover.java
浏览文件 @
40de3268
...
...
@@ -1223,4 +1223,11 @@ public class Recover extends Tool implements DataHandler {
return
null
;
}
/**
* INTERNAL
*/
public
Connection
getLobConnection
()
{
return
null
;
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/value/DataType.java
浏览文件 @
40de3268
...
...
@@ -546,7 +546,7 @@ public class DataType {
if
(
in
==
null
)
{
v
=
ValueNull
.
INSTANCE
;
}
else
{
v
=
LobStorage
.
createClob
(
new
BufferedReader
(
in
),
-
1
,
session
.
getDataHandler
()
);
v
=
session
.
getDataHandler
().
getLobStorage
().
createClob
(
new
BufferedReader
(
in
),
-
1
);
}
}
break
;
...
...
@@ -556,7 +556,7 @@ public class DataType {
v
=
LobStorage
.
createSmallLob
(
Value
.
BLOB
,
rs
.
getBytes
(
columnIndex
));
}
else
{
InputStream
in
=
rs
.
getBinaryStream
(
columnIndex
);
v
=
(
in
==
null
)
?
(
Value
)
ValueNull
.
INSTANCE
:
LobStorage
.
createBlob
(
in
,
-
1
,
session
.
getDataHandler
()
);
v
=
(
in
==
null
)
?
(
Value
)
ValueNull
.
INSTANCE
:
session
.
getDataHandler
().
getLobStorage
().
createBlob
(
in
,
-
1
);
}
break
;
}
...
...
@@ -864,19 +864,19 @@ public class DataType {
return
ValueTimestamp
.
get
(
new
Timestamp
(((
java
.
util
.
Date
)
x
).
getTime
()));
}
else
if
(
x
instanceof
java
.
io
.
Reader
)
{
Reader
r
=
new
BufferedReader
((
java
.
io
.
Reader
)
x
);
return
LobStorage
.
createClob
(
r
,
-
1
,
session
.
getDataHandler
()
);
return
session
.
getDataHandler
().
getLobStorage
().
createClob
(
r
,
-
1
);
}
else
if
(
x
instanceof
java
.
sql
.
Clob
)
{
try
{
Reader
r
=
new
BufferedReader
(((
java
.
sql
.
Clob
)
x
).
getCharacterStream
());
return
LobStorage
.
createClob
(
r
,
-
1
,
session
.
getDataHandler
()
);
return
session
.
getDataHandler
().
getLobStorage
().
createClob
(
r
,
-
1
);
}
catch
(
SQLException
e
)
{
throw
DbException
.
convert
(
e
);
}
}
else
if
(
x
instanceof
java
.
io
.
InputStream
)
{
return
LobStorage
.
createBlob
((
java
.
io
.
InputStream
)
x
,
-
1
,
session
.
getDataHandler
()
);
return
session
.
getDataHandler
().
getLobStorage
().
createBlob
((
java
.
io
.
InputStream
)
x
,
-
1
);
}
else
if
(
x
instanceof
java
.
sql
.
Blob
)
{
try
{
return
LobStorage
.
createBlob
(((
java
.
sql
.
Blob
)
x
).
getBinaryStream
(),
-
1
,
session
.
getDataHandler
()
);
return
session
.
getDataHandler
().
getLobStorage
().
createBlob
(((
java
.
sql
.
Blob
)
x
).
getBinaryStream
(),
-
1
);
}
catch
(
SQLException
e
)
{
throw
DbException
.
convert
(
e
);
}
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/value/Transfer.java
浏览文件 @
40de3268
...
...
@@ -29,13 +29,12 @@ import org.h2.engine.Constants;
import
org.h2.engine.SessionInterface
;
import
org.h2.message.DbException
;
import
org.h2.message.TraceSystem
;
import
org.h2.store.LobStorage
;
import
org.h2.tools.SimpleResultSet
;
import
org.h2.util.Utils
;
import
org.h2.util.ExactUTF8InputStreamReader
;
import
org.h2.util.IOUtils
;
import
org.h2.util.NetUtils
;
import
org.h2.util.StringUtils
;
import
org.h2.util.Utils
;
/**
* The transfer class is used to send and receive Value objects.
...
...
@@ -484,7 +483,7 @@ public class Transfer {
return
ValueStringFixed
.
get
(
readString
());
case
Value
.
BLOB
:
{
long
length
=
readLong
();
Value
v
=
LobStorage
.
createBlob
(
in
,
length
,
session
.
getDataHandler
()
);
Value
v
=
session
.
getDataHandler
().
getLobStorage
().
createBlob
(
in
,
length
);
int
magic
=
readInt
();
if
(
magic
!=
LOB_MAGIC
)
{
throw
DbException
.
get
(
ErrorCode
.
CONNECTION_BROKEN_1
,
"magic="
+
magic
);
...
...
@@ -493,7 +492,7 @@ public class Transfer {
}
case
Value
.
CLOB
:
{
long
length
=
readLong
();
Value
v
=
LobStorage
.
createClob
(
new
ExactUTF8InputStreamReader
(
in
),
length
,
session
.
getDataHandler
()
);
Value
v
=
session
.
getDataHandler
().
getLobStorage
().
createClob
(
new
ExactUTF8InputStreamReader
(
in
),
length
);
int
magic
=
readInt
();
if
(
magic
!=
LOB_MAGIC
)
{
throw
DbException
.
get
(
ErrorCode
.
CONNECTION_BROKEN_1
,
"magic="
+
magic
);
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/value/Value.java
浏览文件 @
40de3268
...
...
@@ -706,6 +706,7 @@ public abstract class Value {
case
BLOB:
{
switch
(
getType
())
{
case
BYTES:
return
LobStorage
.
createSmallLob
(
Value
.
BLOB
,
getBytesNoCopy
());
}
break
;
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/value/ValueLob.java
浏览文件 @
40de3268
...
...
@@ -44,9 +44,6 @@ import org.h2.util.Utils;
* Data compression is supported.
*/
public
class
ValueLob
extends
Value
{
// TODO lob: concatenate function for blob and clob
// (to create a large blob from pieces)
// and a getpart function (to get it in pieces) and make sure a file is created!
/**
* This counter is used to calculate the next directory to store lobs. It is
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/value/ValueLob2.java
浏览文件 @
40de3268
...
...
@@ -20,7 +20,7 @@ import org.h2.store.DataHandler;
import
org.h2.store.FileStore
;
import
org.h2.store.FileStoreInputStream
;
import
org.h2.store.FileStoreOutputStream
;
import
org.h2.store.
fs.FileSystem
;
import
org.h2.store.
LobStorage
;
import
org.h2.util.IOUtils
;
import
org.h2.util.MathUtils
;
import
org.h2.util.StringUtils
;
...
...
@@ -31,33 +31,27 @@ import org.h2.util.Utils;
*/
public
class
ValueLob2
extends
Value
{
/**
* The 'table id' to use for session variables.
*/
public
static
final
int
TABLE_ID_SESSION_VARIABLE
=
-
1
;
private
final
int
type
;
private
long
precision
;
private
DataHandler
handler
;
private
int
tableId
;
private
int
hash
;
private
LobStorage
lobStorage
;
private
long
lobId
;
private
String
fileName
;
private
boolean
linked
;
private
byte
[]
small
;
private
int
hash
;
private
boolean
compression
;
private
DataHandler
handler
;
private
FileStore
tempFile
;
private
String
fileName
;
private
ValueLob2
(
int
type
,
DataHandler
handler
,
String
fileName
,
int
tableId
,
long
lobId
,
boolean
linked
,
long
precision
,
boolean
compression
)
{
private
ValueLob2
(
int
type
,
LobStorage
lobStorage
,
String
fileName
,
int
tableId
,
long
lobId
,
long
precision
)
{
this
.
type
=
type
;
this
.
handler
=
handler
;
this
.
lobStorage
=
lobStorage
;
this
.
fileName
=
fileName
;
this
.
tableId
=
tableId
;
this
.
lobId
=
lobId
;
this
.
linked
=
linked
;
this
.
precision
=
precision
;
this
.
compression
=
compression
;
}
private
ValueLob2
(
int
type
,
byte
[]
small
)
{
...
...
@@ -72,11 +66,8 @@ public class ValueLob2 extends Value {
}
}
private
static
ValueLob2
copy
(
ValueLob2
lob
)
{
ValueLob2
copy
=
new
ValueLob2
(
lob
.
type
,
lob
.
handler
,
lob
.
fileName
,
lob
.
tableId
,
lob
.
lobId
,
lob
.
linked
,
lob
.
precision
,
lob
.
compression
);
copy
.
small
=
lob
.
small
;
copy
.
hash
=
lob
.
hash
;
return
copy
;
public
static
ValueLob2
create
(
int
type
,
LobStorage
lobStorage
,
String
fileName
,
long
id
,
long
precision
)
{
return
new
ValueLob2
(
type
,
lobStorage
,
fileName
,
LobStorage
.
TABLE_ID_SESSION_VARIABLE
,
id
,
precision
);
}
/**
...
...
@@ -90,204 +81,6 @@ public class ValueLob2 extends Value {
return
new
ValueLob2
(
type
,
small
);
}
private
static
String
getFileName
(
DataHandler
handler
,
int
tableId
,
long
objectId
)
{
if
(
SysProperties
.
CHECK
&&
tableId
==
0
&&
objectId
==
0
)
{
DbException
.
throwInternalError
(
"0 LOB"
);
}
String
table
=
tableId
<
0
?
".temp"
:
".t"
+
tableId
;
return
getFileNamePrefix
(
handler
.
getDatabasePath
(),
objectId
)
+
table
+
Constants
.
SUFFIX_LOB_FILE
;
}
/**
* Create a LOB value with the given parameters.
*
* @param type the data type
* @param handler the file handler
* @param tableId the table object id
* @param objectId the object id
* @param precision the precision (length in elements)
* @param compression if compression is used
* @return the value object
*/
public
static
ValueLob2
open
(
int
type
,
DataHandler
handler
,
int
tableId
,
int
objectId
,
long
precision
,
boolean
compression
)
{
String
fileName
=
getFileName
(
handler
,
tableId
,
objectId
);
return
new
ValueLob2
(
type
,
handler
,
fileName
,
tableId
,
objectId
,
true
,
precision
,
compression
);
}
/**
* Create a CLOB value from a stream.
*
* @param in the reader
* @param length the number of characters to read, or -1 for no limit
* @param handler the data handler
* @return the lob value
*/
public
static
ValueLob2
createClob
(
Reader
in
,
long
length
,
DataHandler
handler
)
{
try
{
boolean
compress
=
handler
.
getLobCompressionAlgorithm
(
Value
.
CLOB
)
!=
null
;
long
remaining
=
Long
.
MAX_VALUE
;
if
(
length
>=
0
&&
length
<
remaining
)
{
remaining
=
length
;
}
int
len
=
getBufferSize
(
handler
,
compress
,
remaining
);
char
[]
buff
;
if
(
len
>=
Integer
.
MAX_VALUE
)
{
String
data
=
IOUtils
.
readStringAndClose
(
in
,
-
1
);
buff
=
data
.
toCharArray
();
len
=
buff
.
length
;
}
else
{
buff
=
new
char
[
len
];
len
=
IOUtils
.
readFully
(
in
,
buff
,
len
);
len
=
len
<
0
?
0
:
len
;
}
if
(
len
<=
handler
.
getMaxLengthInplaceLob
())
{
byte
[]
small
=
StringUtils
.
utf8Encode
(
new
String
(
buff
,
0
,
len
));
return
ValueLob2
.
createSmallLob
(
Value
.
CLOB
,
small
);
}
ValueLob2
lob
=
new
ValueLob2
(
Value
.
CLOB
,
null
);
lob
.
createFromReader
(
buff
,
len
,
in
,
remaining
,
handler
);
return
lob
;
}
catch
(
IOException
e
)
{
throw
DbException
.
convertIOException
(
e
,
null
);
}
}
private
static
int
getBufferSize
(
DataHandler
handler
,
boolean
compress
,
long
remaining
)
{
if
(
remaining
<
0
||
remaining
>
Integer
.
MAX_VALUE
)
{
remaining
=
Integer
.
MAX_VALUE
;
}
long
inplace
=
handler
.
getMaxLengthInplaceLob
();
if
(
inplace
>=
Integer
.
MAX_VALUE
)
{
inplace
=
remaining
;
}
long
m
=
compress
?
Constants
.
IO_BUFFER_SIZE_COMPRESS
:
Constants
.
IO_BUFFER_SIZE
;
if
(
m
<
remaining
&&
m
<=
inplace
)
{
m
=
Math
.
min
(
remaining
,
inplace
+
1
);
// the buffer size must be bigger than the inplace lob, otherwise we can't
// know if it must be stored in-place or not
m
=
MathUtils
.
roundUpLong
(
m
,
Constants
.
IO_BUFFER_SIZE
);
}
m
=
Math
.
min
(
remaining
,
m
);
m
=
MathUtils
.
convertLongToInt
(
m
);
if
(
m
<
0
)
{
m
=
Integer
.
MAX_VALUE
;
}
return
(
int
)
m
;
}
private
void
createFromReader
(
char
[]
buff
,
int
len
,
Reader
in
,
long
remaining
,
DataHandler
h
)
{
try
{
FileStoreOutputStream
out
=
initLarge
(
h
);
boolean
compress
=
h
.
getLobCompressionAlgorithm
(
Value
.
CLOB
)
!=
null
;
try
{
while
(
true
)
{
precision
+=
len
;
byte
[]
b
=
StringUtils
.
utf8Encode
(
new
String
(
buff
,
0
,
len
));
out
.
write
(
b
,
0
,
b
.
length
);
remaining
-=
len
;
if
(
remaining
<=
0
)
{
break
;
}
len
=
getBufferSize
(
h
,
compress
,
remaining
);
len
=
IOUtils
.
readFully
(
in
,
buff
,
len
);
if
(
len
<=
0
)
{
break
;
}
}
}
finally
{
out
.
close
();
}
}
catch
(
IOException
e
)
{
throw
DbException
.
convertIOException
(
e
,
null
);
}
}
private
static
String
getFileNamePrefix
(
String
path
,
long
lobId
)
{
return
IOUtils
.
normalize
(
path
+
lobId
);
}
/**
* Create a BLOB value from a stream.
*
* @param in the input stream
* @param length the number of characters to read, or -1 for no limit
* @param handler the data handler
* @return the lob value
*/
public
static
ValueLob2
createBlob
(
InputStream
in
,
long
length
,
DataHandler
handler
)
{
try
{
long
remaining
=
Long
.
MAX_VALUE
;
boolean
compress
=
handler
.
getLobCompressionAlgorithm
(
Value
.
BLOB
)
!=
null
;
if
(
length
>=
0
&&
length
<
remaining
)
{
remaining
=
length
;
}
int
len
=
getBufferSize
(
handler
,
compress
,
remaining
);
byte
[]
buff
;
if
(
len
>=
Integer
.
MAX_VALUE
)
{
buff
=
IOUtils
.
readBytesAndClose
(
in
,
-
1
);
len
=
buff
.
length
;
}
else
{
buff
=
Utils
.
newBytes
(
len
);
len
=
IOUtils
.
readFully
(
in
,
buff
,
0
,
len
);
}
if
(
len
<=
handler
.
getMaxLengthInplaceLob
())
{
byte
[]
small
=
Utils
.
newBytes
(
len
);
System
.
arraycopy
(
buff
,
0
,
small
,
0
,
len
);
return
ValueLob2
.
createSmallLob
(
Value
.
BLOB
,
small
);
}
ValueLob2
lob
=
new
ValueLob2
(
Value
.
BLOB
,
null
);
lob
.
createFromStream
(
buff
,
len
,
in
,
remaining
,
handler
);
return
lob
;
}
catch
(
IOException
e
)
{
throw
DbException
.
convertIOException
(
e
,
null
);
}
}
private
FileStoreOutputStream
initLarge
(
DataHandler
h
)
{
this
.
handler
=
h
;
this
.
tableId
=
0
;
this
.
linked
=
false
;
this
.
precision
=
0
;
this
.
small
=
null
;
this
.
hash
=
0
;
String
compressionAlgorithm
=
h
.
getLobCompressionAlgorithm
(
type
);
this
.
compression
=
compressionAlgorithm
!=
null
;
synchronized
(
h
)
{
lobId
=
getNewObjectId
(
h
);
fileName
=
getFileNamePrefix
(
h
.
getDatabasePath
(),
lobId
)
+
Constants
.
SUFFIX_TEMP_FILE
;
tempFile
=
h
.
openFile
(
fileName
,
"rw"
,
false
);
tempFile
.
autoDelete
();
}
FileStoreOutputStream
out
=
new
FileStoreOutputStream
(
tempFile
,
h
,
compressionAlgorithm
);
return
out
;
}
private
void
createFromStream
(
byte
[]
buff
,
int
len
,
InputStream
in
,
long
remaining
,
DataHandler
h
)
{
try
{
FileStoreOutputStream
out
=
initLarge
(
h
);
boolean
compress
=
h
.
getLobCompressionAlgorithm
(
Value
.
BLOB
)
!=
null
;
try
{
while
(
true
)
{
precision
+=
len
;
out
.
write
(
buff
,
0
,
len
);
remaining
-=
len
;
if
(
remaining
<=
0
)
{
break
;
}
len
=
getBufferSize
(
h
,
compress
,
remaining
);
len
=
IOUtils
.
readFully
(
in
,
buff
,
0
,
len
);
if
(
len
<=
0
)
{
break
;
}
}
}
finally
{
out
.
close
();
}
}
catch
(
IOException
e
)
{
throw
DbException
.
convertIOException
(
e
,
null
);
}
}
/**
* Convert a lob to another data type. The data is fully read in memory
* except when converting to BLOB or CLOB.
...
...
@@ -299,26 +92,17 @@ public class ValueLob2 extends Value {
if
(
t
==
type
)
{
return
this
;
}
else
if
(
t
==
Value
.
CLOB
)
{
Value
Lob2
copy
=
ValueLob2
.
createClob
(
getReader
(),
-
1
,
handler
);
Value
copy
=
handler
.
getLobStorage
().
createClob
(
getReader
(),
-
1
);
return
copy
;
}
else
if
(
t
==
Value
.
BLOB
)
{
Value
Lob2
copy
=
ValueLob2
.
createBlob
(
getInputStream
(),
-
1
,
handler
);
Value
copy
=
handler
.
getLobStorage
().
createBlob
(
getInputStream
(),
-
1
);
return
copy
;
}
return
super
.
convertTo
(
t
);
}
public
boolean
isLinked
()
{
return
linked
;
}
/**
* Get the current file name where the lob is saved.
*
* @return the file name or null
*/
public
String
getFileName
()
{
return
fileName
;
return
tableId
!=
LobStorage
.
TABLE_ID_SESSION_VARIABLE
;
}
public
void
close
()
{
...
...
@@ -330,50 +114,19 @@ public class ValueLob2 extends Value {
}
}
public
void
unlink
()
{
if
(
linked
&&
fileName
!=
null
)
{
String
temp
;
// synchronize on the database, to avoid concurrent temp file
// creation / deletion / backup
synchronized
(
handler
)
{
temp
=
getFileName
(
handler
,
-
1
,
lobId
);
deleteFile
(
handler
,
temp
);
renameFile
(
handler
,
fileName
,
temp
);
tempFile
=
FileStore
.
open
(
handler
,
temp
,
"rw"
);
tempFile
.
autoDelete
();
tempFile
.
closeSilently
();
fileName
=
temp
;
linked
=
false
;
private
static
synchronized
void
deleteFile
(
DataHandler
handler
,
String
fileName
)
{
// synchronize on the database, to avoid concurrent temp file creation /
// deletion / backup
synchronized
(
handler
.
getLobSyncObject
())
{
IOUtils
.
delete
(
fileName
);
}
}
public
void
unlink
()
{
}
public
Value
link
(
DataHandler
h
,
int
tabId
)
{
if
(
fileName
==
null
)
{
this
.
tableId
=
tabId
;
return
this
;
}
if
(
linked
)
{
ValueLob2
copy
=
ValueLob2
.
copy
(
this
);
copy
.
lobId
=
getNewObjectId
(
h
);
copy
.
tableId
=
tabId
;
String
live
=
getFileName
(
h
,
copy
.
tableId
,
copy
.
lobId
);
copyFileTo
(
h
,
fileName
,
live
);
copy
.
fileName
=
live
;
copy
.
linked
=
true
;
return
copy
;
}
if
(!
linked
)
{
this
.
tableId
=
tabId
;
String
live
=
getFileName
(
h
,
tableId
,
lobId
);
if
(
tempFile
!=
null
)
{
tempFile
.
stopAutoDelete
();
tempFile
=
null
;
}
renameFile
(
h
,
fileName
,
live
);
fileName
=
live
;
linked
=
true
;
}
int
todo
;
return
this
;
}
...
...
@@ -415,7 +168,7 @@ public class ValueLob2 extends Value {
}
return
Utils
.
convertBytesToString
(
buff
);
}
catch
(
IOException
e
)
{
throw
DbException
.
convertIOException
(
e
,
fileName
);
throw
DbException
.
convertIOException
(
e
,
toString
()
);
}
}
...
...
@@ -439,7 +192,7 @@ public class ValueLob2 extends Value {
try
{
return
IOUtils
.
readBytesAndClose
(
getInputStream
(),
Integer
.
MAX_VALUE
);
}
catch
(
IOException
e
)
{
throw
DbException
.
convertIOException
(
e
,
fileName
);
throw
DbException
.
convertIOException
(
e
,
toString
()
);
}
}
...
...
@@ -479,14 +232,20 @@ public class ValueLob2 extends Value {
}
public
InputStream
getInputStream
()
{
if
(
fileName
=
=
null
)
{
if
(
small
!
=
null
)
{
return
new
ByteArrayInputStream
(
small
);
}
}
else
if
(
fileName
!=
null
)
{
FileStore
store
=
handler
.
openFile
(
fileName
,
"r"
,
true
);
boolean
alwaysClose
=
SysProperties
.
lobCloseBetweenReads
;
return
new
BufferedInputStream
(
new
FileStoreInputStream
(
store
,
handler
,
compression
,
alwaysClose
),
return
new
BufferedInputStream
(
new
FileStoreInputStream
(
store
,
handler
,
false
,
alwaysClose
),
Constants
.
IO_BUFFER_SIZE
);
}
try
{
return
lobStorage
.
getInputStream
(
lobId
);
}
catch
(
IOException
e
)
{
throw
DbException
.
convertIOException
(
e
,
toString
());
}
}
public
void
set
(
PreparedStatement
prep
,
int
parameterIndex
)
throws
SQLException
{
long
p
=
getPrecision
();
...
...
@@ -521,7 +280,7 @@ public class ValueLob2 extends Value {
}
else
{
buff
.
append
(
"CAST(REPEAT('00', "
).
append
(
getPrecision
()).
append
(
") AS BINARY"
);
}
buff
.
append
(
" /*
"
).
append
(
fileName
).
append
(
" */)"
);
buff
.
append
(
" /*
table: "
).
append
(
tableId
).
append
(
" id: "
).
append
(
lobId
).
append
(
" */)"
);
return
buff
.
toString
();
}
...
...
@@ -542,122 +301,206 @@ public class ValueLob2 extends Value {
return
other
instanceof
ValueLob
&&
compareSecure
((
Value
)
other
,
null
)
==
0
;
}
public
boolean
isFileBased
()
{
return
small
==
null
;
}
public
int
getMemory
()
{
if
(
small
!=
null
)
{
return
small
.
length
+
32
;
}
return
128
;
}
/**
*
Store the lob data to a file if the size of the buffer it larger than the
*
maximum size for an in-place lob
.
*
Create an independent copy of this temporary value.
*
The file will not be deleted automatically
.
*
* @
param h the data handler
* @
return the value
*/
public
void
convertToFileIfRequired
(
DataHandler
h
)
{
if
(
small
!=
null
&&
small
.
length
>
h
.
getMaxLengthInplaceLob
())
{
boolean
compress
=
h
.
getLobCompressionAlgorithm
(
type
)
!=
null
;
int
len
=
getBufferSize
(
h
,
compress
,
Long
.
MAX_VALUE
);
int
tabId
=
tableId
;
if
(
type
==
Value
.
BLOB
)
{
createFromStream
(
Utils
.
newBytes
(
len
),
0
,
getInputStream
(),
Long
.
MAX_VALUE
,
h
);
}
else
{
createFromReader
(
new
char
[
len
],
0
,
getReader
(),
Long
.
MAX_VALUE
,
h
);
public
ValueLob2
copyToTemp
()
{
return
this
;
}
Value
v2
=
link
(
h
,
tabId
);
if
(
SysProperties
.
CHECK
&&
v2
!=
this
)
{
DbException
.
throwInternalError
()
;
public
long
getLobId
(
)
{
return
lobId
;
}
public
void
setPrecision
(
long
precision
)
{
this
.
precision
=
precision
;
}
public
String
toString
()
{
return
"lob: "
+
fileName
+
" table: "
+
tableId
+
" id: "
+
lobId
;
}
/**
*
Remove all lobs for a given table id
.
*
Create a temporary CLOB value from a stream
.
*
* @param in the reader
* @param length the number of characters to read, or -1 for no limit
* @param handler the data handler
* @
param tableId the table id
* @
return the lob value
*/
public
static
void
removeAllForTable
(
DataHandler
handler
,
int
tableId
)
{
String
dir
=
getFileNamePrefix
(
handler
.
getDatabasePath
(),
0
);
removeAllForTable
(
handler
,
dir
,
tableId
);
public
static
ValueLob2
createTempClob
(
Reader
in
,
long
length
,
DataHandler
handler
)
{
try
{
boolean
compress
=
handler
.
getLobCompressionAlgorithm
(
Value
.
CLOB
)
!=
null
;
long
remaining
=
Long
.
MAX_VALUE
;
if
(
length
>=
0
&&
length
<
remaining
)
{
remaining
=
length
;
}
private
static
void
removeAllForTable
(
DataHandler
handler
,
String
dir
,
int
tableId
)
{
for
(
String
name
:
IOUtils
.
listFiles
(
dir
))
{
if
(
IOUtils
.
isDirectory
(
name
))
{
removeAllForTable
(
handler
,
name
,
tableId
);
int
len
=
getBufferSize
(
handler
,
compress
,
remaining
);
char
[]
buff
;
if
(
len
>=
Integer
.
MAX_VALUE
)
{
String
data
=
IOUtils
.
readStringAndClose
(
in
,
-
1
);
buff
=
data
.
toCharArray
();
len
=
buff
.
length
;
}
else
{
if
(
name
.
endsWith
(
".t"
+
tableId
+
Constants
.
SUFFIX_LOB_FILE
))
{
deleteFile
(
handler
,
name
);
buff
=
new
char
[
len
];
len
=
IOUtils
.
readFully
(
in
,
buff
,
len
);
len
=
len
<
0
?
0
:
len
;
}
if
(
len
<=
handler
.
getMaxLengthInplaceLob
())
{
byte
[]
small
=
StringUtils
.
utf8Encode
(
new
String
(
buff
,
0
,
len
));
return
ValueLob2
.
createSmallLob
(
Value
.
CLOB
,
small
);
}
ValueLob2
lob
=
new
ValueLob2
(
Value
.
CLOB
,
null
);
lob
.
createTempFromReader
(
buff
,
len
,
in
,
remaining
,
handler
);
return
lob
;
}
catch
(
IOException
e
)
{
throw
DbException
.
convertIOException
(
e
,
null
);
}
}
/**
* C
heck if this lob value is compressed
.
* C
reate a temporary BLOB value from a stream
.
*
* @return true if it is
* @param in the input stream
* @param length the number of characters to read, or -1 for no limit
* @param handler the data handler
* @return the lob value
*/
public
boolean
useCompression
()
{
return
compression
;
public
static
ValueLob2
createTempBlob
(
InputStream
in
,
long
length
,
DataHandler
handler
)
{
try
{
long
remaining
=
Long
.
MAX_VALUE
;
boolean
compress
=
handler
.
getLobCompressionAlgorithm
(
Value
.
BLOB
)
!=
null
;
if
(
length
>=
0
&&
length
<
remaining
)
{
remaining
=
length
;
}
public
boolean
isFileBased
()
{
return
fileName
!=
null
;
int
len
=
getBufferSize
(
handler
,
compress
,
remaining
);
byte
[]
buff
;
if
(
len
>=
Integer
.
MAX_VALUE
)
{
buff
=
IOUtils
.
readBytesAndClose
(
in
,
-
1
);
len
=
buff
.
length
;
}
else
{
buff
=
Utils
.
newBytes
(
len
);
len
=
IOUtils
.
readFully
(
in
,
buff
,
0
,
len
);
}
private
static
synchronized
void
deleteFile
(
DataHandler
handler
,
String
fileName
)
{
// synchronize on the database, to avoid concurrent temp file creation /
// deletion / backup
synchronized
(
handler
.
getLobSyncObject
())
{
IOUtils
.
delete
(
fileName
);
if
(
len
<=
handler
.
getMaxLengthInplaceLob
())
{
byte
[]
small
=
Utils
.
newBytes
(
len
);
System
.
arraycopy
(
buff
,
0
,
small
,
0
,
len
);
return
ValueLob2
.
createSmallLob
(
Value
.
BLOB
,
small
);
}
ValueLob2
lob
=
new
ValueLob2
(
Value
.
BLOB
,
null
);
lob
.
createTempFromStream
(
buff
,
len
,
in
,
remaining
,
handler
);
return
lob
;
}
catch
(
IOException
e
)
{
throw
DbException
.
convertIOException
(
e
,
null
);
}
}
private
static
synchronized
void
renameFile
(
DataHandler
handler
,
String
oldName
,
String
newName
)
{
synchronized
(
handler
.
getLobSyncObject
())
{
IOUtils
.
rename
(
oldName
,
newName
);
private
void
createTempFromReader
(
char
[]
buff
,
int
len
,
Reader
in
,
long
remaining
,
DataHandler
h
)
{
try
{
FileStoreOutputStream
out
=
initTemp
(
h
);
try
{
while
(
true
)
{
precision
+=
len
;
byte
[]
b
=
StringUtils
.
utf8Encode
(
new
String
(
buff
,
0
,
len
));
out
.
write
(
b
,
0
,
b
.
length
);
remaining
-=
len
;
if
(
remaining
<=
0
)
{
break
;
}
len
=
getBufferSize
(
h
,
false
,
remaining
);
len
=
IOUtils
.
readFully
(
in
,
buff
,
len
);
if
(
len
<=
0
)
{
break
;
}
private
void
copyFileTo
(
DataHandler
h
,
String
sourceFileName
,
String
targetFileName
)
{
synchronized
(
h
.
getLobSyncObject
())
{
FileSystem
.
getInstance
(
sourceFileName
).
copy
(
sourceFileName
,
targetFileName
);
}
}
finally
{
out
.
close
();
}
}
catch
(
IOException
e
)
{
throw
DbException
.
convertIOException
(
e
,
null
);
}
/**
* Set the file name of this lob value.
*
* @param fileName the file name
* @param linked if the lob is linked
*/
public
void
setFileName
(
String
fileName
,
boolean
linked
)
{
this
.
fileName
=
fileName
;
this
.
linked
=
linked
;
}
public
int
getMemory
()
{
if
(
small
!=
null
)
{
return
small
.
length
+
32
;
private
void
createTempFromStream
(
byte
[]
buff
,
int
len
,
InputStream
in
,
long
remaining
,
DataHandler
h
)
{
try
{
FileStoreOutputStream
out
=
initTemp
(
h
);
boolean
compress
=
h
.
getLobCompressionAlgorithm
(
Value
.
BLOB
)
!=
null
;
try
{
while
(
true
)
{
precision
+=
len
;
out
.
write
(
buff
,
0
,
len
);
remaining
-=
len
;
if
(
remaining
<=
0
)
{
break
;
}
len
=
getBufferSize
(
h
,
compress
,
remaining
);
len
=
IOUtils
.
readFully
(
in
,
buff
,
0
,
len
);
if
(
len
<=
0
)
{
break
;
}
}
}
finally
{
out
.
close
();
}
}
catch
(
IOException
e
)
{
throw
DbException
.
convertIOException
(
e
,
null
);
}
return
128
;
}
/**
* Create an independent copy of this temporary value.
* The file will not be deleted automatically.
*
* @return the value
*/
public
ValueLob2
copyToTemp
()
{
ValueLob2
lob
;
if
(
type
==
CLOB
)
{
lob
=
ValueLob2
.
createClob
(
getReader
(),
precision
,
handler
);
}
else
{
lob
=
ValueLob2
.
createBlob
(
getInputStream
(),
precision
,
handler
);
private
FileStoreOutputStream
initTemp
(
DataHandler
h
)
{
this
.
precision
=
0
;
this
.
handler
=
h
;
this
.
small
=
null
;
try
{
String
path
=
h
.
getDatabasePath
();
if
(
path
.
length
()
==
0
)
{
path
=
SysProperties
.
PREFIX_TEMP_FILE
;
}
return
lob
;
fileName
=
IOUtils
.
createTempFile
(
path
,
Constants
.
SUFFIX_TEMP_FILE
,
true
,
true
);
}
catch
(
IOException
e
)
{
throw
DbException
.
convertIOException
(
e
,
null
);
}
tempFile
=
h
.
openFile
(
fileName
,
"rw"
,
false
);
tempFile
.
autoDelete
();
FileStoreOutputStream
out
=
new
FileStoreOutputStream
(
tempFile
,
null
,
null
);
return
out
;
}
public
long
getLobId
()
{
return
lobId
;
private
static
int
getBufferSize
(
DataHandler
handler
,
boolean
compress
,
long
remaining
)
{
if
(
remaining
<
0
||
remaining
>
Integer
.
MAX_VALUE
)
{
remaining
=
Integer
.
MAX_VALUE
;
}
long
inplace
=
handler
.
getMaxLengthInplaceLob
();
if
(
inplace
>=
Integer
.
MAX_VALUE
)
{
inplace
=
remaining
;
}
long
m
=
compress
?
Constants
.
IO_BUFFER_SIZE_COMPRESS
:
Constants
.
IO_BUFFER_SIZE
;
if
(
m
<
remaining
&&
m
<=
inplace
)
{
m
=
Math
.
min
(
remaining
,
inplace
+
1
);
// the buffer size must be bigger than the inplace lob, otherwise we can't
// know if it must be stored in-place or not
m
=
MathUtils
.
roundUpLong
(
m
,
Constants
.
IO_BUFFER_SIZE
);
}
m
=
Math
.
min
(
remaining
,
m
);
m
=
MathUtils
.
convertLongToInt
(
m
);
if
(
m
<
0
)
{
m
=
Integer
.
MAX_VALUE
;
}
return
(
int
)
m
;
}
}
This diff is collapsed.
Click to expand it.
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论