Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
40de3268
提交
40de3268
authored
3月 26, 2010
作者:
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
();
...
...
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
;
}
}
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.
...
...
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
;
}
...
...
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
;
}
...
...
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
:
{
...
...
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
();
}
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
);
}
}
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
;
}
}
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
);
}
...
...
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
);
...
...
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
;
...
...
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
...
...
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
;
}
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论