HHH-7984 - Oracle callable statement closing
Conflicts: hibernate-core/src/main/java/org/hibernate/loader/Loader.java hibernate-core/src/main/java/org/hibernate/loader/entity/DynamicBatchingEntityLoaderBuilder.java
This commit is contained in:
parent
2fb5a9292d
commit
62cea68007
|
@ -370,14 +370,15 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void register(ResultSet resultSet) {
|
||||
public void register(ResultSet resultSet, Statement statement) {
|
||||
LOG.tracev( "Registering result set [{0}]", resultSet );
|
||||
Statement statement;
|
||||
try {
|
||||
statement = resultSet.getStatement();
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
throw exceptionHelper.convert( e, "unable to access statement from resultset" );
|
||||
if ( statement == null ) {
|
||||
try {
|
||||
statement = resultSet.getStatement(); // best guess
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
throw exceptionHelper.convert( e, "unable to access statement from resultset" );
|
||||
}
|
||||
}
|
||||
if ( statement != null ) {
|
||||
if ( LOG.isEnabled( Level.WARN ) && !xref.containsKey( statement ) ) {
|
||||
|
|
|
@ -54,7 +54,7 @@ public class ResultSetReturnImpl implements ResultSetReturn {
|
|||
}
|
||||
try {
|
||||
ResultSet rs = statement.executeQuery();
|
||||
postExtract( rs );
|
||||
postExtract( rs, statement );
|
||||
return rs;
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
|
@ -68,7 +68,7 @@ public class ResultSetReturnImpl implements ResultSetReturn {
|
|||
// sql logged by StatementPreparerImpl
|
||||
ResultSet rs = jdbcCoordinator.getLogicalConnection().getJdbcServices()
|
||||
.getDialect().getResultSet( statement );
|
||||
postExtract( rs );
|
||||
postExtract( rs, statement );
|
||||
return rs;
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
|
@ -82,7 +82,7 @@ public class ResultSetReturnImpl implements ResultSetReturn {
|
|||
.getSqlStatementLogger().logStatement( sql );
|
||||
try {
|
||||
ResultSet rs = statement.executeQuery( sql );
|
||||
postExtract( rs );
|
||||
postExtract( rs, statement );
|
||||
return rs;
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
|
@ -100,7 +100,7 @@ public class ResultSetReturnImpl implements ResultSetReturn {
|
|||
}
|
||||
}
|
||||
ResultSet rs = statement.getResultSet();
|
||||
postExtract( rs );
|
||||
postExtract( rs, statement );
|
||||
return rs;
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
|
@ -119,7 +119,7 @@ public class ResultSetReturnImpl implements ResultSetReturn {
|
|||
}
|
||||
}
|
||||
ResultSet rs = statement.getResultSet();
|
||||
postExtract( rs );
|
||||
postExtract( rs, statement );
|
||||
return rs;
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
|
@ -157,8 +157,8 @@ public class ResultSetReturnImpl implements ResultSetReturn {
|
|||
.getSqlExceptionHelper();
|
||||
}
|
||||
|
||||
private void postExtract(ResultSet rs) {
|
||||
if ( rs != null ) jdbcCoordinator.register( rs );
|
||||
private void postExtract(ResultSet rs, Statement st) {
|
||||
if ( rs != null ) jdbcCoordinator.register( rs, st );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -170,10 +170,15 @@ public interface JdbcCoordinator extends Serializable {
|
|||
|
||||
/**
|
||||
* Register a JDBC result set.
|
||||
* <p/>
|
||||
* Implementation note: Second parameter has been introduced to prevent
|
||||
* multiple registrations of the same statement in case {@link ResultSet#getStatement()}
|
||||
* does not return original {@link Statement} object.
|
||||
*
|
||||
* @param resultSet The result set to register.
|
||||
* @param statement Statement from which {@link ResultSet} has been generated.
|
||||
*/
|
||||
public void register(ResultSet resultSet);
|
||||
public void register(ResultSet resultSet, Statement statement);
|
||||
|
||||
/**
|
||||
* Release a previously registered result set.
|
||||
|
|
|
@ -954,8 +954,9 @@ public class QueryTranslatorImpl extends BasicLoader implements FilterTranslator
|
|||
|
||||
try {
|
||||
final List<AfterLoadAction> afterLoadActions = new ArrayList<AfterLoadAction>();
|
||||
final ResultSet rs = executeQueryStatement( queryParameters, false, afterLoadActions, session );
|
||||
final PreparedStatement st = (PreparedStatement) rs.getStatement();
|
||||
final SqlStatementWrapper wrapper = executeQueryStatement( queryParameters, false, afterLoadActions, session );
|
||||
final ResultSet rs = wrapper.getResultSet();
|
||||
final PreparedStatement st = (PreparedStatement) wrapper.getStatement();
|
||||
HolderInstantiator hi = HolderInstantiator.createClassicHolderInstantiator(holderConstructor, queryParameters.getResultTransformer());
|
||||
Iterator result = new IteratorImpl( rs, st, session, queryParameters.isReadOnly( session ), returnTypes, getColumnNames(), hi );
|
||||
|
||||
|
|
|
@ -896,9 +896,9 @@ public abstract class Loader {
|
|||
|
||||
final List<AfterLoadAction> afterLoadActions = new ArrayList<AfterLoadAction>();
|
||||
|
||||
final ResultSet rs = executeQueryStatement( queryParameters, false, afterLoadActions, session );
|
||||
final Statement st = rs.getStatement();
|
||||
final int entitySpan = getEntityPersisters().length;
|
||||
final SqlStatementWrapper wrapper = executeQueryStatement( queryParameters, false, afterLoadActions, session );
|
||||
final ResultSet rs = wrapper.getResultSet();
|
||||
final Statement st = wrapper.getStatement();
|
||||
|
||||
// would be great to move all this below here into another method that could also be used
|
||||
// from the new scrolling stuff.
|
||||
|
@ -1803,7 +1803,7 @@ public abstract class Loader {
|
|||
* Process query string by applying filters, LIMIT clause, locks and comments if necessary.
|
||||
* Finally execute SQL statement and advance to the first row.
|
||||
*/
|
||||
protected ResultSet executeQueryStatement(
|
||||
protected SqlStatementWrapper executeQueryStatement(
|
||||
final QueryParameters queryParameters,
|
||||
final boolean scroll,
|
||||
List<AfterLoadAction> afterLoadActions,
|
||||
|
@ -1811,10 +1811,10 @@ public abstract class Loader {
|
|||
return executeQueryStatement( getSQLString(), queryParameters, scroll, afterLoadActions, session );
|
||||
}
|
||||
|
||||
protected ResultSet executeQueryStatement(
|
||||
final String sqlStatement,
|
||||
final QueryParameters queryParameters,
|
||||
final boolean scroll,
|
||||
protected SqlStatementWrapper executeQueryStatement(
|
||||
String sqlStatement,
|
||||
QueryParameters queryParameters,
|
||||
boolean scroll,
|
||||
List<AfterLoadAction> afterLoadActions,
|
||||
final SessionImplementor session) throws SQLException {
|
||||
|
||||
|
@ -1829,7 +1829,7 @@ public abstract class Loader {
|
|||
sql = preprocessSQL( sql, queryParameters, getFactory().getDialect(), afterLoadActions );
|
||||
|
||||
final PreparedStatement st = prepareQueryStatement( sql, queryParameters, limitHandler, scroll, session );
|
||||
return getResultSet( st, queryParameters.getRowSelection(), limitHandler, queryParameters.hasAutoDiscoverScalarTypes(), session );
|
||||
return new SqlStatementWrapper( st, getResultSet( st, queryParameters.getRowSelection(), limitHandler, queryParameters.hasAutoDiscoverScalarTypes(), session ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2583,8 +2583,9 @@ public abstract class Loader {
|
|||
if ( stats ) startTime = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
final ResultSet rs = executeQueryStatement( queryParameters, true, Collections.<AfterLoadAction>emptyList(), session );
|
||||
final PreparedStatement st = (PreparedStatement) rs.getStatement();
|
||||
final SqlStatementWrapper wrapper = executeQueryStatement( queryParameters, true, Collections.<AfterLoadAction>emptyList(), session );
|
||||
final ResultSet rs = wrapper.getResultSet();
|
||||
final PreparedStatement st = (PreparedStatement) wrapper.getStatement();
|
||||
|
||||
if ( stats ) {
|
||||
getFactory().getStatisticsImplementor().queryExecuted(
|
||||
|
@ -2657,4 +2658,25 @@ public abstract class Loader {
|
|||
public String toString() {
|
||||
return getClass().getName() + '(' + getSQLString() + ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper class for {@link Statement} and associated {@link ResultSet}.
|
||||
*/
|
||||
protected static class SqlStatementWrapper {
|
||||
private final Statement statement;
|
||||
private final ResultSet resultSet;
|
||||
|
||||
private SqlStatementWrapper(Statement statement, ResultSet resultSet) {
|
||||
this.resultSet = resultSet;
|
||||
this.statement = statement;
|
||||
}
|
||||
|
||||
public ResultSet getResultSet() {
|
||||
return resultSet;
|
||||
}
|
||||
|
||||
public Statement getStatement() {
|
||||
return statement;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -253,8 +253,9 @@ public class DynamicBatchingCollectionInitializerBuilder extends BatchingCollect
|
|||
Integer.MAX_VALUE;
|
||||
|
||||
final List<AfterLoadAction> afterLoadActions = Collections.emptyList();
|
||||
final ResultSet rs = executeQueryStatement( sql, queryParameters, false, afterLoadActions, session );
|
||||
final Statement st = rs.getStatement();
|
||||
final SqlStatementWrapper wrapper = executeQueryStatement( sql, queryParameters, false, afterLoadActions, session );
|
||||
final ResultSet rs = wrapper.getResultSet();
|
||||
final Statement st = wrapper.getStatement();
|
||||
try {
|
||||
processResultSet( rs, queryParameters, session, true, null, maxRows, afterLoadActions );
|
||||
}
|
||||
|
|
|
@ -27,11 +27,9 @@ import java.io.Serializable;
|
|||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Collections;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.dialect.pagination.LimitHelper;
|
||||
|
@ -45,6 +43,7 @@ import org.hibernate.internal.util.StringHelper;
|
|||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.persister.entity.OuterJoinLoadable;
|
||||
import org.hibernate.pretty.MessageHelper;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* A BatchingEntityLoaderBuilder that builds UniqueEntityLoader instances capable of dynamically building
|
||||
|
@ -254,9 +253,10 @@ public class DynamicBatchingEntityLoaderBuilder extends BatchingEntityLoaderBuil
|
|||
selection.getMaxRows() :
|
||||
Integer.MAX_VALUE;
|
||||
|
||||
final List<AfterLoadAction> afterLoadActions = Collections.emptyList();
|
||||
final ResultSet rs = executeQueryStatement( sql, queryParameters, false, afterLoadActions, session );
|
||||
final Statement st = rs.getStatement();
|
||||
final List<AfterLoadAction> afterLoadActions = new ArrayList<AfterLoadAction>();
|
||||
final SqlStatementWrapper wrapper = executeQueryStatement( sql, queryParameters, false, afterLoadActions, session );
|
||||
final ResultSet rs = wrapper.getResultSet();
|
||||
final Statement st = wrapper.getStatement();
|
||||
try {
|
||||
return processResultSet( rs, queryParameters, session, false, null, maxRows, afterLoadActions );
|
||||
}
|
||||
|
|
|
@ -510,8 +510,9 @@ public class QueryLoader extends BasicLoader {
|
|||
if ( queryParameters.isCallable() ) {
|
||||
throw new QueryException("iterate() not supported for callable statements");
|
||||
}
|
||||
final ResultSet rs = executeQueryStatement( queryParameters, false, Collections.<AfterLoadAction>emptyList(), session );
|
||||
final PreparedStatement st = (PreparedStatement) rs.getStatement();
|
||||
final SqlStatementWrapper wrapper = executeQueryStatement( queryParameters, false, Collections.<AfterLoadAction>emptyList(), session );
|
||||
final ResultSet rs = wrapper.getResultSet();
|
||||
final PreparedStatement st = (PreparedStatement) wrapper.getStatement();
|
||||
final Iterator result = new IteratorImpl(
|
||||
rs,
|
||||
st,
|
||||
|
|
|
@ -129,7 +129,7 @@ public class BasicOperationsTest extends BaseCoreFunctionalTestCase {
|
|||
String columnNamePattern = generateFinalNamePattern( meta, columnName );
|
||||
|
||||
ResultSet columnInfo = meta.getColumns( null, null, tableNamePattern, columnNamePattern );
|
||||
s.getTransactionCoordinator().getJdbcCoordinator().register(columnInfo);
|
||||
s.getTransactionCoordinator().getJdbcCoordinator().register(columnInfo, columnInfo.getStatement());
|
||||
assertTrue( columnInfo.next() );
|
||||
int dataType = columnInfo.getInt( "DATA_TYPE" );
|
||||
s.getTransactionCoordinator().getJdbcCoordinator().release( columnInfo );
|
||||
|
|
|
@ -89,6 +89,28 @@ public class CursorFromCallableTest extends BaseCoreFunctionalTestCase {
|
|||
session.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-7984" )
|
||||
public void testStatementClosing() {
|
||||
Session session = openSession();
|
||||
session.getTransaction().begin();
|
||||
// Reading maximum number of opened cursors requires SYS privileges.
|
||||
// Verify statement closing with JdbcCoordinator#hasRegisteredResources() instead.
|
||||
// BigDecimal maxCursors = (BigDecimal) session.createSQLQuery( "SELECT value FROM v$parameter WHERE name = 'open_cursors'" ).uniqueResult();
|
||||
// for ( int i = 0; i < maxCursors + 10; ++i ) { named_query_execution }
|
||||
Assert.assertEquals(
|
||||
Arrays.asList( new NumValue( 1, "Line 1" ), new NumValue( 2, "Line 2" ) ),
|
||||
session.getNamedQuery( "NumValue.getSomeValues" ).list()
|
||||
);
|
||||
JdbcCoordinator jdbcCoordinator = ( (SessionImplementor) session ).getTransactionCoordinator().getJdbcCoordinator();
|
||||
Assert.assertFalse(
|
||||
"Prepared statement and result set should be released after query execution.",
|
||||
jdbcCoordinator.hasRegisteredResources()
|
||||
);
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
}
|
||||
|
||||
private void executeStatement(final String sql) {
|
||||
final Session session = openSession();
|
||||
session.getTransaction().begin();
|
||||
|
|
Loading…
Reference in New Issue