提交 5d3a10b2 authored 作者: Thomas Mueller's avatar Thomas Mueller

New LOB storage.

上级 19a80ed5
......@@ -12,8 +12,8 @@ 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;
import org.h2.value.ValueLob;
/**
* This class represents the statement
......@@ -83,7 +83,7 @@ public class DropTable extends SchemaCommand {
table.setModified();
Database db = session.getDatabase();
db.removeSchemaObject(session, table);
ValueLob.removeAllForTable(db, dropTableId);
LobStorage.removeAllForTable(db, dropTableId);
}
if (next != null) {
next.executeDrop();
......
......@@ -24,6 +24,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.LobStorage;
import org.h2.tools.CompressTool;
import org.h2.util.IOUtils;
import org.h2.util.SmallLRUCache;
......@@ -223,4 +224,8 @@ public abstract class ScriptBase extends Prepared implements DataHandler {
return null;
}
public LobStorage getLobStorage() {
return null;
}
}
......@@ -54,7 +54,6 @@ import org.h2.util.StatementBuilder;
import org.h2.util.StringUtils;
import org.h2.util.Utils;
import org.h2.value.Value;
import org.h2.value.ValueLob;
import org.h2.value.ValueString;
/**
......@@ -254,10 +253,10 @@ public class ScriptCommand extends ScriptBase {
if (v.getPrecision() > lobBlockSize) {
int id;
if (v.getType() == Value.CLOB) {
id = writeLobStream((ValueLob) v);
id = writeLobStream(v);
buff.append("SYSTEM_COMBINE_CLOB(" + id + ")");
} else if (v.getType() == Value.BLOB) {
id = writeLobStream((ValueLob) v);
id = writeLobStream(v);
buff.append("SYSTEM_COMBINE_BLOB(" + id + ")");
} else {
buff.append(v.getSQL());
......@@ -328,7 +327,7 @@ public class ScriptCommand extends ScriptBase {
return r;
}
private int writeLobStream(ValueLob v) throws IOException {
private int writeLobStream(Value v) throws IOException {
if (!tempLobTableCreated) {
add("CREATE TABLE IF NOT EXISTS SYSTEM_LOB_STREAM(ID INT NOT NULL, PART INT NOT NULL, CDATA VARCHAR, BDATA BINARY)", true);
add("CREATE PRIMARY KEY SYSTEM_LOB_STREAM_PRIMARY_KEY ON SYSTEM_LOB_STREAM(ID, PART)", true);
......
......@@ -255,6 +255,12 @@ public class SysProperties {
*/
public static final int LOB_FILES_PER_DIRECTORY = getIntSetting("h2.lobFilesPerDirectory", 256);
/**
* System property <code>h2.lobInDatabase</code> (default: false).<br />
* Store LOB files in the database.
*/
public static final boolean LOB_IN_DATABASE = getBooleanSetting("h2.lobInDatabase", false);
/**
* System property <code>h2.logAllErrors</code> (default: false).<br />
* Write stack traces of any kind of error to a file.
......
......@@ -7,6 +7,7 @@
package org.h2.engine;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.BitSet;
......@@ -25,6 +26,7 @@ import org.h2.constraint.Constraint;
import org.h2.index.Cursor;
import org.h2.index.Index;
import org.h2.index.IndexType;
import org.h2.jdbc.JdbcConnection;
import org.h2.message.DbException;
import org.h2.message.Trace;
import org.h2.message.TraceSystem;
......@@ -38,6 +40,7 @@ import org.h2.store.DataHandler;
import org.h2.store.FileLock;
import org.h2.store.FileStore;
import org.h2.store.InDoubtTransaction;
import org.h2.store.LobStorage;
import org.h2.store.PageStore;
import org.h2.store.WriterThread;
import org.h2.store.fs.FileSystemMemory;
......@@ -50,7 +53,6 @@ import org.h2.table.TableLinkConnection;
import org.h2.table.TableView;
import org.h2.tools.DeleteDbFiles;
import org.h2.tools.Server;
import org.h2.util.Utils;
import org.h2.util.IOUtils;
import org.h2.util.NetUtils;
import org.h2.util.New;
......@@ -58,10 +60,10 @@ import org.h2.util.SmallLRUCache;
import org.h2.util.SourceCompiler;
import org.h2.util.StringUtils;
import org.h2.util.TempFileDeleter;
import org.h2.util.Utils;
import org.h2.value.CompareMode;
import org.h2.value.Value;
import org.h2.value.ValueInt;
import org.h2.value.ValueLob;
/**
* There is one database object per open database.
......@@ -164,6 +166,7 @@ public class Database implements DataHandler {
private SourceCompiler compiler;
private boolean metaTablesInitialized;
private boolean flushOnEachCommit;
private LobStorage lobStorage;
public Database(String name, ConnectionInfo ci, String cipher) {
this.compareMode = CompareMode.getInstance(null, 0);
......@@ -1044,7 +1047,7 @@ public class Database implements DataHandler {
// remove all session variables
if (persistent) {
try {
ValueLob.removeAllForTable(this, ValueLob.TABLE_ID_SESSION_VARIABLE);
LobStorage.removeAllForTable(this, LobStorage.TABLE_ID_SESSION_VARIABLE);
} catch (DbException e) {
traceSystem.getTrace(Trace.DATABASE).error("close", e);
}
......@@ -2203,4 +2206,13 @@ public class Database implements DataHandler {
return compiler;
}
public LobStorage getLobStorage() {
if (lobStorage == null) {
String url = Constants.CONN_URL_INTERNAL;
Connection conn = new JdbcConnection(systemSession, systemUser.getName(), url);
lobStorage = new LobStorage(conn);
}
return lobStorage;
}
}
......@@ -28,10 +28,10 @@ import org.h2.result.Row;
import org.h2.schema.Schema;
import org.h2.store.DataHandler;
import org.h2.store.InDoubtTransaction;
import org.h2.store.LobStorage;
import org.h2.table.Table;
import org.h2.util.New;
import org.h2.value.Value;
import org.h2.value.ValueLob;
import org.h2.value.ValueLong;
import org.h2.value.ValueNull;
import org.h2.value.ValueString;
......@@ -81,7 +81,7 @@ public class Session extends SessionWithState implements SessionFactory {
private String currentSchemaName;
private String[] schemaSearchPath;
private String traceModuleName;
private HashMap<String, ValueLob> unlinkMap;
private HashMap<String, Value> unlinkLobMap;
private int systemIdentifier;
private HashMap<String, Procedure> procedures;
private boolean undoLogEnabled = true;
......@@ -144,10 +144,8 @@ public class Session extends SessionWithState implements SessionFactory {
if (value == ValueNull.INSTANCE) {
old = variables.remove(name);
} else {
if (value instanceof ValueLob) {
// link it, to make sure we have our own file
value = value.link(database, ValueLob.TABLE_ID_SESSION_VARIABLE);
}
// link LOB values, to make sure we have our own object
value = value.link(database, LobStorage.TABLE_ID_SESSION_VARIABLE);
old = variables.put(name, value);
}
if (old != null) {
......@@ -476,14 +474,14 @@ public class Session extends SessionWithState implements SessionFactory {
autoCommitAtTransactionEnd = false;
}
}
if (unlinkMap != null && unlinkMap.size() > 0) {
if (unlinkLobMap != null && unlinkLobMap.size() > 0) {
// need to flush the transaction log, because we can't unlink lobs if the
// commit record is not written
database.flush();
for (Value v : unlinkMap.values()) {
for (Value v : unlinkLobMap.values()) {
v.unlink();
}
unlinkMap = null;
unlinkLobMap = null;
}
unlockAll();
}
......@@ -913,14 +911,14 @@ public class Session extends SessionWithState implements SessionFactory {
*
* @param v the value
*/
public void unlinkAtCommit(ValueLob v) {
public void unlinkAtCommit(Value v) {
if (SysProperties.CHECK && !v.isLinked()) {
DbException.throwInternalError();
}
if (unlinkMap == null) {
unlinkMap = New.hashMap();
if (unlinkLobMap == null) {
unlinkLobMap = New.hashMap();
}
unlinkMap.put(v.toString(), v);
unlinkLobMap.put(v.toString(), v);
}
/**
......@@ -929,8 +927,8 @@ public class Session extends SessionWithState implements SessionFactory {
* @param v the value
*/
public void unlinkAtCommitStop(Value v) {
if (unlinkMap != null) {
unlinkMap.remove(v.toString());
if (unlinkLobMap != null) {
unlinkLobMap.remove(v.toString());
}
}
......
......@@ -23,7 +23,7 @@ import org.h2.message.TraceSystem;
import org.h2.result.ResultInterface;
import org.h2.store.DataHandler;
import org.h2.store.FileStore;
import org.h2.util.Utils;
import org.h2.store.LobStorage;
import org.h2.util.IOUtils;
import org.h2.util.MathUtils;
import org.h2.util.NetUtils;
......@@ -31,6 +31,7 @@ import org.h2.util.New;
import org.h2.util.SmallLRUCache;
import org.h2.util.StringUtils;
import org.h2.util.TempFileDeleter;
import org.h2.util.Utils;
import org.h2.value.Transfer;
import org.h2.value.Value;
import org.h2.value.ValueString;
......@@ -95,9 +96,7 @@ public class SessionRemote extends SessionWithState implements SessionFactory, D
trans.setSSL(ci.isSSL());
trans.init();
trans.writeInt(clientVersion);
if (clientVersion >= Constants.TCP_PROTOCOL_VERSION) {
trans.writeInt(clientVersion);
}
trans.writeInt(clientVersion);
trans.writeString(db);
trans.writeString(ci.getOriginalURL());
trans.writeString(ci.getUserName());
......@@ -109,7 +108,7 @@ public class SessionRemote extends SessionWithState implements SessionFactory, D
trans.writeString(key).writeString(ci.getProperty(key));
}
try {
convert(trans);
done(trans);
if (clientVersion >= Constants.TCP_PROTOCOL_VERSION) {
clientVersion = trans.readInt();
}
......@@ -180,7 +179,7 @@ public class SessionRemote extends SessionWithState implements SessionFactory, D
try {
traceOperation("COMMAND_COMMIT", 0);
transfer.writeInt(SessionRemote.COMMAND_COMMIT);
convert(transfer);
done(transfer);
} catch (IOException e) {
removeServer(e, i--, ++count);
}
......@@ -364,7 +363,7 @@ public class SessionRemote extends SessionWithState implements SessionFactory, D
traceOperation("SESSION_SET_ID", 0);
transfer.writeInt(SessionRemote.SESSION_SET_ID);
transfer.writeString(sessionId);
convert(transfer);
done(transfer);
} catch (Exception e) {
trace.error("sessionSetId", e);
}
......@@ -456,7 +455,7 @@ public class SessionRemote extends SessionWithState implements SessionFactory, D
try {
traceOperation("SESSION_CLOSE", 0);
transfer.writeInt(SessionRemote.SESSION_CLOSE);
convert(transfer);
done(transfer);
transfer.close();
} catch (Exception e) {
trace.error("close", e);
......@@ -494,7 +493,7 @@ public class SessionRemote extends SessionWithState implements SessionFactory, D
* @throws IOException if there is a communication problem between client
* and server
*/
public void convert(Transfer transfer) throws IOException {
public void done(Transfer transfer) throws IOException {
transfer.flush();
int status = transfer.readInt();
if (status == STATUS_ERROR) {
......@@ -620,4 +619,8 @@ public class SessionRemote extends SessionWithState implements SessionFactory, D
// nothing to do
}
public LobStorage getLobStorage() {
return null;
}
}
......@@ -34,6 +34,7 @@ import org.h2.schema.Sequence;
import org.h2.security.BlockCipher;
import org.h2.security.CipherFactory;
import org.h2.security.SHA256;
import org.h2.store.LobStorage;
import org.h2.table.Column;
import org.h2.table.ColumnResolver;
import org.h2.table.LinkSchema;
......@@ -41,14 +42,14 @@ import org.h2.table.TableFilter;
import org.h2.tools.CompressTool;
import org.h2.tools.Csv;
import org.h2.util.AutoCloseInputStream;
import org.h2.util.JdbcUtils;
import org.h2.util.Utils;
import org.h2.util.DateTimeUtils;
import org.h2.util.IOUtils;
import org.h2.util.JdbcUtils;
import org.h2.util.MathUtils;
import org.h2.util.New;
import org.h2.util.StatementBuilder;
import org.h2.util.StringUtils;
import org.h2.util.Utils;
import org.h2.value.DataType;
import org.h2.value.Value;
import org.h2.value.ValueArray;
......@@ -57,7 +58,6 @@ import org.h2.value.ValueBytes;
import org.h2.value.ValueDate;
import org.h2.value.ValueDouble;
import org.h2.value.ValueInt;
import org.h2.value.ValueLob;
import org.h2.value.ValueLong;
import org.h2.value.ValueNull;
import org.h2.value.ValueResultSet;
......@@ -1114,7 +1114,7 @@ public class Function extends Expression implements FunctionCall {
try {
InputStream in = new AutoCloseInputStream(IOUtils.openFileInputStream(fileName));
if (blob) {
result = ValueLob.createBlob(in, -1, database);
result = LobStorage.createBlob(in, -1, database);
} else {
Reader reader;
if (v1 == ValueNull.INSTANCE) {
......@@ -1122,7 +1122,7 @@ public class Function extends Expression implements FunctionCall {
} else {
reader = new InputStreamReader(in, v1.getString());
}
result = ValueLob.createClob(reader, -1, database);
result = LobStorage.createClob(reader, -1, database);
}
} catch (IOException e) {
throw DbException.convertIOException(e, fileName);
......
......@@ -13,6 +13,7 @@ import org.h2.message.DbException;
import org.h2.result.Row;
import org.h2.result.SearchRow;
import org.h2.store.Data;
import org.h2.store.LobStorage;
import org.h2.store.Page;
import org.h2.store.PageStore;
import org.h2.table.Column;
......@@ -20,7 +21,6 @@ import org.h2.table.IndexColumn;
import org.h2.table.TableData;
import org.h2.util.MathUtils;
import org.h2.value.Value;
import org.h2.value.ValueLob;
import org.h2.value.ValueNull;
/**
......@@ -218,7 +218,7 @@ public class PageBtreeIndex extends PageIndex {
for (int i = 0; i < row.getColumnCount(); i++) {
Value v = row.getValue(i);
if (v.isLinked()) {
session.unlinkAtCommit((ValueLob) v);
session.unlinkAtCommit(v);
}
}
}
......@@ -253,7 +253,7 @@ public class PageBtreeIndex extends PageIndex {
}
removeAllRows();
if (tableData.getContainsLargeObject()) {
ValueLob.removeAllForTable(database, table.getId());
LobStorage.removeAllForTable(database, table.getId());
}
tableData.setRowCount(0);
}
......
......@@ -19,6 +19,7 @@ import org.h2.message.DbException;
import org.h2.result.Row;
import org.h2.result.SearchRow;
import org.h2.store.Data;
import org.h2.store.LobStorage;
import org.h2.store.Page;
import org.h2.store.PageStore;
import org.h2.table.Column;
......@@ -27,7 +28,6 @@ import org.h2.table.TableData;
import org.h2.util.MathUtils;
import org.h2.util.New;
import org.h2.value.Value;
import org.h2.value.ValueLob;
import org.h2.value.ValueNull;
/**
......@@ -296,7 +296,7 @@ public class PageDataIndex extends PageIndex {
for (int i = 0; i < row.getColumnCount(); i++) {
Value v = row.getValue(i);
if (v.isLinked()) {
session.unlinkAtCommit((ValueLob) v);
session.unlinkAtCommit(v);
}
}
}
......@@ -347,7 +347,7 @@ public class PageDataIndex extends PageIndex {
store.logTruncate(session, tableData.getId());
removeAllRows();
if (tableData.getContainsLargeObject() && tableData.isPersistData()) {
ValueLob.removeAllForTable(database, table.getId());
LobStorage.removeAllForTable(database, table.getId());
}
if (database.isMultiVersion()) {
sessionRowCount.clear();
......
......@@ -18,11 +18,11 @@ import org.h2.engine.UndoLogRecord;
import org.h2.message.DbException;
import org.h2.result.Row;
import org.h2.result.SearchRow;
import org.h2.store.LobStorage;
import org.h2.table.Column;
import org.h2.table.IndexColumn;
import org.h2.table.TableData;
import org.h2.util.New;
import org.h2.value.ValueLob;
/**
* The scan index is not really an 'index' in the strict sense, because it can
......@@ -55,7 +55,7 @@ public class ScanIndex extends BaseIndex {
rows = New.arrayList();
firstFree = -1;
if (tableData.getContainsLargeObject() && tableData.isPersistData()) {
ValueLob.removeAllForTable(database, table.getId());
LobStorage.removeAllForTable(database, table.getId());
}
tableData.setRowCount(0);
rowCount = 0;
......
......@@ -21,7 +21,6 @@ import java.sql.Savepoint;
import java.sql.Statement;
import java.util.Map;
import java.util.Properties;
import org.h2.command.CommandInterface;
import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties;
......@@ -33,11 +32,11 @@ 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;
import org.h2.value.ValueInt;
import org.h2.value.ValueLob;
import org.h2.value.ValueNull;
import org.h2.value.ValueString;
......@@ -1439,7 +1438,7 @@ public class JdbcConnection extends TraceObject implements Connection {
debugCodeAssign("Clob", TraceObject.CLOB, id, "createClob()");
checkClosedForWrite();
try {
ValueLob v = ValueLob.createSmallLob(Value.CLOB, Utils.EMPTY_BYTES);
Value v = LobStorage.createSmallLob(Value.CLOB, Utils.EMPTY_BYTES);
return new JdbcClob(this, v, id);
} finally {
afterWriting();
......@@ -1460,7 +1459,7 @@ public class JdbcConnection extends TraceObject implements Connection {
debugCodeAssign("Blob", TraceObject.BLOB, id, "createClob()");
checkClosedForWrite();
try {
ValueLob v = ValueLob.createSmallLob(Value.BLOB, Utils.EMPTY_BYTES);
Value v = LobStorage.createSmallLob(Value.BLOB, Utils.EMPTY_BYTES);
return new JdbcBlob(this, v, id);
} finally {
afterWriting();
......@@ -1615,7 +1614,7 @@ public class JdbcConnection extends TraceObject implements Connection {
if (length <= 0) {
length = -1;
}
Value v = ValueLob.createClob(x, length, session.getDataHandler());
Value v = LobStorage.createClob(x, length, session.getDataHandler());
return v;
}
......@@ -1634,7 +1633,7 @@ public class JdbcConnection extends TraceObject implements Connection {
if (length <= 0) {
length = -1;
}
Value v = ValueLob.createBlob(x, length, session.getDataHandler());
Value v = LobStorage.createBlob(x, length, session.getDataHandler());
return v;
}
......
......@@ -290,7 +290,8 @@ public class JdbcDatabaseMetaData extends TraceObject implements DatabaseMetaDat
* </ul>
*
* @param catalogPattern null or the catalog name
* @param schemaPattern schema name (must be specified)
* @param schemaPattern null (to get all objects) or a schema name
* (uppercase for unquoted names)
* @param tableName table name (must be specified)
* @param unique only unique indexes
* @param approximate is ignored
......@@ -356,7 +357,8 @@ public class JdbcDatabaseMetaData extends TraceObject implements DatabaseMetaDat
* </ul>
*
* @param catalogPattern null or the catalog name
* @param schemaPattern schema name (must be specified)
* @param schemaPattern null (to get all objects) or a schema name
* (uppercase for unquoted names)
* @param tableName table name (must be specified)
* @return the list of primary key columns
* @throws SQLException if the connection is closed
......@@ -529,7 +531,8 @@ public class JdbcDatabaseMetaData extends TraceObject implements DatabaseMetaDat
* </ul>
*
* @param catalogPattern null or the catalog name
* @param schemaPattern schema name (must be specified)
* @param schemaPattern null (to get all objects) or a schema name
* (uppercase for unquoted names)
* @param procedureNamePattern the procedure name pattern
* @return the procedures
* @throws SQLException if the connection is closed
......@@ -599,7 +602,8 @@ public class JdbcDatabaseMetaData extends TraceObject implements DatabaseMetaDat
* </ul>
*
* @param catalogPattern null or the catalog name
* @param schemaPattern schema name (must be specified)
* @param schemaPattern null (to get all objects) or a schema name
* (uppercase for unquoted names)
* @param procedureNamePattern the procedure name pattern
* @param columnNamePattern the procedure name pattern
* @return the procedure columns
......@@ -867,7 +871,8 @@ public class JdbcDatabaseMetaData extends TraceObject implements DatabaseMetaDat
* </li></ul>
*
* @param catalogPattern null (to get all objects) or the catalog name
* @param schemaPattern schema name (must be specified)
* @param schemaPattern null (to get all objects) or a schema name
* (uppercase for unquoted names)
* @param tableName table name (must be specified)
* @param scope ignored
* @param nullable ignored
......@@ -932,7 +937,8 @@ public class JdbcDatabaseMetaData extends TraceObject implements DatabaseMetaDat
* </li></ul>
*
* @param catalog null (to get all objects) or the catalog name
* @param schema schema name (must be specified)
* @param schemaPattern null (to get all objects) or a schema name
* (uppercase for unquoted names)
* @param tableName table name (must be specified)
* @return an empty result set
* @throws SQLException if the connection is closed
......@@ -1130,12 +1136,12 @@ public class JdbcDatabaseMetaData extends TraceObject implements DatabaseMetaDat
* </ul>
*
* @param primaryCatalogPattern null or the catalog name
* @param primarySchemaPattern the schema name of the primary table (must be
* specified)
* @param primarySchemaPattern the schema name of the primary table
* (optional)
* @param primaryTable the name of the primary table (must be specified)
* @param foreignCatalogPattern null or the catalog name
* @param foreignSchemaPattern the schema name of the foreign table (must be
* specified)
* @param foreignSchemaPattern the schema name of the foreign table
* (optional)
* @param foreignTable the name of the foreign table (must be specified)
* @return the result set
* @throws SQLException if the connection is closed
......
......@@ -80,8 +80,7 @@ public class DbException extends RuntimeException {
params[i] = StringUtils.quoteIdentifier(s);
}
}
Object[] o = params;
message = MessageFormat.format(message, o);
message = MessageFormat.format(message, (Object[]) params);
}
return message;
}
......
......@@ -15,7 +15,6 @@ import org.h2.store.Data;
import org.h2.store.FileStore;
import org.h2.util.New;
import org.h2.value.Value;
import org.h2.value.ValueLob;
/**
* A list of rows. If the list grows too large, it is buffered to disk
......@@ -29,7 +28,7 @@ public class RowList {
private int index, listIndex;
private FileStore file;
private Data rowBuff;
private ArrayList<ValueLob> lobs;
private ArrayList<Value> lobs;
private int memory, maxMemory;
private boolean written;
private boolean readUncached;
......@@ -65,17 +64,15 @@ public class RowList {
if (v.getType() == Value.CLOB || v.getType() == Value.BLOB) {
// need to keep a reference to temporary lobs,
// otherwise the temp file is deleted
ValueLob lob = (ValueLob) v;
if (lob.getSmall() == null && lob.getTableId() == 0) {
if (v.getSmall() == null && v.getTableId() == 0) {
if (lobs == null) {
lobs = New.arrayList();
}
// need to create a copy, otherwise,
// if stored multiple times, it may be renamed
// and then not found
lob = lob.copyToTemp();
lobs.add(lob);
v = lob;
v = v.copyToTemp();
lobs.add(v);
}
}
buff.checkCapacity(buff.getValueLen(v));
......@@ -182,11 +179,10 @@ public class RowList {
} else {
v = buff.readValue();
if (v.isLinked()) {
ValueLob lob = (ValueLob) v;
// the table id is 0 if it was linked when writing
// a temporary entry
if (lob.getTableId() == 0) {
session.unlinkAtCommit(lob);
if (v.getTableId() == 0) {
session.unlinkAtCommit(v);
}
}
}
......
......@@ -65,10 +65,14 @@ public class TcpServerThread implements Runnable {
// TODO server: should support a list of allowed databases
// and a list of allowed clients
try {
clientVersion = transfer.readInt();
if (!server.allow(transfer.getSocket())) {
throw DbException.get(ErrorCode.REMOTE_CONNECTION_NOT_ALLOWED);
}
clientVersion = transfer.readInt();
if (clientVersion < Constants.TCP_PROTOCOL_VERSION) {
throw DbException.get(ErrorCode.DRIVER_VERSION_ERROR_2, "current client version: " +
clientVersion + "; minimum version: " + Constants.TCP_PROTOCOL_VERSION);
}
// max version (currently not used)
transfer.readInt();
String db = transfer.readString();
......
......@@ -653,7 +653,7 @@ public class Data {
if (smallLen >= 0) {
byte[] small = Utils.newBytes(smallLen);
read(small, 0, smallLen);
return ValueLob.createSmallLob(type, small);
return LobStorage.createSmallLob(type, small);
}
int tableId = readVarInt();
int objectId = readVarInt();
......
......@@ -91,4 +91,6 @@ public interface DataHandler {
*/
SmallLRUCache<String, String[]> getLobFileListCache();
LobStorage getLobStorage();
}
差异被折叠。
......@@ -1423,7 +1423,7 @@ public class PageStore implements CacheWriter {
int key = index.getId() + 1;
Row row = metaIndex.getRow(session, key);
if (row.getKey() != key) {
DbException.throwInternalError();
throw DbException.get(ErrorCode.FILE_CORRUPTED_1, "key: " + key + " index: " + index + " row: " + row);
}
metaIndex.remove(session, row);
}
......
......@@ -15,6 +15,7 @@ import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.BitSet;
......@@ -38,11 +39,11 @@ import org.h2.store.DataReader;
import org.h2.store.FileLister;
import org.h2.store.FileStore;
import org.h2.store.FileStoreInputStream;
import org.h2.store.LobStorage;
import org.h2.store.Page;
import org.h2.store.PageFreeList;
import org.h2.store.PageLog;
import org.h2.store.PageStore;
import org.h2.util.Utils;
import org.h2.util.IOUtils;
import org.h2.util.IntArray;
import org.h2.util.MathUtils;
......@@ -51,8 +52,10 @@ import org.h2.util.SmallLRUCache;
import org.h2.util.StatementBuilder;
import org.h2.util.TempFileDeleter;
import org.h2.util.Tool;
import org.h2.util.Utils;
import org.h2.value.Value;
import org.h2.value.ValueLob;
import org.h2.value.ValueLob2;
import org.h2.value.ValueLong;
/**
......@@ -149,6 +152,21 @@ public class Recover extends Tool implements DataHandler {
return new BufferedInputStream(IOUtils.openFileInputStream(fileName));
}
/**
* INTERNAL
*/
public static Reader readClobDb(Connection conn, long lobId) throws IOException {
return new BufferedReader(new InputStreamReader(readBlobDb(conn, lobId), "UTF-8"));
}
/**
* INTERNAL
*/
public static InputStream readBlobDb(Connection conn, long lobId) throws IOException {
return new BufferedInputStream(new LobStorage.LobInputStream(conn, lobId));
}
private void trace(String message) {
if (trace) {
out.println(message);
......@@ -272,6 +290,16 @@ public class Recover extends Tool implements DataHandler {
}
return "READ_CLOB('" + file + ".txt')";
}
} else if (v instanceof ValueLob2) {
ValueLob2 lob = (ValueLob2) v;
byte[] small = lob.getSmall();
if (small == null) {
long id = lob.getLobId();
if (lob.getType() == Value.BLOB) {
return "READ_BLOB_DB(" + id + ")";
}
return "READ_CLOB_DB(" + id + ")";
}
}
return v.getSQL();
}
......@@ -292,6 +320,8 @@ public class Recover extends Tool implements DataHandler {
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_CLOB_DB FOR \"" + this.getClass().getName() + ".readClobDb\";");
writer.println("CREATE ALIAS IF NOT EXISTS READ_BLOB_DB FOR \"" + this.getClass().getName() + ".readBlobDb\";");
resetSchema();
store = FileStore.open(null, fileName, remove ? "rw" : "r");
long length = store.length();
......@@ -1184,4 +1214,11 @@ public class Recover extends Tool implements DataHandler {
return TempFileDeleter.getInstance();
}
/**
* INTERNAL
*/
public LobStorage getLobStorage() {
return null;
}
}
......@@ -30,6 +30,7 @@ import org.h2.jdbc.JdbcBlob;
import org.h2.jdbc.JdbcClob;
import org.h2.jdbc.JdbcConnection;
import org.h2.message.DbException;
import org.h2.store.LobStorage;
import org.h2.util.Utils;
import org.h2.util.New;
import org.h2.util.StringUtils;
......@@ -539,23 +540,23 @@ public class DataType {
}
case Value.CLOB: {
if (session == null) {
v = ValueLob.createSmallLob(Value.CLOB, StringUtils.utf8Encode(rs.getString(columnIndex)));
v = LobStorage.createSmallLob(Value.CLOB, StringUtils.utf8Encode(rs.getString(columnIndex)));
} else {
Reader in = rs.getCharacterStream(columnIndex);
if (in == null) {
v = ValueNull.INSTANCE;
} else {
v = ValueLob.createClob(new BufferedReader(in), -1, session.getDataHandler());
v = LobStorage.createClob(new BufferedReader(in), -1, session.getDataHandler());
}
}
break;
}
case Value.BLOB: {
if (session == null) {
v = ValueLob.createSmallLob(Value.BLOB, rs.getBytes(columnIndex));
v = LobStorage.createSmallLob(Value.BLOB, rs.getBytes(columnIndex));
} else {
InputStream in = rs.getBinaryStream(columnIndex);
v = (in == null) ? (Value) ValueNull.INSTANCE : ValueLob.createBlob(in, -1, session.getDataHandler());
v = (in == null) ? (Value) ValueNull.INSTANCE : LobStorage.createBlob(in, -1, session.getDataHandler());
}
break;
}
......@@ -863,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 ValueLob.createClob(r, -1, session.getDataHandler());
return LobStorage.createClob(r, -1, session.getDataHandler());
} else if (x instanceof java.sql.Clob) {
try {
Reader r = new BufferedReader(((java.sql.Clob) x).getCharacterStream());
return ValueLob.createClob(r, -1, session.getDataHandler());
return LobStorage.createClob(r, -1, session.getDataHandler());
} catch (SQLException e) {
throw DbException.convert(e);
}
} else if (x instanceof java.io.InputStream) {
return ValueLob.createBlob((java.io.InputStream) x, -1, session.getDataHandler());
return LobStorage.createBlob((java.io.InputStream) x, -1, session.getDataHandler());
} else if (x instanceof java.sql.Blob) {
try {
return ValueLob.createBlob(((java.sql.Blob) x).getBinaryStream(), -1, session.getDataHandler());
return LobStorage.createBlob(((java.sql.Blob) x).getBinaryStream(), -1, session.getDataHandler());
} catch (SQLException e) {
throw DbException.convert(e);
}
......
......@@ -29,6 +29,7 @@ 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;
......@@ -483,7 +484,7 @@ public class Transfer {
return ValueStringFixed.get(readString());
case Value.BLOB: {
long length = readLong();
ValueLob v = ValueLob.createBlob(in, length, session.getDataHandler());
Value v = LobStorage.createBlob(in, length, session.getDataHandler());
int magic = readInt();
if (magic != LOB_MAGIC) {
throw DbException.get(ErrorCode.CONNECTION_BROKEN_1, "magic=" + magic);
......@@ -492,7 +493,7 @@ public class Transfer {
}
case Value.CLOB: {
long length = readLong();
ValueLob v = ValueLob.createClob(new ExactUTF8InputStreamReader(in), length, session.getDataHandler());
Value v = LobStorage.createClob(new ExactUTF8InputStreamReader(in), length, session.getDataHandler());
int magic = readInt();
if (magic != LOB_MAGIC) {
throw DbException.get(ErrorCode.CONNECTION_BROKEN_1, "magic=" + magic);
......
......@@ -21,10 +21,11 @@ import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties;
import org.h2.message.DbException;
import org.h2.store.DataHandler;
import org.h2.store.LobStorage;
import org.h2.tools.SimpleResultSet;
import org.h2.util.Utils;
import org.h2.util.IOUtils;
import org.h2.util.StringUtils;
import org.h2.util.Utils;
/**
* This is the base class for all value classes.
......@@ -705,7 +706,7 @@ public abstract class Value {
case BLOB: {
switch(getType()) {
case BYTES:
return ValueLob.createSmallLob(Value.BLOB, getBytesNoCopy());
return LobStorage.createSmallLob(Value.BLOB, getBytesNoCopy());
}
break;
}
......@@ -763,9 +764,9 @@ public abstract class Value {
case FLOAT:
return ValueFloat.get(Float.parseFloat(s.trim()));
case CLOB:
return ValueLob.createSmallLob(CLOB, StringUtils.utf8Encode(s));
return LobStorage.createSmallLob(CLOB, StringUtils.utf8Encode(s));
case BLOB:
return ValueLob.createSmallLob(BLOB, Utils.convertStringToBytes(s.trim()));
return LobStorage.createSmallLob(BLOB, Utils.convertStringToBytes(s.trim()));
case ARRAY:
return ValueArray.get(new Value[]{ValueString.get(s)});
case RESULT_SET: {
......@@ -978,4 +979,16 @@ public abstract class Value {
throw DbException.getUnsupportedException(DataType.getDataType(getType()).name);
}
public int getTableId() {
return 0;
}
public byte[] getSmall() {
return null;
}
public Value copyToTemp() {
return this;
}
}
......@@ -48,11 +48,6 @@ public class ValueLob extends Value {
// (to create a large blob from pieces)
// and a getpart function (to get it in pieces) and make sure a file is created!
/**
* The 'table id' to use for session variables.
*/
public static final int TABLE_ID_SESSION_VARIABLE = -1;
/**
* This counter is used to calculate the next directory to store lobs. It is
* better than using a random number because less directories are created.
......
差异被折叠。
......@@ -118,6 +118,7 @@ import org.h2.test.unit.TestIntArray;
import org.h2.test.unit.TestIntIntHashMap;
import org.h2.test.unit.TestMathUtils;
import org.h2.test.unit.TestNetUtils;
import org.h2.test.unit.TestOldVersion;
import org.h2.test.unit.TestOverflow;
import org.h2.test.unit.TestPageStore;
import org.h2.test.unit.TestPattern;
......@@ -292,6 +293,15 @@ java org.h2.test.TestAll timer
power failure test: larger binaries and additional index.
drop table test;
create table test(id identity, name varchar(100) default space(100));
@LOOP 10 insert into test select null, null from system_range(1, 100000);
delete from test;
insert 50,000,000 tuples into table
2. execute 'delete table where (always true)'
compatibility test for tcp/ip
rename Page* classes
move classes to the right packages
......@@ -400,6 +410,8 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
memory = true;
test();
memory = false;
networked = false;
diskUndo = true;
diskResult = true;
traceLevelFile = 3;
......@@ -568,6 +580,7 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
new TestIntArray().runTest(this);
new TestIntIntHashMap().runTest(this);
new TestMathUtils().runTest(this);
new TestOldVersion().runTest(this);
new TestNetUtils().runTest(this);
new TestMultiThreadedKernel().runTest(this);
new TestOverflow().runTest(this);
......
......@@ -1150,30 +1150,15 @@ public abstract class TestBase {
*/
protected void eatMemory(int remainingKB) {
byte[] reserve = new byte[remainingKB * 1024];
int max = 128 * 1024 * 1024;
int div = 2;
while (true) {
long free = Runtime.getRuntime().freeMemory();
long freeTry = free / div;
int eat = (int) Math.min(max, freeTry);
try {
byte[] block = new byte[eat];
memory.add(block);
} catch (OutOfMemoryError e) {
if (eat < 32) {
// first, eat memory in 16 KB blocks, then eat in 16 byte blocks
for (int size = 16 * 1024; size > 0; size /= 1024) {
while (true) {
try {
byte[] block = new byte[16 * 1024];
memory.add(block);
} catch (OutOfMemoryError e) {
break;
}
if (eat == max) {
max /= 2;
if (max < 128) {
break;
}
}
if (eat == freeTry) {
div += 1;
} else {
div = 2;
}
}
}
// silly code - makes sure there are no warnings
......
......@@ -32,8 +32,8 @@ public class TestCompatibility extends TestBase {
public void test() throws SQLException {
deleteDb("compatibility");
conn = getConnection("compatibility");
conn = getConnection("compatibility");
testDomain();
testColumnAlias();
testUniqueIndexSingleNull();
......
......@@ -13,6 +13,7 @@ import java.sql.Timestamp;
import org.h2.store.Data;
import org.h2.store.DataHandler;
import org.h2.store.FileStore;
import org.h2.store.LobStorage;
import org.h2.test.TestBase;
import org.h2.util.SmallLRUCache;
import org.h2.util.TempFileDeleter;
......@@ -304,4 +305,8 @@ public class TestDataPage extends TestBase implements DataHandler {
return TempFileDeleter.getInstance();
}
public LobStorage getLobStorage() {
return null;
}
}
......@@ -9,6 +9,7 @@ package org.h2.test.unit;
import java.util.Random;
import org.h2.store.DataHandler;
import org.h2.store.FileStore;
import org.h2.store.LobStorage;
import org.h2.test.TestBase;
import org.h2.util.IOUtils;
import org.h2.util.SmallLRUCache;
......@@ -169,4 +170,8 @@ public class TestFile extends TestBase implements DataHandler {
return TempFileDeleter.getInstance();
}
public LobStorage getLobStorage() {
return null;
}
}
......@@ -13,6 +13,7 @@ import java.util.HashMap;
import java.util.Random;
import org.h2.store.DataHandler;
import org.h2.store.FileStore;
import org.h2.store.LobStorage;
import org.h2.test.TestBase;
import org.h2.util.New;
import org.h2.util.SmallLRUCache;
......@@ -147,4 +148,8 @@ public class TestValueHashMap extends TestBase implements DataHandler {
return TempFileDeleter.getInstance();
}
public LobStorage getLobStorage() {
return null;
}
}
......@@ -15,10 +15,11 @@ import java.util.IdentityHashMap;
import java.util.Random;
import org.h2.store.DataHandler;
import org.h2.store.FileStore;
import org.h2.store.LobStorage;
import org.h2.test.TestBase;
import org.h2.util.Utils;
import org.h2.util.SmallLRUCache;
import org.h2.util.TempFileDeleter;
import org.h2.util.Utils;
import org.h2.value.Value;
import org.h2.value.ValueArray;
import org.h2.value.ValueBoolean;
......@@ -30,7 +31,6 @@ import org.h2.value.ValueDouble;
import org.h2.value.ValueFloat;
import org.h2.value.ValueInt;
import org.h2.value.ValueJavaObject;
import org.h2.value.ValueLob;
import org.h2.value.ValueLong;
import org.h2.value.ValueNull;
import org.h2.value.ValueShort;
......@@ -137,12 +137,12 @@ public class TestValueMemory extends TestBase implements DataHandler {
case Value.BLOB: {
int len = (int) Math.abs(random.nextGaussian() * 10);
byte[] data = randomBytes(len);
return ValueLob.createBlob(new ByteArrayInputStream(data), len, this);
return LobStorage.createBlob(new ByteArrayInputStream(data), len, this);
}
case Value.CLOB: {
int len = (int) Math.abs(random.nextGaussian() * 10);
String s = randomString(len);
return ValueLob.createClob(new StringReader(s), len, this);
return LobStorage.createClob(new StringReader(s), len, this);
}
case Value.ARRAY: {
int len = random.nextInt(20);
......@@ -226,4 +226,8 @@ public class TestValueMemory extends TestBase implements DataHandler {
return TempFileDeleter.getInstance();
}
public LobStorage getLobStorage() {
return null;
}
}
......@@ -532,6 +532,10 @@ public class Build extends BuildBase {
* Compile and run all tests.
*/
public void test() {
// for TestOldVersion
download("ext/h2-1.2.127.jar",
"http://repo1.maven.org/maven2/com/h2database/h2/1.2.127/h2-1.2.127.jar",
"056e784c7cf009483366ab9cd8d21d02fe47031a");
compile();
java("org.h2.test.TestAll", null);
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论