提交 7a163bbc authored 作者: noelgrandin's avatar noelgrandin

New feature from Davide Cavestro - allow using custom Java object serialization…

New feature from Davide Cavestro - allow using custom Java object serialization engines on a per-DB basis.
上级 85e74dd1
...@@ -1207,6 +1207,26 @@ This setting can be appended to the database URL: ""jdbc:h2:test;IGNORECASE=TRUE ...@@ -1207,6 +1207,26 @@ This setting can be appended to the database URL: ""jdbc:h2:test;IGNORECASE=TRUE
SET IGNORECASE TRUE SET IGNORECASE TRUE
" "
"Commands (Other)","SET JAVA_OBJECT_SERIALIZER","
SET JAVA_OBJECT_SERIALIZER
{ null | className }
","
Sets the object used to serialize and deserialize java objects being stored in column of type OTHER.
The serializer class must be public and implement ""org.h2.api.JavaObjectSerializer"".
Inner classes are not supported.
The class must be available in the classpath of the database engine
(when using the server mode, it must be both in the classpath of the server and the client).
This command can only be executed if there are no tables defined.
Admin rights are required to execute this command.
This command commits an open transaction.
This setting is persistent.
This setting can be appended to the database URL: ""jdbc:h2:test;JAVA_OBJECT_SERIALIZER='com.acme.SerializerClassName'""
","
SET JAVA_OBJECT_SERIALIZER 'com.acme.SerializerClassName'
"
"Commands (Other)","SET LOG"," "Commands (Other)","SET LOG","
SET LOG int SET LOG int
"," ","
......
...@@ -80,6 +80,8 @@ Advanced ...@@ -80,6 +80,8 @@ Advanced
Split File System</a><br /> Split File System</a><br />
<a href="#database_upgrade"> <a href="#database_upgrade">
Database Upgrade</a><br /> Database Upgrade</a><br />
<a href="#java_objects_serialization">
Java Objects Serialization</a><br />
<a href="#limits_limitations"> <a href="#limits_limitations">
Limits and Limitations</a><br /> Limits and Limitations</a><br />
<a href="#glossary_links"> <a href="#glossary_links">
...@@ -1566,6 +1568,32 @@ Please note the old driver did not process the system property <code>"h2.baseDir ...@@ -1566,6 +1568,32 @@ Please note the old driver did not process the system property <code>"h2.baseDir
so that using this setting is not supported when upgrading. so that using this setting is not supported when upgrading.
</p> </p>
<h2 id="java_objects_serialization">Java Objects Serialization</h2>
<p>
Java objects serialization is enabled by default for columns of type <code>OTHER</code>, using standard Java serialization/deserialization semantics.
</p>
<p>
To disable this feature set the system property <code>h2.serializeJavaObject=false</code> (default: true).
</p>
<p>
Serialization and deserialization of java objects is customizable both at system level and at database level providing a <a href="../javadoc/org/h2/api/JavaObjectSerializer.html">JavaObjectSerializer</a> implementation:
<ul>
<li>
At system level set the system property <code>h2.javaObjectSerializer</code> with the
Fully Qualified Name of the <code>JavaObjectSerializer</code> interface implementation.
It will be used over the entire JVM session to (de)serialize java objects being stored in column of type OTHER.
Example <code>h2.javaObjectSerializer=com.acme.SerializerClassName</code>.
</li>
<li>
At database level execute the SQL statement <code>SET JAVA_OBJECT_SERIALIZER 'com.acme.SerializerClassName'</code>
or append <code>;JAVA_OBJECT_SERIALIZER='com.acme.SerializerClassName'</code> to the database URL: <code>jdbc:h2:~/test;JAVA_OBJECT_SERIALIZER='com.acme.SerializerClassName'</code>.
<p>
Please note that this SQL statement can only be executed before any tables are defined.
</p>
</li>
</ul>
</p>
<h2 id="limits_limitations">Limits and Limitations</h2> <h2 id="limits_limitations">Limits and Limitations</h2>
<p> <p>
This database has the following known limitations: This database has the following known limitations:
......
...@@ -26,6 +26,8 @@ Change Log ...@@ -26,6 +26,8 @@ Change Log
e.g. where the one was INT and the other was LONG e.g. where the one was INT and the other was LONG
</li><li>Bug: Changes to the database structure did not result </li><li>Bug: Changes to the database structure did not result
in the Session query cache being invalidated. in the Session query cache being invalidated.
</li><li>New feature from Davide Cavestro - allow using custom Java object serialization
engines on a per-DB basis.
</li></ul> </li></ul>
<h2>Version 1.3.173 (2013-07-28)</h2> <h2>Version 1.3.173 (2013-07-28)</h2>
......
...@@ -159,6 +159,7 @@ ...@@ -159,6 +159,7 @@
90138=Invalid database name: {0} 90138=Invalid database name: {0}
90139=The public static Java method was not found: {0} 90139=The public static Java method was not found: {0}
90140=The result set is readonly. You may need to use conn.createStatement(.., ResultSet.CONCUR_UPDATABLE). 90140=The result set is readonly. You may need to use conn.createStatement(.., ResultSet.CONCUR_UPDATABLE).
90141=Serializer cannot be changed because there is a data table: {0}
HY000=General error: {0} HY000=General error: {0}
HY004=Unknown data type: {0} HY004=Unknown data type: {0}
HYC00=Feature not supported: {0} HYC00=Feature not supported: {0}
......
...@@ -4716,6 +4716,9 @@ public class Parser { ...@@ -4716,6 +4716,9 @@ public class Parser {
list.toArray(schemaNames); list.toArray(schemaNames);
command.setStringArray(schemaNames); command.setStringArray(schemaNames);
return command; return command;
} else if (readIf("JAVA_OBJECT_SERIALIZER")) {
readIfEqualOrTo();
return parseSetJavaObjectSerializer();
} else { } else {
if (isToken("LOGSIZE")) { if (isToken("LOGSIZE")) {
// HSQLDB compatibility // HSQLDB compatibility
...@@ -4775,6 +4778,13 @@ public class Parser { ...@@ -4775,6 +4778,13 @@ public class Parser {
throw DbException.getInvalidValueException("BINARY_COLLATION", name); throw DbException.getInvalidValueException("BINARY_COLLATION", name);
} }
private Set parseSetJavaObjectSerializer() {
Set command = new Set(session, SetTypes.JAVA_OBJECT_SERIALIZER);
String name = readString();
command.setString(name);
return command;
}
private RunScriptCommand parseRunScript() { private RunScriptCommand parseRunScript() {
RunScriptCommand command = new RunScriptCommand(session); RunScriptCommand command = new RunScriptCommand(session);
read("FROM"); read("FROM");
......
...@@ -12,6 +12,7 @@ import java.io.IOException; ...@@ -12,6 +12,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.sql.Connection; import java.sql.Connection;
import org.h2.api.JavaObjectSerializer;
import org.h2.command.Prepared; import org.h2.command.Prepared;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties; import org.h2.constant.SysProperties;
...@@ -258,4 +259,8 @@ abstract class ScriptBase extends Prepared implements DataHandler { ...@@ -258,4 +259,8 @@ abstract class ScriptBase extends Prepared implements DataHandler {
throw DbException.throwInternalError(); throw DbException.throwInternalError();
} }
@Override
public JavaObjectSerializer getJavaObjectSerializer() {
return session.getDataHandler().getJavaObjectSerializer();
}
} }
...@@ -220,6 +220,16 @@ public class Set extends Prepared { ...@@ -220,6 +220,16 @@ public class Set extends Prepared {
} }
break; break;
} }
case SetTypes.JAVA_OBJECT_SERIALIZER: {
session.getUser().checkAdmin();
Table table = database.getFirstUserTable();
if (table != null) {
throw DbException.get(ErrorCode.JAVA_OBJECT_SERIALIZER_CHANGE_WITH_DATA_TABLE, table.getSQL());
}
database.setJavaObjectSerializerFQN (stringValue);
addOrUpdateSetting(name, stringValue, 0);
break;
}
case SetTypes.IGNORECASE: case SetTypes.IGNORECASE:
session.getUser().checkAdmin(); session.getUser().checkAdmin();
database.setIgnoreCase(getIntValue() == 1); database.setIgnoreCase(getIntValue() == 1);
......
...@@ -200,10 +200,15 @@ public class SetTypes { ...@@ -200,10 +200,15 @@ public class SetTypes {
public static final int REDO_LOG_BINARY = 37; public static final int REDO_LOG_BINARY = 37;
/** /**
* The type of a SET BINARY_COLLATION statement. * The type of a SET BINARY_COLLATION statement.
*/ */
public static final int BINARY_COLLATION = 38; public static final int BINARY_COLLATION = 38;
/**
* The type of a SET JAVA_OBJECT_SERIALIZER statement.
*/
public static final int JAVA_OBJECT_SERIALIZER = 39;
private static final ArrayList<String> TYPES = New.arrayList(); private static final ArrayList<String> TYPES = New.arrayList();
private SetTypes() { private SetTypes() {
...@@ -251,6 +256,7 @@ public class SetTypes { ...@@ -251,6 +256,7 @@ public class SetTypes {
list.add(QUERY_TIMEOUT, "QUERY_TIMEOUT"); list.add(QUERY_TIMEOUT, "QUERY_TIMEOUT");
list.add(REDO_LOG_BINARY, "REDO_LOG_BINARY"); list.add(REDO_LOG_BINARY, "REDO_LOG_BINARY");
list.add(BINARY_COLLATION, "BINARY_COLLATION"); list.add(BINARY_COLLATION, "BINARY_COLLATION");
list.add(JAVA_OBJECT_SERIALIZER, "JAVA_OBJECT_SERIALIZER");
} }
/** /**
......
...@@ -1860,8 +1860,18 @@ public class ErrorCode { ...@@ -1860,8 +1860,18 @@ public class ErrorCode {
*/ */
public static final int RESULT_SET_READONLY = 90140; public static final int RESULT_SET_READONLY = 90140;
/**
* The error with code <code>90141</code> is thrown when
* trying to change the java object serializer while there was already data in
* the database. The serializer of the database must be set when the
* database is empty.
*/
public static final int JAVA_OBJECT_SERIALIZER_CHANGE_WITH_DATA_TABLE = 90141;
// next are 90006, 90009, 90010, 90011, 90021, 90039, // next are 90006, 90009, 90010, 90011, 90021, 90039,
// 90051, 90056, 90110, 90122, 90141 // 90051, 90056, 90110, 90122, 90142
private ErrorCode() { private ErrorCode() {
// utility class // utility class
......
...@@ -12,6 +12,7 @@ import java.util.Arrays; ...@@ -12,6 +12,7 @@ import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Properties; import java.util.Properties;
import org.h2.command.dml.SetTypes; import org.h2.command.dml.SetTypes;
import org.h2.constant.DbSettings; import org.h2.constant.DbSettings;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
...@@ -602,7 +603,7 @@ public class ConnectionInfo implements Cloneable { ...@@ -602,7 +603,7 @@ public class ConnectionInfo implements Cloneable {
this.name = serverKey; this.name = serverKey;
} }
DbSettings getDbSettings() { public DbSettings getDbSettings() {
DbSettings defaultSettings = DbSettings.getInstance(null); DbSettings defaultSettings = DbSettings.getInstance(null);
HashMap<String, String> s = null; HashMap<String, String> s = null;
for (Object k : prop.keySet()) { for (Object k : prop.keySet()) {
......
...@@ -15,8 +15,8 @@ import java.util.HashSet; ...@@ -15,8 +15,8 @@ import java.util.HashSet;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import org.h2.api.DatabaseEventListener; import org.h2.api.DatabaseEventListener;
import org.h2.api.JavaObjectSerializer;
import org.h2.command.ddl.CreateTableData; import org.h2.command.ddl.CreateTableData;
import org.h2.command.dml.SetTypes; import org.h2.command.dml.SetTypes;
import org.h2.constant.DbSettings; import org.h2.constant.DbSettings;
...@@ -178,6 +178,10 @@ public class Database implements DataHandler { ...@@ -178,6 +178,10 @@ public class Database implements DataHandler {
private MVTableEngine.Store mvStore; private MVTableEngine.Store mvStore;
private DbException backgroundException; private DbException backgroundException;
private JavaObjectSerializer javaObjectSerializer;
private String javaObjectSerializerFQN;
private volatile boolean javaObjectSerializerInitialized;
public Database(ConnectionInfo ci, String cipher) { public Database(ConnectionInfo ci, String cipher) {
String name = ci.getName(); String name = ci.getName();
this.dbSettings = ci.getDbSettings(); this.dbSettings = ci.getDbSettings();
...@@ -212,6 +216,8 @@ public class Database implements DataHandler { ...@@ -212,6 +216,8 @@ public class Database implements DataHandler {
} }
this.multiVersion = ci.getProperty("MVCC", false); this.multiVersion = ci.getProperty("MVCC", false);
this.logMode = ci.getProperty("LOG", PageStore.LOG_MODE_SYNC); this.logMode = ci.getProperty("LOG", PageStore.LOG_MODE_SYNC);
this.javaObjectSerializerFQN = ci.getProperty("JAVA_OBJECT_SERIALIZER", null);
boolean closeAtVmShutdown = dbSettings.dbCloseOnExit; boolean closeAtVmShutdown = dbSettings.dbCloseOnExit;
int traceLevelFile = ci.getIntProperty(SetTypes.TRACE_LEVEL_FILE, TraceSystem.DEFAULT_TRACE_LEVEL_FILE); int traceLevelFile = ci.getIntProperty(SetTypes.TRACE_LEVEL_FILE, TraceSystem.DEFAULT_TRACE_LEVEL_FILE);
int traceLevelSystemOut = ci.getIntProperty(SetTypes.TRACE_LEVEL_SYSTEM_OUT, int traceLevelSystemOut = ci.getIntProperty(SetTypes.TRACE_LEVEL_SYSTEM_OUT,
...@@ -2498,4 +2504,39 @@ public class Database implements DataHandler { ...@@ -2498,4 +2504,39 @@ public class Database implements DataHandler {
return filePasswordHash; return filePasswordHash;
} }
@Override
public JavaObjectSerializer getJavaObjectSerializer() {
initJavaObjectSerializer();
return javaObjectSerializer;
}
private void initJavaObjectSerializer() {
if (javaObjectSerializerInitialized) {
return;
}
synchronized (this) {
if (javaObjectSerializerInitialized) {
return;
}
String serializerFQN = javaObjectSerializerFQN;
if (serializerFQN != null) {
serializerFQN = serializerFQN.trim();
if (!serializerFQN.isEmpty() && !serializerFQN.equals("null")) {
try {
javaObjectSerializer = (JavaObjectSerializer) Utils.loadUserClass(serializerFQN).newInstance();
} catch (Exception e) {
throw DbException.convert(e);
}
}
}
javaObjectSerializerInitialized = true;
}
}
public void setJavaObjectSerializerFQN(String javaObjectSerializerFQN) {
this.javaObjectSerializerFQN = javaObjectSerializerFQN;
synchronized (this) {
javaObjectSerializerInitialized = false;
}
}
} }
...@@ -11,6 +11,7 @@ import java.net.Socket; ...@@ -11,6 +11,7 @@ import java.net.Socket;
import java.sql.Connection; import java.sql.Connection;
import java.util.ArrayList; import java.util.ArrayList;
import org.h2.api.DatabaseEventListener; import org.h2.api.DatabaseEventListener;
import org.h2.api.JavaObjectSerializer;
import org.h2.command.CommandInterface; import org.h2.command.CommandInterface;
import org.h2.command.CommandRemote; import org.h2.command.CommandRemote;
import org.h2.command.dml.SetTypes; import org.h2.command.dml.SetTypes;
...@@ -20,6 +21,7 @@ import org.h2.jdbc.JdbcSQLException; ...@@ -20,6 +21,7 @@ import org.h2.jdbc.JdbcSQLException;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.message.Trace; import org.h2.message.Trace;
import org.h2.message.TraceSystem; import org.h2.message.TraceSystem;
import org.h2.result.ResultInterface;
import org.h2.store.DataHandler; import org.h2.store.DataHandler;
import org.h2.store.FileStore; import org.h2.store.FileStore;
import org.h2.store.LobStorageFrontend; import org.h2.store.LobStorageFrontend;
...@@ -33,6 +35,7 @@ import org.h2.util.StringUtils; ...@@ -33,6 +35,7 @@ import org.h2.util.StringUtils;
import org.h2.util.TempFileDeleter; import org.h2.util.TempFileDeleter;
import org.h2.util.Utils; import org.h2.util.Utils;
import org.h2.value.Transfer; import org.h2.value.Transfer;
import org.h2.value.Value;
/** /**
* The client side part of a session when using the server mode. This object * The client side part of a session when using the server mode. This object
...@@ -87,6 +90,9 @@ public class SessionRemote extends SessionWithState implements DataHandler { ...@@ -87,6 +90,9 @@ public class SessionRemote extends SessionWithState implements DataHandler {
private boolean cluster; private boolean cluster;
private TempFileDeleter tempFileDeleter; private TempFileDeleter tempFileDeleter;
private JavaObjectSerializer javaObjectSerializer;
private volatile boolean javaObjectSerializerInitialized;
public SessionRemote(ConnectionInfo ci) { public SessionRemote(ConnectionInfo ci) {
this.connectionInfo = ci; this.connectionInfo = ci;
} }
...@@ -749,4 +755,52 @@ public class SessionRemote extends SessionWithState implements DataHandler { ...@@ -749,4 +755,52 @@ public class SessionRemote extends SessionWithState implements DataHandler {
return 1; return 1;
} }
@Override
public JavaObjectSerializer getJavaObjectSerializer() {
initJavaObjectSerializer();
return javaObjectSerializer;
}
private void initJavaObjectSerializer() {
if (javaObjectSerializerInitialized) {
return;
}
synchronized (this) {
if (javaObjectSerializerInitialized) {
return;
}
String serializerFQN = readSerializationSettings();
if (serializerFQN != null) {
serializerFQN = serializerFQN.trim();
if (!serializerFQN.isEmpty() && !serializerFQN.equals("null")) {
try {
javaObjectSerializer = (JavaObjectSerializer) Utils.loadUserClass(serializerFQN).newInstance();
} catch (Exception e) {
throw DbException.convert(e);
}
}
}
javaObjectSerializerInitialized = true;
}
}
/**
* Read needed persistent db settings
*/
private String readSerializationSettings () {
String javaObjectSerializerFQN = null;
CommandInterface ci = prepareCommand(
"SELECT * FROM INFORMATION_SCHEMA.SETTINGS "+
" WHERE NAME='JAVA_OBJECT_SERIALIZER'", Integer.MAX_VALUE);
try {
ResultInterface result = ci.executeQuery(0, false);
if (result.next()) {
Value[] row = result.currentRow();
javaObjectSerializerFQN = row[1].getString();
}
} finally {
ci.close();
}
return javaObjectSerializerFQN;
}
} }
...@@ -1833,7 +1833,7 @@ public class JdbcConnection extends TraceObject implements Connection { ...@@ -1833,7 +1833,7 @@ public class JdbcConnection extends TraceObject implements Connection {
} }
case Value.JAVA_OBJECT: case Value.JAVA_OBJECT:
if (SysProperties.serializeJavaObject) { if (SysProperties.serializeJavaObject) {
o = Utils.deserialize(v.getBytesNoCopy()); o = Utils.deserialize(v.getBytesNoCopy(), session.getDataHandler());
break; break;
} }
default: default:
......
...@@ -580,7 +580,7 @@ public class ValueDataType implements DataType { ...@@ -580,7 +580,7 @@ public class ValueDataType implements DataType {
int len = readVarInt(buff); int len = readVarInt(buff);
byte[] b = DataUtils.newBytes(len); byte[] b = DataUtils.newBytes(len);
buff.get(b, 0, len); buff.get(b, 0, len);
return ValueJavaObject.getNoCopy(null, b); return ValueJavaObject.getNoCopy(null, b, handler);
} }
case Value.UUID: case Value.UUID:
return ValueUuid.get(buff.getLong(), buff.getLong()); return ValueUuid.get(buff.getLong(), buff.getLong());
......
...@@ -159,6 +159,7 @@ ...@@ -159,6 +159,7 @@
90138=Invalid database name: {0} 90138=Invalid database name: {0}
90139=The public static Java method was not found: {0} 90139=The public static Java method was not found: {0}
90140=The result set is readonly. You may need to use conn.createStatement(.., ResultSet.CONCUR_UPDATABLE). 90140=The result set is readonly. You may need to use conn.createStatement(.., ResultSet.CONCUR_UPDATABLE).
90141=Serializer cannot be changed because there is a data table: {0}
HY000=General error: {0} HY000=General error: {0}
HY004=Unknown data type: {0} HY004=Unknown data type: {0}
HYC00=Feature not supported: {0} HYC00=Feature not supported: {0}
......
...@@ -387,6 +387,11 @@ SET IGNORECASE { TRUE | FALSE } ...@@ -387,6 +387,11 @@ SET IGNORECASE { TRUE | FALSE }
"," ","
If IGNORECASE is enabled, text columns in newly created tables will be If IGNORECASE is enabled, text columns in newly created tables will be
case-insensitive." case-insensitive."
"Commands (Other)","SET JAVA_OBJECT_SERIALIZER","
SET JAVA_OBJECT_SERIALIZER
{ null | className }
","
Sets the object used to serialize and deserialize java objects being stored in column of type OTHER."
"Commands (Other)","SET LOG"," "Commands (Other)","SET LOG","
SET LOG int SET LOG int
"," ","
......
...@@ -772,7 +772,7 @@ public class Data { ...@@ -772,7 +772,7 @@ public class Data {
int len = readVarInt(); int len = readVarInt();
byte[] b = DataUtils.newBytes(len); byte[] b = DataUtils.newBytes(len);
read(b, 0, len); read(b, 0, len);
return ValueJavaObject.getNoCopy(null, b); return ValueJavaObject.getNoCopy(null, b, handler);
} }
case Value.UUID: case Value.UUID:
return ValueUuid.get(readLong(), readLong()); return ValueUuid.get(readLong(), readLong());
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
package org.h2.store; package org.h2.store;
import java.sql.Connection; import java.sql.Connection;
import org.h2.api.JavaObjectSerializer;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.util.SmallLRUCache; import org.h2.util.SmallLRUCache;
import org.h2.util.TempFileDeleter; import org.h2.util.TempFileDeleter;
...@@ -112,4 +113,12 @@ public interface DataHandler { ...@@ -112,4 +113,12 @@ public interface DataHandler {
*/ */
int readLob(long lobId, byte[] hmac, long offset, byte[] buff, int off, int length); int readLob(long lobId, byte[] hmac, long offset, byte[] buff, int off, int length);
/**
* Return the serializer to be used for java objects being stored in
* column of type OTHER.
*
* @return the serializer to be used for java objects being stored in
* column of type OTHER
*/
JavaObjectSerializer getJavaObjectSerializer();
} }
...@@ -23,6 +23,7 @@ import java.util.HashSet; ...@@ -23,6 +23,7 @@ import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.zip.CRC32; import java.util.zip.CRC32;
import org.h2.api.JavaObjectSerializer;
import org.h2.compress.CompressLZF; import org.h2.compress.CompressLZF;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.engine.DbObject; import org.h2.engine.DbObject;
...@@ -1536,4 +1537,8 @@ public class Recover extends Tool implements DataHandler { ...@@ -1536,4 +1537,8 @@ public class Recover extends Tool implements DataHandler {
throw DbException.throwInternalError(); throw DbException.throwInternalError();
} }
@Override
public JavaObjectSerializer getJavaObjectSerializer() {
return null;
}
} }
...@@ -28,6 +28,7 @@ import org.h2.api.JavaObjectSerializer; ...@@ -28,6 +28,7 @@ import org.h2.api.JavaObjectSerializer;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties; import org.h2.constant.SysProperties;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.store.DataHandler;
/** /**
* This utility class contains miscellaneous functions. * This utility class contains miscellaneous functions.
...@@ -331,9 +332,31 @@ public class Utils { ...@@ -331,9 +332,31 @@ public class Utils {
* *
* @param obj the object to serialize * @param obj the object to serialize
* @return the byte array * @return the byte array
*
* @deprecated use {@link #serialize(Object, DataHandler)} instead
*/ */
@Deprecated
public static byte[] serialize(Object obj) { public static byte[] serialize(Object obj) {
return serialize(obj, null);
}
/**
* Serialize the object to a byte array, eventually using the serializer
* specified by the connection info.
*
* @param obj the object to serialize
* @param dataHandler provides the object serializer (may be null)
* @return the byte array
*/
public static byte[] serialize(Object obj, DataHandler dataHandler) {
try { try {
JavaObjectSerializer dbJavaObjectSerializer = null;
if (dataHandler != null) {
dbJavaObjectSerializer = dataHandler.getJavaObjectSerializer();
}
if (dbJavaObjectSerializer != null) {
return dbJavaObjectSerializer.serialize(obj);
}
if (serializer != null) { if (serializer != null) {
return serializer.serialize(obj); return serializer.serialize(obj);
} }
...@@ -352,9 +375,32 @@ public class Utils { ...@@ -352,9 +375,32 @@ public class Utils {
* @param data the byte array * @param data the byte array
* @return the object * @return the object
* @throws DbException if serialization fails * @throws DbException if serialization fails
*
* @deprecated use {@link #deserialize(byte[], DataHandler)} instead
*/ */
@Deprecated
public static Object deserialize(byte[] data) { public static Object deserialize(byte[] data) {
return deserialize(data, null);
}
/**
* De-serialize the byte array to an object, eventually using the serializer
* specified by the connection info.
*
* @param data the byte array
* @param dataHandler provides the object serializer (may be null)
* @return the object
* @throws DbException if serialization fails
*/
public static Object deserialize(byte[] data, DataHandler dataHandler) {
try { try {
JavaObjectSerializer dbJavaObjectSerializer = null;
if (dataHandler != null) {
dbJavaObjectSerializer = dataHandler.getJavaObjectSerializer();
}
if (dbJavaObjectSerializer != null) {
return dbJavaObjectSerializer.deserialize(data);
}
if (serializer != null) { if (serializer != null) {
return serializer.deserialize(data); return serializer.deserialize(data);
} }
......
...@@ -586,10 +586,10 @@ public class DataType { ...@@ -586,10 +586,10 @@ public class DataType {
case Value.JAVA_OBJECT: { case Value.JAVA_OBJECT: {
if (SysProperties.serializeJavaObject) { if (SysProperties.serializeJavaObject) {
byte[] buff = rs.getBytes(columnIndex); byte[] buff = rs.getBytes(columnIndex);
v = buff == null ? ValueNull.INSTANCE : ValueJavaObject.getNoCopy(null, buff); v = buff == null ? ValueNull.INSTANCE : ValueJavaObject.getNoCopy(null, buff, session.getDataHandler());
} else { } else {
Object o = rs.getObject(columnIndex); Object o = rs.getObject(columnIndex);
v = o == null ? ValueNull.INSTANCE : ValueJavaObject.getNoCopy(o, null); v = o == null ? ValueNull.INSTANCE : ValueJavaObject.getNoCopy(o, null, session.getDataHandler());
} }
break; break;
} }
...@@ -884,7 +884,7 @@ public class DataType { ...@@ -884,7 +884,7 @@ public class DataType {
return ValueNull.INSTANCE; return ValueNull.INSTANCE;
} }
if (type == Value.JAVA_OBJECT) { if (type == Value.JAVA_OBJECT) {
return ValueJavaObject.getNoCopy(x, null); return ValueJavaObject.getNoCopy(x, null, session.getDataHandler());
} }
if (x instanceof String) { if (x instanceof String) {
return ValueString.get((String) x); return ValueString.get((String) x);
...@@ -957,7 +957,7 @@ public class DataType { ...@@ -957,7 +957,7 @@ public class DataType {
} else if (isGeometry(x)) { } else if (isGeometry(x)) {
return ValueGeometry.getFromGeometry(x); return ValueGeometry.getFromGeometry(x);
} else { } else {
return ValueJavaObject.getNoCopy(x, null); return ValueJavaObject.getNoCopy(x, null, session.getDataHandler());
} }
} }
...@@ -1096,7 +1096,8 @@ public class DataType { ...@@ -1096,7 +1096,8 @@ public class DataType {
return new JdbcClob(conn, v, 0); return new JdbcClob(conn, v, 0);
} }
if (v.getType() == Value.JAVA_OBJECT) { if (v.getType() == Value.JAVA_OBJECT) {
Object o = SysProperties.serializeJavaObject ? Utils.deserialize(v.getBytes()) : v.getObject(); Object o = SysProperties.serializeJavaObject ? Utils.deserialize(v.getBytes(),
conn.getSession().getDataHandler()) : v.getObject();
if (paramClass.isAssignableFrom(o.getClass())) { if (paramClass.isAssignableFrom(o.getClass())) {
return o; return o;
} }
......
...@@ -530,7 +530,7 @@ public class Transfer { ...@@ -530,7 +530,7 @@ public class Transfer {
case Value.UUID: case Value.UUID:
return ValueUuid.get(readLong(), readLong()); return ValueUuid.get(readLong(), readLong());
case Value.JAVA_OBJECT: case Value.JAVA_OBJECT:
return ValueJavaObject.getNoCopy(null, readBytes()); return ValueJavaObject.getNoCopy(null, readBytes(), session.getDataHandler());
case Value.BOOLEAN: case Value.BOOLEAN:
return ValueBoolean.get(readBoolean()); return ValueBoolean.get(readBoolean());
case Value.BYTE: case Value.BYTE:
......
...@@ -776,7 +776,7 @@ public abstract class Value { ...@@ -776,7 +776,7 @@ public abstract class Value {
switch(getType()) { switch(getType()) {
case BYTES: case BYTES:
case BLOB: case BLOB:
return ValueJavaObject.getNoCopy(null, getBytesNoCopy()); return ValueJavaObject.getNoCopy(null, getBytesNoCopy(), getDataHandler());
} }
break; break;
} }
...@@ -798,7 +798,7 @@ public abstract class Value { ...@@ -798,7 +798,7 @@ public abstract class Value {
case BYTES: case BYTES:
return ValueGeometry.get(getBytesNoCopy()); return ValueGeometry.get(getBytesNoCopy());
case JAVA_OBJECT: case JAVA_OBJECT:
Object object = Utils.deserialize(getBytesNoCopy()); Object object = Utils.deserialize(getBytesNoCopy(), getDataHandler());
if (DataType.isGeometry(object)) { if (DataType.isGeometry(object)) {
return ValueGeometry.getFromGeometry(object); return ValueGeometry.getFromGeometry(object);
} }
...@@ -844,7 +844,7 @@ public abstract class Value { ...@@ -844,7 +844,7 @@ public abstract class Value {
case BYTES: case BYTES:
return ValueBytes.getNoCopy(StringUtils.convertHexToBytes(s.trim())); return ValueBytes.getNoCopy(StringUtils.convertHexToBytes(s.trim()));
case JAVA_OBJECT: case JAVA_OBJECT:
return ValueJavaObject.getNoCopy(null, StringUtils.convertHexToBytes(s.trim())); return ValueJavaObject.getNoCopy(null, StringUtils.convertHexToBytes(s.trim()), getDataHandler());
case STRING: case STRING:
return ValueString.get(s); return ValueString.get(s);
case STRING_IGNORECASE: case STRING_IGNORECASE:
...@@ -1099,6 +1099,15 @@ public abstract class Value { ...@@ -1099,6 +1099,15 @@ public abstract class Value {
return rs; return rs;
} }
/**
* Return the data handler for the values that support it
* (actually only Java objects).
* @return the data handler
*/
protected DataHandler getDataHandler() {
return null;
}
/** /**
* A "binary large object". * A "binary large object".
*/ */
......
...@@ -11,6 +11,7 @@ import java.sql.SQLException; ...@@ -11,6 +11,7 @@ import java.sql.SQLException;
import java.sql.Types; import java.sql.Types;
import org.h2.constant.SysProperties; import org.h2.constant.SysProperties;
import org.h2.store.DataHandler;
import org.h2.util.Utils; import org.h2.util.Utils;
/** /**
...@@ -18,10 +19,12 @@ import org.h2.util.Utils; ...@@ -18,10 +19,12 @@ import org.h2.util.Utils;
*/ */
public class ValueJavaObject extends ValueBytes { public class ValueJavaObject extends ValueBytes {
private static final ValueJavaObject EMPTY = new ValueJavaObject(Utils.EMPTY_BYTES); private static final ValueJavaObject EMPTY = new ValueJavaObject(Utils.EMPTY_BYTES, null);
private final DataHandler dataHandler;
protected ValueJavaObject(byte[] v) { protected ValueJavaObject(byte[] v, DataHandler dataHandler) {
super(v); super(v);
this.dataHandler = dataHandler;
} }
/** /**
...@@ -30,20 +33,21 @@ public class ValueJavaObject extends ValueBytes { ...@@ -30,20 +33,21 @@ public class ValueJavaObject extends ValueBytes {
* *
* @param javaObject the object * @param javaObject the object
* @param b the byte array * @param b the byte array
* @param dataHandler provides the object serializer
* @return the value * @return the value
*/ */
public static ValueJavaObject getNoCopy(Object javaObject, byte[] b) { public static ValueJavaObject getNoCopy(Object javaObject, byte[] b, DataHandler dataHandler) {
if (b != null && b.length == 0) { if (b != null && b.length == 0) {
return EMPTY; return EMPTY;
} }
ValueJavaObject obj; ValueJavaObject obj;
if (SysProperties.serializeJavaObject) { if (SysProperties.serializeJavaObject) {
if (b == null) { if (b == null) {
b = Utils.serialize(javaObject); b = Utils.serialize(javaObject, dataHandler);
} }
obj = new ValueJavaObject(b); obj = new ValueJavaObject(b, dataHandler);
} else { } else {
obj = new NotSerialized(javaObject, b); obj = new NotSerialized(javaObject, b, dataHandler);
} }
if (b == null || b.length > SysProperties.OBJECT_CACHE_MAX_PER_ELEMENT_SIZE) { if (b == null || b.length > SysProperties.OBJECT_CACHE_MAX_PER_ELEMENT_SIZE) {
return obj; return obj;
...@@ -58,7 +62,7 @@ public class ValueJavaObject extends ValueBytes { ...@@ -58,7 +62,7 @@ public class ValueJavaObject extends ValueBytes {
@Override @Override
public void set(PreparedStatement prep, int parameterIndex) throws SQLException { public void set(PreparedStatement prep, int parameterIndex) throws SQLException {
Object obj = Utils.deserialize(getBytesNoCopy()); Object obj = Utils.deserialize(getBytesNoCopy(), getDataHandler());
prep.setObject(parameterIndex, obj, Types.JAVA_OBJECT); prep.setObject(parameterIndex, obj, Types.JAVA_OBJECT);
} }
...@@ -74,8 +78,8 @@ public class ValueJavaObject extends ValueBytes { ...@@ -74,8 +78,8 @@ public class ValueJavaObject extends ValueBytes {
private int displaySize = -1; private int displaySize = -1;
NotSerialized(Object javaObject, byte[] v) { NotSerialized(Object javaObject, byte[] v, DataHandler dataHandler) {
super(v); super(v, dataHandler);
this.javaObject = javaObject; this.javaObject = javaObject;
} }
...@@ -87,7 +91,7 @@ public class ValueJavaObject extends ValueBytes { ...@@ -87,7 +91,7 @@ public class ValueJavaObject extends ValueBytes {
@Override @Override
public byte[] getBytesNoCopy() { public byte[] getBytesNoCopy() {
if (value == null) { if (value == null) {
value = Utils.serialize(javaObject); value = Utils.serialize(javaObject, null);
} }
return value; return value;
} }
...@@ -155,7 +159,7 @@ public class ValueJavaObject extends ValueBytes { ...@@ -155,7 +159,7 @@ public class ValueJavaObject extends ValueBytes {
@Override @Override
public Object getObject() { public Object getObject() {
if (javaObject == null) { if (javaObject == null) {
javaObject = Utils.deserialize(value); javaObject = Utils.deserialize(value, getDataHandler());
} }
return javaObject; return javaObject;
} }
...@@ -193,4 +197,9 @@ public class ValueJavaObject extends ValueBytes { ...@@ -193,4 +197,9 @@ public class ValueJavaObject extends ValueBytes {
return this; return this;
} }
} }
@Override
protected DataHandler getDataHandler() {
return dataHandler;
}
} }
...@@ -81,6 +81,7 @@ import org.h2.test.jdbc.TestCancel; ...@@ -81,6 +81,7 @@ import org.h2.test.jdbc.TestCancel;
import org.h2.test.jdbc.TestDatabaseEventListener; import org.h2.test.jdbc.TestDatabaseEventListener;
import org.h2.test.jdbc.TestDriver; import org.h2.test.jdbc.TestDriver;
import org.h2.test.jdbc.TestJavaObject; import org.h2.test.jdbc.TestJavaObject;
import org.h2.test.jdbc.TestJavaObjectSerializer;
import org.h2.test.jdbc.TestLimitUpdates; import org.h2.test.jdbc.TestLimitUpdates;
import org.h2.test.jdbc.TestLobApi; import org.h2.test.jdbc.TestLobApi;
import org.h2.test.jdbc.TestManyJdbcObjects; import org.h2.test.jdbc.TestManyJdbcObjects;
...@@ -91,6 +92,7 @@ import org.h2.test.jdbc.TestResultSet; ...@@ -91,6 +92,7 @@ import org.h2.test.jdbc.TestResultSet;
import org.h2.test.jdbc.TestStatement; import org.h2.test.jdbc.TestStatement;
import org.h2.test.jdbc.TestTransactionIsolation; import org.h2.test.jdbc.TestTransactionIsolation;
import org.h2.test.jdbc.TestUpdatableResultSet; import org.h2.test.jdbc.TestUpdatableResultSet;
import org.h2.test.jdbc.TestUrlJavaObjectSerializer;
import org.h2.test.jdbc.TestZloty; import org.h2.test.jdbc.TestZloty;
import org.h2.test.jdbcx.TestConnectionPool; import org.h2.test.jdbcx.TestConnectionPool;
import org.h2.test.jdbcx.TestDataSource; import org.h2.test.jdbcx.TestDataSource;
...@@ -348,6 +350,8 @@ java org.h2.test.TestAll timer ...@@ -348,6 +350,8 @@ java org.h2.test.TestAll timer
private Server server; private Server server;
public String javaObjectSerializer;
/** /**
* Run all tests. * Run all tests.
* *
...@@ -648,6 +652,9 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1` ...@@ -648,6 +652,9 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
new TestDatabaseEventListener().runTest(this); new TestDatabaseEventListener().runTest(this);
new TestDriver().runTest(this); new TestDriver().runTest(this);
new TestJavaObject().runTest(this); new TestJavaObject().runTest(this);
new TestJavaObjectSerializer().runTest(this);
new TestUrlJavaObjectSerializer().runTest(this);
new TestLimitUpdates().runTest(this); new TestLimitUpdates().runTest(this);
new TestLobApi().runTest(this); new TestLobApi().runTest(this);
new TestManyJdbcObjects().runTest(this); new TestManyJdbcObjects().runTest(this);
......
...@@ -320,6 +320,9 @@ public abstract class TestBase { ...@@ -320,6 +320,9 @@ public abstract class TestBase {
if (config.nestedJoins) { if (config.nestedJoins) {
url = addOption(url, "NESTED_JOINS", "TRUE"); url = addOption(url, "NESTED_JOINS", "TRUE");
} }
if (config.javaObjectSerializer!=null) {
url = addOption(url, "JAVA_OBJECT_SERIALIZER", config.javaObjectSerializer);
}
return "jdbc:h2:" + url; return "jdbc:h2:" + url;
} }
......
...@@ -1394,7 +1394,7 @@ public class TestLob extends TestBase { ...@@ -1394,7 +1394,7 @@ public class TestLob extends TestBase {
private void testJavaObject() throws SQLException { private void testJavaObject() throws SQLException {
deleteDb("lob"); deleteDb("lob");
Connection conn = getConnection("lob"); JdbcConnection conn = (JdbcConnection) getConnection("lob");
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, DATA OTHER)"); stat.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, DATA OTHER)");
PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST VALUES(1, ?)"); PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST VALUES(1, ?)");
...@@ -1413,7 +1413,7 @@ public class TestLob extends TestBase { ...@@ -1413,7 +1413,7 @@ public class TestLob extends TestBase {
conn.createStatement().execute("drop table test"); conn.createStatement().execute("drop table test");
stat.execute("create table test(value other)"); stat.execute("create table test(value other)");
prep = conn.prepareStatement("insert into test values(?)"); prep = conn.prepareStatement("insert into test values(?)");
prep.setObject(1, Utils.serialize("")); prep.setObject(1, Utils.serialize("", conn.getSession().getDataHandler()));
prep.execute(); prep.execute();
rs = stat.executeQuery("select value from test"); rs = stat.executeQuery("select value from test");
while (rs.next()) { while (rs.next()) {
......
...@@ -19,6 +19,7 @@ import org.h2.util.Utils; ...@@ -19,6 +19,7 @@ import org.h2.util.Utils;
* Tests {@link JavaObjectSerializer}. * Tests {@link JavaObjectSerializer}.
* *
* @author Sergi Vladykin * @author Sergi Vladykin
* @author Davide Cavestro
*/ */
public class TestJavaObjectSerializer extends TestBase { public class TestJavaObjectSerializer extends TestBase {
...@@ -39,6 +40,13 @@ public class TestJavaObjectSerializer extends TestBase { ...@@ -39,6 +40,13 @@ public class TestJavaObjectSerializer extends TestBase {
@Override @Override
public void test() throws Exception { public void test() throws Exception {
deleteDb("javaSerializer");
testStaticGlobalSerializer();
testDbLevelJavaObjectSerializer();
deleteDb("javaSerializer");
}
public void testStaticGlobalSerializer() throws Exception {
Utils.serializer = new JavaObjectSerializer() { Utils.serializer = new JavaObjectSerializer() {
@Override @Override
public byte[] serialize(Object obj) throws Exception { public byte[] serialize(Object obj) throws Exception {
...@@ -58,6 +66,7 @@ public class TestJavaObjectSerializer extends TestBase { ...@@ -58,6 +66,7 @@ public class TestJavaObjectSerializer extends TestBase {
try { try {
deleteDb("javaSerializer"); deleteDb("javaSerializer");
Connection conn = getConnection("javaSerializer"); Connection conn = getConnection("javaSerializer");
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
stat.execute("create table t(id identity, val other)"); stat.execute("create table t(id identity, val other)");
...@@ -74,9 +83,65 @@ public class TestJavaObjectSerializer extends TestBase { ...@@ -74,9 +83,65 @@ public class TestJavaObjectSerializer extends TestBase {
assertEquals(100500, ((Integer) rs.getObject(1)).intValue()); assertEquals(100500, ((Integer) rs.getObject(1)).intValue());
assertEquals(new byte[] { 1, 2, 3 }, rs.getBytes(1)); assertEquals(new byte[] { 1, 2, 3 }, rs.getBytes(1));
conn.close();
deleteDb("javaSerializer"); deleteDb("javaSerializer");
} finally { } finally {
Utils.serializer = null; Utils.serializer = null;
} }
} }
/**
* Tests per-db {@link JavaObjectSerializer} when set through the related
* SET command.
*/
public void testDbLevelJavaObjectSerializer() throws Exception {
DbLevelJavaObjectSerializer.testBaseRef = this;
try {
deleteDb("javaSerializer");
Connection conn = getConnection("javaSerializer");
conn.createStatement().execute("SET JAVA_OBJECT_SERIALIZER '"+DbLevelJavaObjectSerializer.class.getName()+"'");
Statement stat = conn.createStatement();
stat.execute("create table t1(id identity, val other)");
PreparedStatement ins = conn.prepareStatement("insert into t1(val) values(?)");
ins.setObject(1, 100500, Types.JAVA_OBJECT);
assertEquals(1, ins.executeUpdate());
Statement s = conn.createStatement();
ResultSet rs = s.executeQuery("select val from t1");
assertTrue(rs.next());
assertEquals(100500, ((Integer) rs.getObject(1)).intValue());
assertEquals(new byte[] { 1, 2, 3 }, rs.getBytes(1));
conn.close();
deleteDb("javaSerializer");
} finally {
DbLevelJavaObjectSerializer.testBaseRef = null;
}
}
public static class DbLevelJavaObjectSerializer implements JavaObjectSerializer {
private static TestBase testBaseRef;
@Override
public byte[] serialize(Object obj) throws Exception {
testBaseRef.assertEquals(100500, ((Integer) obj).intValue());
return new byte[] { 1, 2, 3 };
}
@Override
public Object deserialize(byte[] bytes) throws Exception {
testBaseRef.assertEquals(new byte[] { 1, 2, 3 }, bytes);
return 100500;
}
}
} }
/*
* Copyright 2004-2013 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.test.jdbc;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.Types;
import org.h2.api.JavaObjectSerializer;
import org.h2.test.TestBase;
/**
* Tests per-db {@link JavaObjectSerializer} when set through the JDBC URL.
*
* @author Davide Cavestro
*/
public class TestUrlJavaObjectSerializer extends TestBase {
/**
* Run just this test.
*
* @param a ignored
*/
public static void main(String... a) throws Exception {
TestBase test = createCaller().init();
test.config.traceTest = true;
test.config.memory = true;
test.config.networked = true;
test.config.javaObjectSerializer = FakeJavaObjectSerializer.class.getName();
test.config.beforeTest();
test.test();
test.config.afterTest();
}
@Override
public void test() throws Exception {
FakeJavaObjectSerializer.testBaseRef = this;
try {
deleteDb("javaSerializer");
String fqn = FakeJavaObjectSerializer.class.getName();
Connection conn = getConnection("javaSerializer;JAVA_OBJECT_SERIALIZER='"+fqn+"'");
Statement stat = conn.createStatement();
stat.execute("create table t1(id identity, val other)");
PreparedStatement ins = conn.prepareStatement("insert into t1(val) values(?)");
ins.setObject(1, 100500, Types.JAVA_OBJECT);
assertEquals(1, ins.executeUpdate());
Statement s = conn.createStatement();
ResultSet rs = s.executeQuery("select val from t1");
assertTrue(rs.next());
assertEquals(100500, ((Integer) rs.getObject(1)).intValue());
assertEquals(new byte[] { 1, 2, 3 }, rs.getBytes(1));
conn.close();
deleteDb("javaSerializer");
} finally {
FakeJavaObjectSerializer.testBaseRef = null;
}
}
public static class FakeJavaObjectSerializer implements JavaObjectSerializer {
private static TestBase testBaseRef;
@Override
public byte[] serialize(Object obj) throws Exception {
testBaseRef.assertEquals(100500, ((Integer) obj).intValue());
return new byte[] { 1, 2, 3 };
}
@Override
public Object deserialize(byte[] bytes) throws Exception {
testBaseRef.assertEquals(new byte[] { 1, 2, 3 }, bytes);
return 100500;
}
}
}
...@@ -12,6 +12,7 @@ import java.sql.Date; ...@@ -12,6 +12,7 @@ import java.sql.Date;
import java.sql.Time; import java.sql.Time;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.sql.Types; import java.sql.Types;
import org.h2.api.JavaObjectSerializer;
import org.h2.store.Data; import org.h2.store.Data;
import org.h2.store.DataHandler; import org.h2.store.DataHandler;
import org.h2.store.FileStore; import org.h2.store.FileStore;
...@@ -167,8 +168,8 @@ public class TestDataPage extends TestBase implements DataHandler { ...@@ -167,8 +168,8 @@ public class TestDataPage extends TestBase implements DataHandler {
testValue(ValueTime.get(new Time(0))); testValue(ValueTime.get(new Time(0)));
testValue(ValueTimestamp.get(new Timestamp(System.currentTimeMillis()))); testValue(ValueTimestamp.get(new Timestamp(System.currentTimeMillis())));
testValue(ValueTimestamp.get(new Timestamp(0))); testValue(ValueTimestamp.get(new Timestamp(0)));
testValue(ValueJavaObject.getNoCopy(null, new byte[0])); testValue(ValueJavaObject.getNoCopy(null, new byte[0], this));
testValue(ValueJavaObject.getNoCopy(null, new byte[100])); testValue(ValueJavaObject.getNoCopy(null, new byte[100], this));
for (int i = 0; i < 300; i++) { for (int i = 0; i < 300; i++) {
testValue(ValueBytes.getNoCopy(new byte[i])); testValue(ValueBytes.getNoCopy(new byte[i]));
} }
...@@ -340,4 +341,9 @@ public class TestDataPage extends TestBase implements DataHandler { ...@@ -340,4 +341,9 @@ public class TestDataPage extends TestBase implements DataHandler {
return -1; return -1;
} }
@Override
public JavaObjectSerializer getJavaObjectSerializer() {
return null;
}
} }
...@@ -8,6 +8,7 @@ package org.h2.test.unit; ...@@ -8,6 +8,7 @@ package org.h2.test.unit;
import java.sql.Connection; import java.sql.Connection;
import java.util.Random; import java.util.Random;
import org.h2.api.JavaObjectSerializer;
import org.h2.store.DataHandler; import org.h2.store.DataHandler;
import org.h2.store.FileStore; import org.h2.store.FileStore;
import org.h2.store.LobStorageBackend; import org.h2.store.LobStorageBackend;
...@@ -194,4 +195,9 @@ public class TestFile extends TestBase implements DataHandler { ...@@ -194,4 +195,9 @@ public class TestFile extends TestBase implements DataHandler {
return -1; return -1;
} }
@Override
public JavaObjectSerializer getJavaObjectSerializer() {
return null;
}
} }
...@@ -45,7 +45,7 @@ public class TestObjectDeserialization extends TestBase { ...@@ -45,7 +45,7 @@ public class TestObjectDeserialization extends TestBase {
usesThreadContextClassLoader = false; usesThreadContextClassLoader = false;
Thread.currentThread().setContextClassLoader(new TestClassLoader()); Thread.currentThread().setContextClassLoader(new TestClassLoader());
try { try {
Utils.deserialize(StringUtils.convertHexToBytes(OBJECT)); Utils.deserialize(StringUtils.convertHexToBytes(OBJECT), null);
fail(); fail();
} catch (DbException e) { } catch (DbException e) {
// expected // expected
......
...@@ -12,6 +12,7 @@ import java.util.Collections; ...@@ -12,6 +12,7 @@ import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.Random; import java.util.Random;
import org.h2.api.JavaObjectSerializer;
import org.h2.store.DataHandler; import org.h2.store.DataHandler;
import org.h2.store.FileStore; import org.h2.store.FileStore;
import org.h2.store.LobStorageBackend; import org.h2.store.LobStorageBackend;
...@@ -171,4 +172,8 @@ public class TestValueHashMap extends TestBase implements DataHandler { ...@@ -171,4 +172,8 @@ public class TestValueHashMap extends TestBase implements DataHandler {
return -1; return -1;
} }
@Override
public JavaObjectSerializer getJavaObjectSerializer() {
return null;
}
} }
...@@ -14,6 +14,7 @@ import java.sql.SQLException; ...@@ -14,6 +14,7 @@ import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.IdentityHashMap; import java.util.IdentityHashMap;
import java.util.Random; import java.util.Random;
import org.h2.api.JavaObjectSerializer;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.store.DataHandler; import org.h2.store.DataHandler;
import org.h2.store.FileStore; import org.h2.store.FileStore;
...@@ -188,7 +189,7 @@ public class TestValueMemory extends TestBase implements DataHandler { ...@@ -188,7 +189,7 @@ public class TestValueMemory extends TestBase implements DataHandler {
case Value.RESULT_SET: case Value.RESULT_SET:
return ValueResultSet.get(new SimpleResultSet()); return ValueResultSet.get(new SimpleResultSet());
case Value.JAVA_OBJECT: case Value.JAVA_OBJECT:
return ValueJavaObject.getNoCopy(null, randomBytes(random.nextInt(100))); return ValueJavaObject.getNoCopy(null, randomBytes(random.nextInt(100)), this);
case Value.UUID: case Value.UUID:
return ValueUuid.get(random.nextLong(), random.nextLong()); return ValueUuid.get(random.nextLong(), random.nextLong());
case Value.STRING_FIXED: case Value.STRING_FIXED:
...@@ -286,4 +287,8 @@ public class TestValueMemory extends TestBase implements DataHandler { ...@@ -286,4 +287,8 @@ public class TestValueMemory extends TestBase implements DataHandler {
return -1; return -1;
} }
@Override
public JavaObjectSerializer getJavaObjectSerializer() {
return null;
}
} }
...@@ -35,7 +35,7 @@ balance balancing bananas band banking bar barcelona base based baseline basic ...@@ -35,7 +35,7 @@ balance balancing bananas band banking bar barcelona base based baseline basic
basically basis bat batch bbalance bcc bcdfghklmnprstwz bdata bdfghklmnpqrst basically basis bat batch bbalance bcc bcdfghklmnprstwz bdata bdfghklmnpqrst
bdquo beans became because become becomes becoming been before begin beginning bdquo beans became because become becomes becoming been before begin beginning
behalf behave behavior behaviour behind being bel believes belong belongs below behalf behave behavior behaviour behind being bel believes belong belongs below
bench benchmark benchmarks beneficial bennet berlini best beta better between bench benchmark benchmarks beneficial bennet berlini best beta better between beware
beyond bfff bgcolor bid big bigger biggest bigint biginteger billion bin binary beyond bfff bgcolor bid big bigger biggest bigint biginteger billion bin binary
bind biological biondi birth birthday bit bitand bitmap bitor bits bitxor bind biological biondi birth birthday bit bitand bitmap bitor bits bitxor
blank blind blob blobs block blocked blockquote blocks blocksize blog blank blind blob blobs block blocked blockquote blocks blocksize blog
...@@ -52,7 +52,7 @@ calling calls cally camel can cancel canceled cancels cannot canonical cap ...@@ -52,7 +52,7 @@ calling calls cally camel can cancel canceled cancels cannot canonical cap
capabilities capability capacity capone caps capture car cardinality care careful capabilities capability capacity capone caps capture car cardinality care careful
carriage carrier cars cartesian cascade cascading case cases casesensitive carriage carrier cars cartesian cascade cascading case cases casesensitive
casewhen casqueiro cast cat catalog catalogs catch catcher catches caucho cause casewhen casqueiro cast cat catalog catalogs catch catcher catches caucho cause
caused causes cayenne cbc ccc ccedil cdata cdd cddl cdup cedil ceil ceiling cell caused causes cavestro cayenne cbc ccc ccedil cdata cdd cddl cdup cedil ceil ceiling cell
cellpadding cells cellspacing cent center central cert certain certificate cellpadding cells cellspacing cent center central cert certain certificate
certificates certified certs cet cfg cgi chain chained chaining chair challenge certificates certified certs cet cfg cgi chain chained chaining chair challenge
challenger chance change changed changelog changes changing channel channels char challenger chance change changed changelog changes changing channel channels char
...@@ -98,11 +98,11 @@ createtable creating creation creatively credential credit criteria critical crl ...@@ -98,11 +98,11 @@ createtable creating creation creatively credential credit criteria critical crl
cross cruncher crypt cryptographic cryptographically cryptoloop css csv csvread cross cruncher crypt cryptographic cryptographically cryptoloop css csv csvread
csvwrite cte ctid ctor ctrl ctx cuaz cube cup curation curdate cure curly curren csvwrite cte ctid ctor ctrl ctx cuaz cube cup curation curdate cure curly curren
currency current currently currval cursor cursors curtime curtimestamp curve currency current currently currval cursor cursors curtime curtimestamp curve
curves custom customer customerid customers cut cvs cwd cycle cyclic daemon curves custom customizable customer customerid customers cut cvs cwd cycle cyclic daemon
daffodil dagger damage damages dangerous darr darwin dash dashes dat data daffodil dagger damage damages dangerous darr darwin dash dashes dat data
database databaseaccess databases datalink datanamic datapage datasource database databaseaccess databases datalink datanamic datapage datasource
datastore datatype datatypes date dateadd datediff dates datestyle datetime datastore datatype datatypes date dateadd datediff dates datestyle datetime
datetimes datum david day dayname dayofmonth dayofweek dayofyear days dba dbcopy datetimes datum david davide day dayname dayofmonth dayofweek dayofyear days dba dbcopy
dbcopyplugin dbcp dbev dbid dbmonster dbms dbname dbo dbs dbserv ddl ddlutils dbcopyplugin dbcp dbev dbid dbmonster dbms dbname dbo dbs dbserv ddl ddlutils
deadlock deadlocks deal dealing deallocate death debug debugging dec december deadlock deadlocks deal dealing deallocate death debug debugging dec december
decimal deck declaration declaratory declare declared decode decoder decodes decimal deck declaration declaratory declare declared decode decoder decodes
...@@ -171,7 +171,7 @@ floating floor florent flower fluent flush flushed flushes flushing fly focus ...@@ -171,7 +171,7 @@ floating floor florent flower fluent flush flushed flushes flushing fly focus
focusable folder follow followed following follows font foo footer footprint for focusable folder follow followed following follows font foo footer footprint for
forall force forcefully forces forcing foreign forever forge forget forgotten forall force forcefully forces forcing foreign forever forge forget forgotten
form format formatdatetime formats formatted formatting formed forms forth form format formatdatetime formats formatted formatting formed forms forth
forward found foundation four fourth fowler fox frac fractional frame frameborder forward found foundation four fourth fowler fox fqn frac fractional frame frameborder
frames frameset framespacing framework frameworks fran france frank frasl free frames frameset framespacing framework frameworks fran france frank frasl free
freed french frequently fresh freshmeat friendly from front frontend fsutil fsync freed french frequently fresh freshmeat friendly from front frontend fsutil fsync
ftl ftp ftps fukushima fulfill fulfilled fulfils full fulltext fully fulvio fun ftl ftp ftps fukushima fulfill fulfilled fulfils full fulltext fully fulvio fun
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论