http://groups.google.com/group/h2-database/browse_thread/thread/4feb31b18179a44b
http://groups.google.com/group/h2-database/browse_thread/thread/706872a45c32031d
I'm confused by Thomas' statement that H2 closes the LOB when the
ResultSet is closed. The JDBC4 spec says on page 138:
"Note – The closing of a ResultSet object does not close the Blob,
Clob, NClob or SQLXML objects created by the ResultSet. Blob, Clob,
NClob and SQLXML objects remain valid for at least the duration of the
transation in which they are created, unless their free method is
invoked."
It's certainly true that all (?) DBMS close the LOB when the
transaction ends but this is the first time I'm hearing that closing a
ResultSet invalidates the LOBs.
I'm seeing the following error on a Hibernate test:
[main ] FINE - 14:24:54,501 -
bernate.jdbc.ConnectionManager: opening JDBC connection
[main ] FINE - 14:24:54,501 - org.hibernate.SQL:
/* load org.jpwh.model.advanced.Item */ select
item0_.id as id0_0_,
item0_.description as descript2_0_0_,
item0_.imageBlob as imageBlob0_0_
from
Item item0_
where
item0_.id=?
[main ] FINEST - 14:24:54,502 -
hibernate.jdbc.AbstractBatcher: preparing statement
[main ] FINEST - 14:24:54,504 -
ype.descriptor.sql.BasicBinder: binding parameter [1] as [BIGINT] -
1000
[main ] FINEST - 14:24:54,505 -
org.hibernate.loader.Loader: Bound [2] parameters total
[main ] FINE - 14:24:54,509 -
hibernate.jdbc.AbstractBatcher: about to open ResultSet (open
ResultSets: 0, globally: 0)
[main ] FINEST - 14:24:54,509 -
org.hibernate.loader.Loader: processing result set
[main ] FINE - 14:24:54,509 -
org.hibernate.loader.Loader: result set row: 0
[main ] FINE - 14:24:54,510 -
org.hibernate.loader.Loader: result row:
EntityKey[org.jpwh.model.advanced.Item#1000]
[main ] FINEST - 14:24:54,510 -
org.hibernate.loader.Loader: Initializing object from ResultSet:
[org.jpwh.model.advanced.Item#1000]
[main ] FINEST - 14:24:54,511 -
entity.AbstractEntityPersister: Hydrating entity:
[org.jpwh.model.advanced.Item#1000]
[main ] FINEST - 14:24:54,513
- .descriptor.sql.BasicExtractor: found [This is some description.] as
column [descript2_0_0_]
[main ] FINEST - 14:24:54,518
- .descriptor.sql.BasicExtractor: found [blob0: CAST(REPEAT('00',
131072) AS BINARY /* table: 0 id: 0 */)] as column [imageBlob0_0_]
[main ] FINEST - 14:24:54,519 -
org.hibernate.loader.Loader: done processing result set (1 rows)
[main ] FINE - 14:24:54,519 -
hibernate.jdbc.AbstractBatcher: about to close ResultSet (open
ResultSets: 1, globally: 1)
[main ] FINE - 14:24:54,521 -
hibernate.jdbc.AbstractBatcher: about to close PreparedStatement (open
PreparedStatements: 1, globally: 1)
[main ] FINEST - 14:24:54,521 -
hibernate.jdbc.AbstractBatcher: closing statement
[main ] FINEST - 14:24:54,522 -
org.hibernate.loader.Loader: total objects hydrated: 1
[main ] FINE - 14:24:54,522
- .hibernate.engine.TwoPhaseLoad: resolving associations for
[org.jpwh.model.advanced.Item#1000]
[main ] FINE - 14:24:54,522
- .hibernate.engine.TwoPhaseLoad: done materializing entity
[org.jpwh.model.advanced.Item#1000]
[main ] FINE - 14:24:54,523 -
ine.StatefulPersistenceContext: initializing non-lazy collections
[main ] FINE - 14:24:54,523 -
org.hibernate.loader.Loader: done entity load
[main ] FINEST - 14:24:54,523 -
org.hibernate.impl.SessionImpl: setting cache mode to: NORMAL
#### NOW I'M TRIGGERING THE MATERIALIZATION OF THE BLOB THROUGH
HIBERNATE. THE FOLLOWING LINES ARE IN A finally{} BLOCK AND EXECUTED
AFTER THE EXCEPTION! ####
[main ] FINEST - 14:24:54,538 -
n.HibernateSynchronizationImpl: JTA sync : afterCompletion(4)
[main ] FINEST - 14:24:54,539 -
ronization.CallbackCoordinator: transaction after completion callback
[status=4]
[main ] FINEST - 14:24:54,539 -
org.hibernate.jdbc.JDBCContext: after transaction completion
[main ] FINE - 14:24:54,539 -
bernate.jdbc.ConnectionManager: aggressively releasing JDBC connection
[main ] FINE - 14:24:54,539 -
bernate.jdbc.ConnectionManager: releasing JDBC connection [ (open
PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
[main ] FINEST - 14:24:54,539 -
org.hibernate.impl.SessionImpl: after transaction completion
org.h2.jdbc.JdbcSQLException: File not found: "/private/var/folders/6g/
6gmKY4DQH5qiRof2QSZWok+++TI/-Tmp-/
h2.temp.de157a94a4c6fd40.1.temp.db" [90124-162]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:
329)
at org.h2.message.DbException.get(DbException.java:169)
at org.h2.message.DbException.get(DbException.java:146)
at org.h2.engine.SessionRemote.openFile(SessionRemote.java:634)
at org.h2.value.ValueLobDb.getInputStream(ValueLobDb.java:275)
at org.h2.jdbc.JdbcBlob.getBinaryStream(JdbcBlob.java:154)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:
39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:
25)
at java.lang.reflect.Method.invoke(Method.java:597)
at
org.hibernate.engine.jdbc.SerializableBlobProxy.invoke(SerializableBlobProxy.java:
74)
at $Proxy21.getBinaryStream(Unknown Source)
at
org.jpwh.test.advanced.LazyProperties.storeLoadLocator(LazyProperties.java:
101)
I'm using "jdbc:h2:tcp://localhost/mem:test", same error with
"jdbc:h2:tcp://localhost/test". However, everything works with
"jdbc:h2:mem:test".
public static void main(String args[]) throws Exception {
Connection conn = DriverManager.getConnection("jdbc:derby:test;create=true");
//Connection conn = DriverManager.getConnection("jdbc:h2:tcp://localhost/mem:test", "sa", "");
conn.createStatement().executeUpdate("drop table ITEM");
//conn.createStatement().executeUpdate("drop table if exists ITEM");
conn.createStatement().executeUpdate("create table ITEM (FOO blob)");
conn.setAutoCommit(false);
// INSERT
PreparedStatement statement = conn.prepareStatement("insert into ITEM (FOO) values (?)");
byte[] bytes = new byte[131072];
new Random().nextBytes(bytes);
statement.setBinaryStream(1, new ByteArrayInputStream(bytes));
int result = statement.executeUpdate();
assert result == 1;
statement.close();
conn.commit();
// SELECT
ResultSet rs = conn.createStatement().executeQuery("select * from ITEM");
Blob blob = null;
while(rs.next()) {
blob = rs.getBlob(1);
// Works
//assert blob != null;
//bytes = blob.getBytes(1, (int)blob.length());
//assert bytes.length == 131072;
}
// Failure A
//assert blob != null;
//bytes = blob.getBytes(1, (int)blob.length());
//assert bytes.length == 131072;
rs.close();
// Failure B
//assert blob != null;
//bytes = blob.getBytes(1, (int)blob.length());
//assert bytes.length == 131072;
conn.commit();
// Failure C
//assert blob != null;
//bytes = blob.getBytes(1, (int)blob.length());
//assert bytes.length == 131072;
conn.close();
}
Expected is that Failure A and B pass, as they do on Derby. H2 seems to restrict the validity of the blob to the iteration of the ResultSet, not even the open/close status of the ResultSet. It should use the transaction scope.
--
You received this message because you are subscribed to the Google Groups "H2 Database" group.
To post to this group, send email to h2-da...@googlegroups.com.
To unsubscribe from this group, send email to h2-database...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/h2-database?hl=en.
This bug is now fixed in the trunk. Thanks for reporting this issue,
and thanks a lot for the test case!
Regards,
Thomas
--
You received this message because you are subscribed to the Google Groups "H2 Database" group.
To view this discussion on the web visit https://groups.google.com/d/msg/h2-database/-/5UdHSqdD-1oJ.