Uploaded image for project: 'Hibernate ORM'
  1. HHH-9145

Compatibility improvement suggestion for org.hibernate.engine.jdbc.internal.ResultSetReturnImpl

    Details

      Description

      The fix implemented for issue HHH-8022 Closed in org.hibernate.engine.jdbc.internal.ResultSetReturnImpl performs an instanceof check on the statement object to determine if the current statement is an instance of CallableStatement. This presents a potential problem if a framework wraps a statement object in either a proxy or a concrete class that implements both PreparedStatement and CallableStatement.

      This can result in wrapped/proxied PreparedStatement objects being incorrectly identified as CallableStatement instances with the end result often being a ClassCastException, AbstractMethodError, or NoSuchMethodException error in the wrapper or proxy.

      Since JDK 6 is now a minimum requirement it seems like a more compatible fix would have been to call java.sql.Wrapper.isWrapperFor(CallableStatement.class) method on the statement object to determine the instance type instead of using the instanceof keyword. While I'm not stating that the implemented fix is technically wrong, I believe the use of Wrapper.isWrapperFor would promote improved compatibility across the greatest range of pooling frameworks, JDBC drivers, etc.

      Improvement Suggestion:

      org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.java
      public ResultSet extract(PreparedStatement statement) {
      	// IMPL NOTE : SQL logged by caller
      	if (isTypeOf(statement, CallableStatement.class)) {
      		// We actually need to extract from Callable statement.  Although
      		// this seems needless, Oracle can return an
      		// OracleCallableStatementWrapper that finds its way to this method,
      		// rather than extract(CallableStatement).  See HHH-8022.
      		final CallableStatement callableStatement = (CallableStatement) statement;
      		return extract( callableStatement );
      	}
      	try {
      		final ResultSet rs;
      		try {
      			jdbcCoordinator.getTransactionCoordinator().getTransactionContext().startStatementExecution();
      			rs = statement.executeQuery();
      		}
      		finally {
      			jdbcCoordinator.getTransactionCoordinator().getTransactionContext().endStatementExecution();
      		}
      		postExtract( rs, statement );
      		return rs;
      	}
      	catch (SQLException e) {
      		throw sqlExceptionHelper.convert( e, "could not extract ResultSet" );
      	}
      }
      private boolean isTypeOf(final Statement statement, final Class<? extends Statement> type) {
      	boolean matches;
      	try {
      		// Verify if the statement either implements the interface directly
      		// or is a wrapper for the specified type via the JDBC API
      		matches = statement.isWrapperFor(type);
      	} catch (SQLException e) {
      		// If the wrapper check fails for some reason, fall back to assignable class verification
      		matches = type.isAssignableFrom(statement.getClass());
      	}
      	return matches;
      }
      

        Attachments

          Activity

            People

            • Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: