提交 d263ba28 authored 作者: Thomas Mueller's avatar Thomas Mueller

New experimental LOB storage mechanism.

上级 1de0bbf7
...@@ -32,7 +32,7 @@ import org.h2.value.ValueFloat; ...@@ -32,7 +32,7 @@ import org.h2.value.ValueFloat;
import org.h2.value.ValueInt; import org.h2.value.ValueInt;
import org.h2.value.ValueJavaObject; import org.h2.value.ValueJavaObject;
import org.h2.value.ValueLob; import org.h2.value.ValueLob;
import org.h2.value.ValueLob2; import org.h2.value.ValueLobDb;
import org.h2.value.ValueLong; import org.h2.value.ValueLong;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
import org.h2.value.ValueShort; import org.h2.value.ValueShort;
...@@ -565,10 +565,11 @@ public class Data { ...@@ -565,10 +565,11 @@ public class Data {
write(small, 0, small.length); write(small, 0, small.length);
} }
} else { } else {
ValueLob2 lob = (ValueLob2) v; ValueLobDb lob = (ValueLobDb) v;
byte[] small = lob.getSmall(); byte[] small = lob.getSmall();
if (small == null) { if (small == null) {
writeVarInt(-3); writeVarInt(-3);
writeVarInt(lob.getTableId());
writeVarLong(lob.getLobId()); writeVarLong(lob.getLobId());
writeVarLong(lob.getPrecision()); writeVarLong(lob.getPrecision());
} else { } else {
...@@ -697,10 +698,11 @@ public class Data { ...@@ -697,10 +698,11 @@ public class Data {
read(small, 0, smallLen); read(small, 0, smallLen);
return LobStorage.createSmallLob(type, small); return LobStorage.createSmallLob(type, small);
} else if (smallLen == -3) { } else if (smallLen == -3) {
int tableId = readVarInt();
long lobId = readVarLong(); long lobId = readVarLong();
long precision = readVarLong(); long precision = readVarLong();
LobStorage lobStorage = handler.getLobStorage(); LobStorage lobStorage = handler.getLobStorage();
ValueLob2 lob = ValueLob2.create(type, lobStorage, null, lobId, precision); ValueLobDb lob = ValueLobDb.create(type, lobStorage, null, tableId, lobId, precision);
return lob; return lob;
} else { } else {
int tableId = readVarInt(); int tableId = readVarInt();
...@@ -890,10 +892,11 @@ public class Data { ...@@ -890,10 +892,11 @@ public class Data {
len += small.length; len += small.length;
} }
} else { } else {
ValueLob2 lob = (ValueLob2) v; ValueLobDb lob = (ValueLobDb) v;
byte[] small = lob.getSmall(); byte[] small = lob.getSmall();
if (small == null) { if (small == null) {
len += getVarIntLen(-3); len += getVarIntLen(-3);
len += getVarIntLen(lob.getTableId());
len += getVarLongLen(lob.getLobId()); len += getVarLongLen(lob.getLobId());
len += getVarLongLen(lob.getPrecision()); len += getVarLongLen(lob.getPrecision());
} else { } else {
......
...@@ -16,7 +16,6 @@ import java.sql.SQLException; ...@@ -16,7 +16,6 @@ import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.concurrent.atomic.AtomicLong;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties; import org.h2.constant.SysProperties;
import org.h2.engine.Constants; import org.h2.engine.Constants;
...@@ -28,7 +27,7 @@ import org.h2.util.StringUtils; ...@@ -28,7 +27,7 @@ import org.h2.util.StringUtils;
import org.h2.util.Utils; import org.h2.util.Utils;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueLob; import org.h2.value.ValueLob;
import org.h2.value.ValueLob2; import org.h2.value.ValueLobDb;
/** /**
* This class stores LOB objects in the database. * This class stores LOB objects in the database.
...@@ -40,6 +39,12 @@ public class LobStorage { ...@@ -40,6 +39,12 @@ public class LobStorage {
*/ */
public static final int TABLE_ID_SESSION_VARIABLE = -1; public static final int TABLE_ID_SESSION_VARIABLE = -1;
/**
* The table id for temporary objects (not assigned to any object).
*/
public static final int TABLE_TEMP = -2;
private static final String LOBS = "INFORMATION_SCHEMA.LOBS"; private static final String LOBS = "INFORMATION_SCHEMA.LOBS";
private static final String LOB_MAP = "INFORMATION_SCHEMA.LOB_MAP"; private static final String LOB_MAP = "INFORMATION_SCHEMA.LOB_MAP";
private static final String LOB_DATA = "INFORMATION_SCHEMA.LOB_DATA"; private static final String LOB_DATA = "INFORMATION_SCHEMA.LOB_DATA";
...@@ -49,7 +54,6 @@ public class LobStorage { ...@@ -49,7 +54,6 @@ public class LobStorage {
private static final long UNIQUE = 0xffff; private static final long UNIQUE = 0xffff;
private Connection conn; private Connection conn;
private HashMap<String, PreparedStatement> prepared = New.hashMap(); private HashMap<String, PreparedStatement> prepared = New.hashMap();
private AtomicLong nextLob = new AtomicLong();
private long nextBlock; private long nextBlock;
private CompressTool compress = CompressTool.getInstance(); private CompressTool compress = CompressTool.getInstance();
...@@ -76,7 +80,7 @@ public class LobStorage { ...@@ -76,7 +80,7 @@ public class LobStorage {
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
// stat.execute("SET UNDO_LOG 0"); // stat.execute("SET UNDO_LOG 0");
// stat.execute("SET REDO_LOG_BINARY 0"); // stat.execute("SET REDO_LOG_BINARY 0");
stat.execute("CREATE TABLE IF NOT EXISTS " + LOBS + "(ID BIGINT PRIMARY KEY, LENGTH BIGINT, TABLE INT) HIDDEN"); stat.execute("CREATE TABLE IF NOT EXISTS " + LOBS + "(ID BIGINT PRIMARY KEY, BYTE_COUNT BIGINT, TABLE INT) HIDDEN");
stat.execute("CREATE TABLE IF NOT EXISTS " + LOB_MAP + "(LOB BIGINT, SEQ INT, BLOCK BIGINT, PRIMARY KEY(LOB, SEQ)) HIDDEN"); stat.execute("CREATE TABLE IF NOT EXISTS " + LOB_MAP + "(LOB BIGINT, SEQ INT, BLOCK BIGINT, PRIMARY KEY(LOB, SEQ)) HIDDEN");
stat.execute("CREATE INDEX IF NOT EXISTS INFORMATION_SCHEMA.INDEX_LOB_MAP_DATA_LOB ON " + LOB_MAP + "(BLOCK, LOB)"); stat.execute("CREATE INDEX IF NOT EXISTS INFORMATION_SCHEMA.INDEX_LOB_MAP_DATA_LOB ON " + LOB_MAP + "(BLOCK, LOB)");
stat.execute("CREATE TABLE IF NOT EXISTS " + LOB_DATA + "(BLOCK BIGINT PRIMARY KEY, COMPRESSED INT, DATA BINARY) HIDDEN"); stat.execute("CREATE TABLE IF NOT EXISTS " + LOB_DATA + "(BLOCK BIGINT PRIMARY KEY, COMPRESSED INT, DATA BINARY) HIDDEN");
...@@ -85,16 +89,20 @@ public class LobStorage { ...@@ -85,16 +89,20 @@ public class LobStorage {
rs.next(); rs.next();
nextBlock = rs.getLong(1) + 1; nextBlock = rs.getLong(1) + 1;
if (HASH) { if (HASH) {
nextBlock = Math.max(UNIQUE + 1, nextLob.get()); nextBlock = Math.max(UNIQUE + 1, nextBlock);
} }
rs = stat.executeQuery("SELECT MAX(ID) FROM " + LOBS);
rs.next();
nextLob.set(rs.getLong(1) + 1);
} catch (SQLException e) { } catch (SQLException e) {
throw DbException.convert(e); throw DbException.convert(e);
} }
} }
private long getNextLobId() throws SQLException {
PreparedStatement prep = prepare("SELECT MAX(ID) FROM " + LOBS);
ResultSet rs = prep.executeQuery();
rs.next();
return rs.getLong(1) + 1;
}
/** /**
* Remove all LOBs for this table. * Remove all LOBs for this table.
* *
...@@ -104,7 +112,7 @@ public class LobStorage { ...@@ -104,7 +112,7 @@ public class LobStorage {
if (SysProperties.LOB_IN_DATABASE) { if (SysProperties.LOB_IN_DATABASE) {
init(); init();
try { try {
PreparedStatement prep = prepare("SELECT ID FROM " + LOBS + " WHERE TABLE=?"); PreparedStatement prep = prepare("SELECT ID FROM " + LOBS + " WHERE TABLE = ?");
prep.setInt(1, tableId); prep.setInt(1, tableId);
ResultSet rs = prep.executeQuery(); ResultSet rs = prep.executeQuery();
while (rs.next()) { while (rs.next()) {
...@@ -113,6 +121,9 @@ public class LobStorage { ...@@ -113,6 +121,9 @@ public class LobStorage {
} catch (SQLException e) { } catch (SQLException e) {
throw DbException.convert(e); throw DbException.convert(e);
} }
if (tableId == TABLE_ID_SESSION_VARIABLE) {
removeAllForTable(TABLE_TEMP);
}
// remove both lobs in the database as well as in the file system // remove both lobs in the database as well as in the file system
// (compatibility) // (compatibility)
} }
...@@ -134,7 +145,7 @@ public class LobStorage { ...@@ -134,7 +145,7 @@ public class LobStorage {
} else { } else {
precision = small.length; precision = small.length;
} }
return ValueLob2.createSmallLob(type, small, precision); return ValueLobDb.createSmallLob(type, small, precision);
} }
return ValueLob.createSmallLob(type, small); return ValueLob.createSmallLob(type, small);
} }
...@@ -148,7 +159,7 @@ public class LobStorage { ...@@ -148,7 +159,7 @@ public class LobStorage {
private PreparedStatement prepSelect; private PreparedStatement prepSelect;
private byte[] buffer; private byte[] buffer;
private int pos; private int pos;
private long remaining; private long remainingBytes;
private long lob; private long lob;
private int seq; private int seq;
private CompressTool compress; private CompressTool compress;
...@@ -158,13 +169,13 @@ public class LobStorage { ...@@ -158,13 +169,13 @@ public class LobStorage {
try { try {
this.lob = lob; this.lob = lob;
PreparedStatement prep = conn.prepareStatement( PreparedStatement prep = conn.prepareStatement(
"SELECT LENGTH FROM " + LOBS + " WHERE ID = ?"); "SELECT BYTE_COUNT FROM " + LOBS + " WHERE ID = ?");
prep.setLong(1, lob); prep.setLong(1, lob);
ResultSet rs = prep.executeQuery(); ResultSet rs = prep.executeQuery();
if (!rs.next()) { if (!rs.next()) {
throw DbException.get(ErrorCode.IO_EXCEPTION_1, "Missing lob: "+ lob).getSQLException(); throw DbException.get(ErrorCode.IO_EXCEPTION_1, "Missing lob: "+ lob).getSQLException();
} }
remaining = rs.getLong(1); remainingBytes = rs.getLong(1);
rs.close(); rs.close();
} catch (SQLException e) { } catch (SQLException e) {
throw DbException.convertToIOException(e); throw DbException.convertToIOException(e);
...@@ -173,10 +184,10 @@ public class LobStorage { ...@@ -173,10 +184,10 @@ public class LobStorage {
public int read() throws IOException { public int read() throws IOException {
fillBuffer(); fillBuffer();
if (remaining <= 0) { if (remainingBytes <= 0) {
return -1; return -1;
} }
remaining--; remainingBytes--;
return buffer[pos++] & 255; return buffer[pos++] & 255;
} }
...@@ -195,15 +206,15 @@ public class LobStorage { ...@@ -195,15 +206,15 @@ public class LobStorage {
int read = 0; int read = 0;
while (length > 0) { while (length > 0) {
fillBuffer(); fillBuffer();
if (remaining <= 0) { if (remainingBytes <= 0) {
break; break;
} }
int len = (int) Math.min(length, remaining); int len = (int) Math.min(length, remainingBytes);
len = Math.min(len, buffer.length - pos); len = Math.min(len, buffer.length - pos);
System.arraycopy(buffer, pos, buff, off, len); System.arraycopy(buffer, pos, buff, off, len);
pos += len; pos += len;
read += len; read += len;
remaining -= len; remainingBytes -= len;
off += len; off += len;
length -= len; length -= len;
} }
...@@ -214,7 +225,7 @@ public class LobStorage { ...@@ -214,7 +225,7 @@ public class LobStorage {
if (buffer != null && pos < buffer.length) { if (buffer != null && pos < buffer.length) {
return; return;
} }
if (remaining <= 0) { if (remainingBytes <= 0) {
return; return;
} }
try { try {
...@@ -289,17 +300,17 @@ public class LobStorage { ...@@ -289,17 +300,17 @@ public class LobStorage {
return new LobInputStream(conn, lobId); return new LobInputStream(conn, lobId);
} }
private ValueLob2 addLob(InputStream in, long maxLength, int type) { private ValueLobDb addLob(InputStream in, long maxLength, int type) {
byte[] buff = new byte[BLOCK_LENGTH]; byte[] buff = new byte[BLOCK_LENGTH];
if (maxLength < 0) { if (maxLength < 0) {
maxLength = Long.MAX_VALUE; maxLength = Long.MAX_VALUE;
} }
long length = 0; long length = 0;
long lobId; long lobId;
lobId = nextLob.getAndIncrement();
int maxLengthInPlaceLob = handler.getMaxLengthInplaceLob(); int maxLengthInPlaceLob = handler.getMaxLengthInplaceLob();
String compressAlgorithm = handler.getLobCompressionAlgorithm(type); String compressAlgorithm = handler.getLobCompressionAlgorithm(type);
try { try {
lobId = getNextLobId();
try { try {
for (int seq = 0; maxLength > 0; seq++) { for (int seq = 0; maxLength > 0; seq++) {
int len = (int) Math.min(BLOCK_LENGTH, maxLength); int len = (int) Math.min(BLOCK_LENGTH, maxLength);
...@@ -318,23 +329,63 @@ public class LobStorage { ...@@ -318,23 +329,63 @@ public class LobStorage {
} }
if (seq == 0 && b.length < BLOCK_LENGTH && b.length <= maxLengthInPlaceLob) { if (seq == 0 && b.length < BLOCK_LENGTH && b.length <= maxLengthInPlaceLob) {
// CLOB: the precision will be fixed later // CLOB: the precision will be fixed later
ValueLob2 v = ValueLob2.createSmallLob(type, b, b.length); ValueLobDb v = ValueLobDb.createSmallLob(type, b, b.length);
return v; return v;
} }
storeBlock(lobId, seq, b, compressAlgorithm); storeBlock(lobId, seq, b, compressAlgorithm);
} }
return registerLob(type, lobId, TABLE_TEMP, length);
} catch (IOException e) {
deleteLob(lobId);
throw DbException.convertIOException(e, "adding blob");
}
} catch (SQLException e) {
throw DbException.convert(e);
}
}
private ValueLobDb registerLob(int type, long lobId, int tableId, long byteCount) {
try {
PreparedStatement prep = prepare( PreparedStatement prep = prepare(
"INSERT INTO " + LOBS + "(ID, LENGTH, TABLE) VALUES(?, ?, ?)"); "INSERT INTO " + LOBS + "(ID, BYTE_COUNT, TABLE) VALUES(?, ?, ?)");
prep.setLong(1, lobId); prep.setLong(1, lobId);
prep.setLong(2, length); prep.setLong(2, byteCount);
prep.setInt(3, TABLE_ID_SESSION_VARIABLE); prep.setInt(3, tableId);
prep.execute(); prep.execute();
ValueLob2 v = ValueLob2.create(type, this, null, lobId, length); ValueLobDb v = ValueLobDb.create(type, this, null, tableId, lobId, byteCount);
return v; return v;
} catch (IOException e) { } catch (SQLException e) {
deleteLob(lobId); throw DbException.convert(e);
throw DbException.convertIOException(e, "adding blob");
} }
}
/**
* Copy a lob.
*
* @param type the type
* @param oldLobId the old lob id
* @param tableId the new table id
* @param length the length
* @return the new lob
*/
public ValueLobDb copyLob(int type, long oldLobId, int tableId, long length) {
try {
long lobId = getNextLobId();
PreparedStatement prep = prepare(
"INSERT INTO " + LOB_MAP + "(LOB, SEQ, BLOCK) " +
"SELECT ?, SEQ, BLOCK FROM " + LOB_MAP + " WHERE LOB = ?");
prep.setLong(1, lobId);
prep.setLong(2, oldLobId);
prep.executeUpdate();
prep = prepare(
"INSERT INTO " + LOBS + "(ID, BYTE_COUNT, TABLE) " +
"SELECT ?, BYTE_COUNT, ? FROM " + LOBS + " WHERE ID = ?");
prep.setLong(1, lobId);
prep.setLong(2, tableId);
prep.setLong(3, oldLobId);
prep.executeUpdate();
ValueLobDb v = ValueLobDb.create(type, this, null, tableId, lobId, length);
return v;
} catch (SQLException e) { } catch (SQLException e) {
throw DbException.convert(e); throw DbException.convert(e);
} }
...@@ -474,7 +525,7 @@ public class LobStorage { ...@@ -474,7 +525,7 @@ public class LobStorage {
if (SysProperties.LOB_IN_DATABASE) { if (SysProperties.LOB_IN_DATABASE) {
init(); init();
if (conn == null) { if (conn == null) {
return ValueLob2.createTempBlob(in, maxLength, handler); return ValueLobDb.createTempBlob(in, maxLength, handler);
} }
return addLob(in, maxLength, Value.BLOB); return addLob(in, maxLength, Value.BLOB);
} }
...@@ -492,11 +543,11 @@ public class LobStorage { ...@@ -492,11 +543,11 @@ public class LobStorage {
if (SysProperties.LOB_IN_DATABASE) { if (SysProperties.LOB_IN_DATABASE) {
init(); init();
if (conn == null) { if (conn == null) {
return ValueLob2.createTempClob(reader, maxLength, handler); return ValueLobDb.createTempClob(reader, maxLength, handler);
} }
long max = maxLength == -1 ? Long.MAX_VALUE : maxLength; long max = maxLength == -1 ? Long.MAX_VALUE : maxLength;
CountingReaderInputStream in = new CountingReaderInputStream(reader, max); CountingReaderInputStream in = new CountingReaderInputStream(reader, max);
ValueLob2 lob = addLob(in, Long.MAX_VALUE, Value.CLOB); ValueLobDb lob = addLob(in, Long.MAX_VALUE, Value.CLOB);
lob.setPrecision(in.getLength()); lob.setPrecision(in.getLength());
return lob; return lob;
} }
...@@ -516,7 +567,8 @@ public class LobStorage { ...@@ -516,7 +567,8 @@ public class LobStorage {
prep.setLong(2, lobId); prep.setLong(2, lobId);
int updateCount = prep.executeUpdate(); int updateCount = prep.executeUpdate();
if (updateCount != 1) { if (updateCount != 1) {
throw DbException.throwInternalError("count: " + updateCount); // can be zero when recovering
// throw DbException.throwInternalError("count: " + updateCount);
} }
} catch (SQLException e) { } catch (SQLException e) {
throw DbException.convert(e); throw DbException.convert(e);
......
...@@ -18,6 +18,7 @@ import java.io.Reader; ...@@ -18,6 +18,7 @@ import java.io.Reader;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet; import java.util.BitSet;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
...@@ -29,6 +30,7 @@ import org.h2.constant.SysProperties; ...@@ -29,6 +30,7 @@ import org.h2.constant.SysProperties;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.engine.DbObject; import org.h2.engine.DbObject;
import org.h2.engine.MetaRecord; import org.h2.engine.MetaRecord;
import org.h2.jdbc.JdbcConnection;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.result.SimpleRow; import org.h2.result.SimpleRow;
...@@ -55,7 +57,7 @@ import org.h2.util.Tool; ...@@ -55,7 +57,7 @@ import org.h2.util.Tool;
import org.h2.util.Utils; import org.h2.util.Utils;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueLob; import org.h2.value.ValueLob;
import org.h2.value.ValueLob2; import org.h2.value.ValueLobDb;
import org.h2.value.ValueLong; import org.h2.value.ValueLong;
/** /**
...@@ -74,15 +76,46 @@ public class Recover extends Tool implements DataHandler { ...@@ -74,15 +76,46 @@ public class Recover extends Tool implements DataHandler {
private ArrayList<MetaRecord> schema; private ArrayList<MetaRecord> schema;
private HashSet<Integer> objectIdSet; private HashSet<Integer> objectIdSet;
private HashMap<Integer, String> tableMap; private HashMap<Integer, String> tableMap;
private HashMap<String, String> columnTypeMap;
private boolean remove; private boolean remove;
private long pageDataEmpty;
private int pageDataRows;
private int pageDataHead;
private int pageSize; private int pageSize;
private FileStore store; private FileStore store;
private int[] parents; private int[] parents;
private Stats stat;
/**
* Statistic data
*/
class Stats {
/**
* The empty space in bytes in a data leaf pages.
*/
long pageDataEmpty;
/**
* The number of bytes used for data.
*/
int pageDataRows;
/**
* The number of bytes used for the page headers.
*/
int pageDataHead;
/**
* The count per page type.
*/
int[] pageTypeCount = new int[Page.TYPE_STREAM_DATA + 2];
/**
* The number of free pages.
*/
int free;
}
/** /**
* Options are case sensitive. Supported options are: * Options are case sensitive. Supported options are:
* <table> * <table>
...@@ -155,18 +188,21 @@ public class Recover extends Tool implements DataHandler { ...@@ -155,18 +188,21 @@ public class Recover extends Tool implements DataHandler {
/** /**
* INTERNAL * INTERNAL
*/ */
public static Reader readClobDb(Connection conn, long lobId) throws IOException { public static Value.ValueBlob readBlobDb(Connection conn, long lobId, long precision) {
return new BufferedReader(new InputStreamReader(readBlobDb(conn, lobId), "UTF-8")); DataHandler h = ((JdbcConnection) conn).getSession().getDataHandler();
LobStorage lobStorage = h.getLobStorage();
return ValueLobDb.create(Value.BLOB, lobStorage, null, LobStorage.TABLE_TEMP, lobId, precision);
} }
/** /**
* INTERNAL * INTERNAL
*/ */
public static InputStream readBlobDb(Connection conn, long lobId) throws IOException { public static Value.ValueClob readClobDb(Connection conn, long lobId, long precision) {
return new BufferedInputStream(new LobStorage.LobInputStream(conn, lobId)); DataHandler h = ((JdbcConnection) conn).getSession().getDataHandler();
LobStorage lobStorage = h.getLobStorage();
return ValueLobDb.create(Value.CLOB, lobStorage, null, LobStorage.TABLE_TEMP, lobId, precision);
} }
private void trace(String message) { private void trace(String message) {
if (trace) { if (trace) {
out.println(message); out.println(message);
...@@ -279,7 +315,7 @@ public class Recover extends Tool implements DataHandler { ...@@ -279,7 +315,7 @@ public class Recover extends Tool implements DataHandler {
} }
} }
private String getSQL(Value v) { private String getSQL(String column, Value v) {
if (v instanceof ValueLob) { if (v instanceof ValueLob) {
ValueLob lob = (ValueLob) v; ValueLob lob = (ValueLob) v;
byte[] small = lob.getSmall(); byte[] small = lob.getSmall();
...@@ -290,15 +326,24 @@ public class Recover extends Tool implements DataHandler { ...@@ -290,15 +326,24 @@ public class Recover extends Tool implements DataHandler {
} }
return "READ_CLOB('" + file + ".txt')"; return "READ_CLOB('" + file + ".txt')";
} }
} else if (v instanceof ValueLob2) { } else if (v instanceof ValueLobDb) {
ValueLob2 lob = (ValueLob2) v; ValueLobDb lob = (ValueLobDb) v;
byte[] small = lob.getSmall(); byte[] small = lob.getSmall();
if (small == null) { if (small == null) {
int type = lob.getType();
long id = lob.getLobId(); long id = lob.getLobId();
if (lob.getType() == Value.BLOB) { long precision = lob.getPrecision();
return "READ_BLOB_DB(" + id + ")"; String m;
String columnType;
if (type == Value.BLOB) {
columnType = "BLOB";
m = "READ_BLOB_DB";
} else {
columnType = "CLOB";
m = "READ_CLOB_DB";
} }
return "READ_CLOB_DB(" + id + ")"; columnTypeMap.put(column, columnType);
return m + "(" + id + ", " + precision + ")";
} }
} }
return v.getSQL(); return v.getSQL();
...@@ -311,17 +356,13 @@ public class Recover extends Tool implements DataHandler { ...@@ -311,17 +356,13 @@ public class Recover extends Tool implements DataHandler {
private void dumpPageStore(String fileName) { private void dumpPageStore(String fileName) {
setDatabaseName(fileName.substring(0, fileName.length() - Constants.SUFFIX_PAGE_FILE.length())); setDatabaseName(fileName.substring(0, fileName.length() - Constants.SUFFIX_PAGE_FILE.length()));
PrintWriter writer = null; PrintWriter writer = null;
int[] pageTypeCount = new int[Page.TYPE_STREAM_DATA + 2]; stat = new Stats();
int emptyPages = 0;
pageDataEmpty = 0;
pageDataRows = 0;
pageDataHead = 0;
try { try {
writer = getWriter(fileName, ".sql"); writer = getWriter(fileName, ".sql");
writer.println("CREATE ALIAS IF NOT EXISTS READ_CLOB FOR \"" + this.getClass().getName() + ".readClob\";");
writer.println("CREATE ALIAS IF NOT EXISTS READ_BLOB FOR \"" + this.getClass().getName() + ".readBlob\";"); writer.println("CREATE ALIAS IF NOT EXISTS READ_BLOB FOR \"" + this.getClass().getName() + ".readBlob\";");
writer.println("CREATE ALIAS IF NOT EXISTS READ_CLOB_DB FOR \"" + this.getClass().getName() + ".readClobDb\";"); writer.println("CREATE ALIAS IF NOT EXISTS READ_CLOB FOR \"" + this.getClass().getName() + ".readClob\";");
writer.println("CREATE ALIAS IF NOT EXISTS READ_BLOB_DB FOR \"" + this.getClass().getName() + ".readBlobDb\";"); writer.println("CREATE ALIAS IF NOT EXISTS READ_BLOB_DB FOR \"" + this.getClass().getName() + ".readBlobDb\";");
writer.println("CREATE ALIAS IF NOT EXISTS READ_CLOB_DB FOR \"" + this.getClass().getName() + ".readClobDb\";");
resetSchema(); resetSchema();
store = FileStore.open(null, fileName, remove ? "rw" : "r"); store = FileStore.open(null, fileName, remove ? "rw" : "r");
long length = store.length(); long length = store.length();
...@@ -356,6 +397,7 @@ public class Recover extends Tool implements DataHandler { ...@@ -356,6 +397,7 @@ public class Recover extends Tool implements DataHandler {
parents[i] = s.readInt(); parents[i] = s.readInt();
} }
int logKey = 0, logFirstTrunkPage = 0, logFirstDataPage = 0; int logKey = 0, logFirstTrunkPage = 0, logFirstDataPage = 0;
s = Data.create(this, pageSize);
for (int i = 1;; i++) { for (int i = 1;; i++) {
if (i == 3) { if (i == 3) {
break; break;
...@@ -363,7 +405,6 @@ public class Recover extends Tool implements DataHandler { ...@@ -363,7 +405,6 @@ public class Recover extends Tool implements DataHandler {
s.reset(); s.reset();
store.seek(i * pageSize); store.seek(i * pageSize);
store.readFully(s.getBytes(), 0, pageSize); store.readFully(s.getBytes(), 0, pageSize);
CRC32 crc = new CRC32(); CRC32 crc = new CRC32();
crc.update(s.getBytes(), 4, pageSize - 4); crc.update(s.getBytes(), 4, pageSize - 4);
int expected = (int) crc.getValue(); int expected = (int) crc.getValue();
...@@ -386,8 +427,45 @@ public class Recover extends Tool implements DataHandler { ...@@ -386,8 +427,45 @@ public class Recover extends Tool implements DataHandler {
writer.println("-- firstTrunkPage: " + logFirstTrunkPage + writer.println("-- firstTrunkPage: " + logFirstTrunkPage +
" firstDataPage: " + logFirstDataPage); " firstDataPage: " + logFirstDataPage);
s = Data.create(this, pageSize); int[] pageTypeCount = new int[Page.TYPE_STREAM_DATA + 2];
int free = 0; PrintWriter devNull = new PrintWriter(new OutputStream() {
public void write(int b) {
// ignore
}
});
dumpPageStore(devNull, pageCount);
Arrays.fill(pageTypeCount, 0);
stat = new Stats();
schema.clear();
objectIdSet = New.hashSet();
dumpPageStore(writer, pageCount);
writeSchema(writer);
try {
dumpPageLogStream(writer, logKey, logFirstTrunkPage, logFirstDataPage);
} catch (EOFException e) {
// ignore
}
writer.println("---- Statistics ----------");
writer.println("-- page count: " + pageCount + " free: " + stat.free);
writer.println("-- page data head: " + stat.pageDataHead + " empty: " + stat.pageDataEmpty + " rows: " + stat.pageDataRows);
for (int i = 0; i < pageTypeCount.length; i++) {
int count = pageTypeCount[i];
if (count > 0) {
writer.println("-- page count type: " + i + " " + (100 * count / pageCount) + "% count: " + count);
}
}
writer.close();
} catch (Throwable e) {
writeError(writer, e);
} finally {
IOUtils.closeSilently(writer);
closeSilently(store);
}
}
private void dumpPageStore(PrintWriter writer, int pageCount) {
Data s = Data.create(this, pageSize);
for (int page = 3; page < pageCount; page++) { for (int page = 3; page < pageCount; page++) {
s = Data.create(this, pageSize); s = Data.create(this, pageSize);
store.seek(page * pageSize); store.seek(page * pageSize);
...@@ -395,8 +473,7 @@ public class Recover extends Tool implements DataHandler { ...@@ -395,8 +473,7 @@ public class Recover extends Tool implements DataHandler {
int type = s.readByte(); int type = s.readByte();
switch (type) { switch (type) {
case Page.TYPE_EMPTY: case Page.TYPE_EMPTY:
pageTypeCount[type]++; stat.pageTypeCount[type]++;
emptyPages++;
continue; continue;
} }
boolean last = (type & Page.FLAG_LAST) != 0; boolean last = (type & Page.FLAG_LAST) != 0;
...@@ -408,7 +485,7 @@ public class Recover extends Tool implements DataHandler { ...@@ -408,7 +485,7 @@ public class Recover extends Tool implements DataHandler {
switch (type) { switch (type) {
// type 1 // type 1
case Page.TYPE_DATA_LEAF: { case Page.TYPE_DATA_LEAF: {
pageTypeCount[type]++; stat.pageTypeCount[type]++;
int parentPageId = s.readInt(); int parentPageId = s.readInt();
setStorage(s.readVarInt()); setStorage(s.readVarInt());
int columnCount = s.readVarInt(); int columnCount = s.readVarInt();
...@@ -420,7 +497,7 @@ public class Recover extends Tool implements DataHandler { ...@@ -420,7 +497,7 @@ public class Recover extends Tool implements DataHandler {
} }
// type 2 // type 2
case Page.TYPE_DATA_NODE: { case Page.TYPE_DATA_NODE: {
pageTypeCount[type]++; stat.pageTypeCount[type]++;
int parentPageId = s.readInt(); int parentPageId = s.readInt();
setStorage(s.readVarInt()); setStorage(s.readVarInt());
int rowCount = s.readInt(); int rowCount = s.readInt();
...@@ -432,12 +509,12 @@ public class Recover extends Tool implements DataHandler { ...@@ -432,12 +509,12 @@ public class Recover extends Tool implements DataHandler {
} }
// type 3 // type 3
case Page.TYPE_DATA_OVERFLOW: case Page.TYPE_DATA_OVERFLOW:
pageTypeCount[type]++; stat.pageTypeCount[type]++;
writer.println("-- page " + page + ": data overflow " + (last ? "(last)" : "")); writer.println("-- page " + page + ": data overflow " + (last ? "(last)" : ""));
break; break;
// type 4 // type 4
case Page.TYPE_BTREE_LEAF: { case Page.TYPE_BTREE_LEAF: {
pageTypeCount[type]++; stat.pageTypeCount[type]++;
int parentPageId = s.readInt(); int parentPageId = s.readInt();
setStorage(s.readVarInt()); setStorage(s.readVarInt());
int entries = s.readShortInt(); int entries = s.readShortInt();
...@@ -450,7 +527,7 @@ public class Recover extends Tool implements DataHandler { ...@@ -450,7 +527,7 @@ public class Recover extends Tool implements DataHandler {
} }
// type 5 // type 5
case Page.TYPE_BTREE_NODE: case Page.TYPE_BTREE_NODE:
pageTypeCount[type]++; stat.pageTypeCount[type]++;
int parentPageId = s.readInt(); int parentPageId = s.readInt();
setStorage(s.readVarInt()); setStorage(s.readVarInt());
writer.println("-- page " + page + ": b-tree node" + (last ? "(last)" : "") + " parent: " + parentPageId + writer.println("-- page " + page + ": b-tree node" + (last ? "(last)" : "") + " parent: " + parentPageId +
...@@ -459,18 +536,18 @@ public class Recover extends Tool implements DataHandler { ...@@ -459,18 +536,18 @@ public class Recover extends Tool implements DataHandler {
break; break;
// type 6 // type 6
case Page.TYPE_FREE_LIST: case Page.TYPE_FREE_LIST:
pageTypeCount[type]++; stat.pageTypeCount[type]++;
writer.println("-- page " + page + ": free list " + (last ? "(last)" : "")); writer.println("-- page " + page + ": free list " + (last ? "(last)" : ""));
free += dumpPageFreeList(writer, s, page, pageCount); stat.free += dumpPageFreeList(writer, s, page, pageCount);
break; break;
// type 7 // type 7
case Page.TYPE_STREAM_TRUNK: case Page.TYPE_STREAM_TRUNK:
pageTypeCount[type]++; stat.pageTypeCount[type]++;
writer.println("-- page " + page + ": log trunk"); writer.println("-- page " + page + ": log trunk");
break; break;
// type 8 // type 8
case Page.TYPE_STREAM_DATA: case Page.TYPE_STREAM_DATA:
pageTypeCount[type]++; stat.pageTypeCount[type]++;
writer.println("-- page " + page + ": log data"); writer.println("-- page " + page + ": log data");
break; break;
default: default:
...@@ -478,28 +555,6 @@ public class Recover extends Tool implements DataHandler { ...@@ -478,28 +555,6 @@ public class Recover extends Tool implements DataHandler {
break; break;
} }
} }
writeSchema(writer);
try {
dumpPageLogStream(writer, logKey, logFirstTrunkPage, logFirstDataPage);
} catch (EOFException e) {
// ignore
}
writer.println("---- Statistics ----------");
writer.println("-- page count: " + pageCount + " empty: " + emptyPages + " free: " + free);
writer.println("-- page data head: " + pageDataHead + " empty: " + pageDataEmpty + " rows: " + pageDataRows);
for (int i = 0; i < pageTypeCount.length; i++) {
int count = pageTypeCount[i];
if (count > 0) {
writer.println("-- page count type: " + i + " " + (100 * count / pageCount) + "% count: " + count);
}
}
writer.close();
} catch (Throwable e) {
writeError(writer, e);
} finally {
IOUtils.closeSilently(writer);
closeSilently(store);
}
} }
private void dumpPageLogStream(PrintWriter writer, int logKey, int logFirstTrunkPage, int logFirstDataPage) throws IOException { private void dumpPageLogStream(PrintWriter writer, int logKey, int logFirstTrunkPage, int logFirstDataPage) throws IOException {
...@@ -906,10 +961,10 @@ public class Recover extends Tool implements DataHandler { ...@@ -906,10 +961,10 @@ public class Recover extends Tool implements DataHandler {
empty = Math.min(off, empty); empty = Math.min(off, empty);
offsets[i] = off; offsets[i] = off;
} }
pageDataRows += pageSize - empty; stat.pageDataRows += pageSize - empty;
empty = empty - s.length(); empty = empty - s.length();
pageDataHead += s.length(); stat.pageDataHead += s.length();
pageDataEmpty += empty; stat.pageDataEmpty += empty;
if (trace) { if (trace) {
writer.println("-- empty: " + empty); writer.println("-- empty: " + empty);
} }
...@@ -1020,7 +1075,8 @@ public class Recover extends Tool implements DataHandler { ...@@ -1020,7 +1075,8 @@ public class Recover extends Tool implements DataHandler {
if (valueId > 0) { if (valueId > 0) {
sb.append(", "); sb.append(", ");
} }
sb.append(getSQL(v)); String columnName = storageName + "." + valueId;
sb.append(getSQL(columnName, v));
} catch (Exception e) { } catch (Exception e) {
writeDataError(writer, "exception " + e, s.getBytes()); writeDataError(writer, "exception " + e, s.getBytes());
continue; continue;
...@@ -1051,6 +1107,7 @@ public class Recover extends Tool implements DataHandler { ...@@ -1051,6 +1107,7 @@ public class Recover extends Tool implements DataHandler {
schema = New.arrayList(); schema = New.arrayList();
objectIdSet = New.hashSet(); objectIdSet = New.hashSet();
tableMap = New.hashMap(); tableMap = New.hashMap();
columnTypeMap = New.hashMap();
} }
private void writeSchema(PrintWriter writer) { private void writeSchema(PrintWriter writer) {
...@@ -1063,11 +1120,31 @@ public class Recover extends Tool implements DataHandler { ...@@ -1063,11 +1120,31 @@ public class Recover extends Tool implements DataHandler {
writer.println(sql + ";"); writer.println(sql + ";");
} }
} }
// first, copy the lob storage (if there is any)
// must occur before copying data,
// otherwise the lob storage may be overwritten
for (Map.Entry<Integer, String> entry : tableMap.entrySet()) { for (Map.Entry<Integer, String> entry : tableMap.entrySet()) {
Integer objectId = entry.getKey(); Integer objectId = entry.getKey();
String name = entry.getValue(); String name = entry.getValue();
if (objectIdSet.contains(objectId)) { if (objectIdSet.contains(objectId)) {
if (name.startsWith("INFORMATION_SCHEMA.LOB")) {
setStorage(objectId); setStorage(objectId);
writer.println("DELETE FROM " + name + ";");
writer.println("INSERT INTO " + name + " SELECT * FROM " + storageName + ";");
if (name.startsWith("INFORMATION_SCHEMA.LOBS")) {
writer.println("UPDATE " + name + " SET TABLE = " + LobStorage.TABLE_TEMP + ";");
}
}
}
}
for (Map.Entry<Integer, String> entry : tableMap.entrySet()) {
Integer objectId = entry.getKey();
String name = entry.getValue();
if (objectIdSet.contains(objectId)) {
setStorage(objectId);
if (name.startsWith("INFORMATION_SCHEMA.LOB")) {
continue;
}
writer.println("INSERT INTO " + name + " SELECT * FROM " + storageName + ";"); writer.println("INSERT INTO " + name + " SELECT * FROM " + storageName + ";");
} }
} }
...@@ -1075,10 +1152,11 @@ public class Recover extends Tool implements DataHandler { ...@@ -1075,10 +1152,11 @@ public class Recover extends Tool implements DataHandler {
setStorage(objectId); setStorage(objectId);
writer.println("DROP TABLE " + storageName + ";"); writer.println("DROP TABLE " + storageName + ";");
} }
writer.println("DROP ALIAS READ_CLOB;");
writer.println("DROP ALIAS READ_BLOB;"); writer.println("DROP ALIAS READ_BLOB;");
writer.println("DROP ALIAS READ_CLOB_DB;"); writer.println("DROP ALIAS READ_CLOB;");
writer.println("DROP ALIAS READ_BLOB_DB;"); writer.println("DROP ALIAS READ_BLOB_DB;");
writer.println("DROP ALIAS READ_CLOB_DB;");
writer.println("DELETE FROM INFORMATION_SCHEMA.LOBS WHERE TABLE = " + LobStorage.TABLE_TEMP + ";");
for (MetaRecord m : schema) { for (MetaRecord m : schema) {
String sql = m.getSQL(); String sql = m.getSQL();
// everything except create // everything except create
...@@ -1095,7 +1173,13 @@ public class Recover extends Tool implements DataHandler { ...@@ -1095,7 +1173,13 @@ public class Recover extends Tool implements DataHandler {
buff.append(storageName).append('('); buff.append(storageName).append('(');
for (int i = 0; i < recordLength; i++) { for (int i = 0; i < recordLength; i++) {
buff.appendExceptFirst(", "); buff.appendExceptFirst(", ");
buff.append('C').append(i).append(" VARCHAR"); buff.append('C').append(i).append(' ');
String columnType = columnTypeMap.get(storageName + "." + i);
if (columnType == null) {
buff.append("VARCHAR");
} else {
buff.append(columnType);
}
} }
writer.println(buff.append(");").toString()); writer.println(buff.append(");").toString());
writer.flush(); writer.flush();
...@@ -1119,6 +1203,9 @@ public class Recover extends Tool implements DataHandler { ...@@ -1119,6 +1203,9 @@ public class Recover extends Tool implements DataHandler {
} else { } else {
return "UNKNOWN"; return "UNKNOWN";
} }
if (sql.startsWith("IF NOT EXISTS ")) {
sql = sql.substring("IF NOT EXISTS ".length());
}
boolean ignore = false; boolean ignore = false;
for (int i = 0; i < sql.length(); i++) { for (int i = 0; i < sql.length(); i++) {
char ch = sql.charAt(i); char ch = sql.charAt(i);
......
...@@ -770,6 +770,10 @@ public class DataType { ...@@ -770,6 +770,10 @@ public class DataType {
} }
if (ResultSet.class.isAssignableFrom(x)) { if (ResultSet.class.isAssignableFrom(x)) {
return Value.RESULT_SET; return Value.RESULT_SET;
} else if (Value.ValueBlob.class.isAssignableFrom(x)) {
return Value.BLOB;
} else if (Value.ValueClob.class.isAssignableFrom(x)) {
return Value.CLOB;
} else if (String.class.isAssignableFrom(x)) { } else if (String.class.isAssignableFrom(x)) {
return Value.STRING; return Value.STRING;
} else if (BigDecimal.class.isAssignableFrom(x)) { } else if (BigDecimal.class.isAssignableFrom(x)) {
...@@ -836,6 +840,12 @@ public class DataType { ...@@ -836,6 +840,12 @@ public class DataType {
} }
if (x instanceof String) { if (x instanceof String) {
return ValueString.get((String) x); return ValueString.get((String) x);
} else if (x instanceof Value) {
return (Value) x;
} else if (x instanceof Long) {
return ValueLong.get(((Long) x).longValue());
} else if (x instanceof Integer) {
return ValueInt.get(((Integer) x).intValue());
} else if (x instanceof BigDecimal) { } else if (x instanceof BigDecimal) {
return ValueDecimal.get((BigDecimal) x); return ValueDecimal.get((BigDecimal) x);
} else if (x instanceof Boolean) { } else if (x instanceof Boolean) {
...@@ -844,10 +854,6 @@ public class DataType { ...@@ -844,10 +854,6 @@ public class DataType {
return ValueByte.get(((Byte) x).byteValue()); return ValueByte.get(((Byte) x).byteValue());
} else if (x instanceof Short) { } else if (x instanceof Short) {
return ValueShort.get(((Short) x).shortValue()); return ValueShort.get(((Short) x).shortValue());
} else if (x instanceof Integer) {
return ValueInt.get(((Integer) x).intValue());
} else if (x instanceof Long) {
return ValueLong.get(((Long) x).longValue());
} else if (x instanceof Float) { } else if (x instanceof Float) {
return ValueFloat.get(((Float) x).floatValue()); return ValueFloat.get(((Float) x).floatValue());
} else if (x instanceof Double) { } else if (x instanceof Double) {
......
...@@ -1007,4 +1007,18 @@ public abstract class Value { ...@@ -1007,4 +1007,18 @@ public abstract class Value {
return this; return this;
} }
/**
* A "binary large object".
*/
public interface ValueClob {
// this is a marker interface
}
/**
* A "character large object".
*/
public interface ValueBlob {
// this is a marker interface
}
} }
...@@ -29,7 +29,7 @@ import org.h2.util.Utils; ...@@ -29,7 +29,7 @@ import org.h2.util.Utils;
/** /**
* An alternate LOB implementation. * An alternate LOB implementation.
*/ */
public class ValueLob2 extends Value { public class ValueLobDb extends Value implements Value.ValueClob, Value.ValueBlob {
private final int type; private final int type;
private long precision; private long precision;
...@@ -45,7 +45,7 @@ public class ValueLob2 extends Value { ...@@ -45,7 +45,7 @@ public class ValueLob2 extends Value {
private FileStore tempFile; private FileStore tempFile;
private String fileName; private String fileName;
private ValueLob2(int type, LobStorage lobStorage, String fileName, int tableId, long lobId, long precision) { private ValueLobDb(int type, LobStorage lobStorage, String fileName, int tableId, long lobId, long precision) {
this.type = type; this.type = type;
this.lobStorage = lobStorage; this.lobStorage = lobStorage;
this.fileName = fileName; this.fileName = fileName;
...@@ -54,7 +54,7 @@ public class ValueLob2 extends Value { ...@@ -54,7 +54,7 @@ public class ValueLob2 extends Value {
this.precision = precision; this.precision = precision;
} }
private ValueLob2(int type, byte[] small, long precision) { private ValueLobDb(int type, byte[] small, long precision) {
this.type = type; this.type = type;
this.small = small; this.small = small;
this.precision = precision; this.precision = precision;
...@@ -66,12 +66,13 @@ public class ValueLob2 extends Value { ...@@ -66,12 +66,13 @@ public class ValueLob2 extends Value {
* @param type the type * @param type the type
* @param lobStorage the storage * @param lobStorage the storage
* @param fileName the file name (may be null) * @param fileName the file name (may be null)
* @param tableId the table id
* @param id the lob id * @param id the lob id
* @param precision the precision (number of bytes / characters) * @param precision the precision (number of bytes / characters)
* @return the value * @return the value
*/ */
public static ValueLob2 create(int type, LobStorage lobStorage, String fileName, long id, long precision) { public static ValueLobDb create(int type, LobStorage lobStorage, String fileName, int tableId, long id, long precision) {
return new ValueLob2(type, lobStorage, fileName, LobStorage.TABLE_ID_SESSION_VARIABLE, id, precision); return new ValueLobDb(type, lobStorage, fileName, tableId, id, precision);
} }
/** /**
...@@ -82,8 +83,8 @@ public class ValueLob2 extends Value { ...@@ -82,8 +83,8 @@ public class ValueLob2 extends Value {
* @param precision the precision * @param precision the precision
* @return the lob value * @return the lob value
*/ */
public static ValueLob2 createSmallLob(int type, byte[] small, long precision) { public static ValueLobDb createSmallLob(int type, byte[] small, long precision) {
return new ValueLob2(type, small, precision); return new ValueLobDb(type, small, precision);
} }
/** /**
...@@ -141,12 +142,21 @@ public class ValueLob2 extends Value { ...@@ -141,12 +142,21 @@ public class ValueLob2 extends Value {
public Value link(DataHandler h, int tabId) { public Value link(DataHandler h, int tabId) {
if (small == null) { if (small == null) {
if (tabId != tableId) { if (tabId != tableId) {
if (tableId != LobStorage.TABLE_ID_SESSION_VARIABLE) { if (tableId != LobStorage.TABLE_TEMP) {
throw DbException.throwInternalError(); return lobStorage.copyLob(type, lobId, tabId, getPrecision());
} }
lobStorage.setTable(lobId, tabId); lobStorage.setTable(lobId, tabId);
this.tableId = tabId; this.tableId = tabId;
} }
} else if (small.length > h.getMaxLengthInplaceLob()) {
LobStorage s = h.getLobStorage();
Value v;
if (type == Value.BLOB) {
v = s.createBlob(getInputStream(), getPrecision());
} else {
v = s.createClob(getReader(), getPrecision());
}
return v.link(h, tabId);
} }
return this; return this;
} }
...@@ -335,7 +345,7 @@ public class ValueLob2 extends Value { ...@@ -335,7 +345,7 @@ public class ValueLob2 extends Value {
* *
* @return the value * @return the value
*/ */
public ValueLob2 copyToTemp() { public ValueLobDb copyToTemp() {
return this; return this;
} }
...@@ -359,7 +369,7 @@ public class ValueLob2 extends Value { ...@@ -359,7 +369,7 @@ public class ValueLob2 extends Value {
* @param handler the data handler * @param handler the data handler
* @return the lob value * @return the lob value
*/ */
public static ValueLob2 createTempClob(Reader in, long length, DataHandler handler) { public static ValueLobDb createTempClob(Reader in, long length, DataHandler handler) {
try { try {
boolean compress = handler.getLobCompressionAlgorithm(Value.CLOB) != null; boolean compress = handler.getLobCompressionAlgorithm(Value.CLOB) != null;
long remaining = Long.MAX_VALUE; long remaining = Long.MAX_VALUE;
...@@ -379,9 +389,9 @@ public class ValueLob2 extends Value { ...@@ -379,9 +389,9 @@ public class ValueLob2 extends Value {
} }
if (len <= handler.getMaxLengthInplaceLob()) { if (len <= handler.getMaxLengthInplaceLob()) {
byte[] small = StringUtils.utf8Encode(new String(buff, 0, len)); byte[] small = StringUtils.utf8Encode(new String(buff, 0, len));
return ValueLob2.createSmallLob(Value.CLOB, small, len); return ValueLobDb.createSmallLob(Value.CLOB, small, len);
} }
ValueLob2 lob = new ValueLob2(Value.CLOB, null, 0); ValueLobDb lob = new ValueLobDb(Value.CLOB, null, 0);
lob.createTempFromReader(buff, len, in, remaining, handler); lob.createTempFromReader(buff, len, in, remaining, handler);
return lob; return lob;
} catch (IOException e) { } catch (IOException e) {
...@@ -397,7 +407,7 @@ public class ValueLob2 extends Value { ...@@ -397,7 +407,7 @@ public class ValueLob2 extends Value {
* @param handler the data handler * @param handler the data handler
* @return the lob value * @return the lob value
*/ */
public static ValueLob2 createTempBlob(InputStream in, long length, DataHandler handler) { public static ValueLobDb createTempBlob(InputStream in, long length, DataHandler handler) {
try { try {
long remaining = Long.MAX_VALUE; long remaining = Long.MAX_VALUE;
boolean compress = handler.getLobCompressionAlgorithm(Value.BLOB) != null; boolean compress = handler.getLobCompressionAlgorithm(Value.BLOB) != null;
...@@ -416,9 +426,9 @@ public class ValueLob2 extends Value { ...@@ -416,9 +426,9 @@ public class ValueLob2 extends Value {
if (len <= handler.getMaxLengthInplaceLob()) { if (len <= handler.getMaxLengthInplaceLob()) {
byte[] small = Utils.newBytes(len); byte[] small = Utils.newBytes(len);
System.arraycopy(buff, 0, small, 0, len); System.arraycopy(buff, 0, small, 0, len);
return ValueLob2.createSmallLob(Value.BLOB, small, small.length); return ValueLobDb.createSmallLob(Value.BLOB, small, small.length);
} }
ValueLob2 lob = new ValueLob2(Value.BLOB, null, 0); ValueLobDb lob = new ValueLobDb(Value.BLOB, null, 0);
lob.createTempFromStream(buff, len, in, remaining, handler); lob.createTempFromStream(buff, len, in, remaining, handler);
return lob; return lob;
} catch (IOException e) { } catch (IOException e) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论