HHH-11600 - Sap HANA PreparedStatement implements CallableStatement and is treated as such by Hibernate
This commit is contained in:
parent
1c34914455
commit
d80c6ac0f9
|
@ -31,8 +31,6 @@ public class ResultSetReturnImpl implements ResultSetReturn {
|
||||||
private final SqlStatementLogger sqlStatementLogger;
|
private final SqlStatementLogger sqlStatementLogger;
|
||||||
private final SqlExceptionHelper sqlExceptionHelper;
|
private final SqlExceptionHelper sqlExceptionHelper;
|
||||||
|
|
||||||
private boolean isJdbc4 = true;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a ResultSetReturnImpl
|
* Constructs a ResultSetReturnImpl
|
||||||
*
|
*
|
||||||
|
@ -56,15 +54,6 @@ public class ResultSetReturnImpl implements ResultSetReturn {
|
||||||
public ResultSet extract(PreparedStatement statement) {
|
public ResultSet extract(PreparedStatement statement) {
|
||||||
// IMPL NOTE : SQL logged by caller
|
// IMPL NOTE : SQL logged by caller
|
||||||
try {
|
try {
|
||||||
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 = statement.unwrap( CallableStatement.class );
|
|
||||||
return extract( callableStatement );
|
|
||||||
}
|
|
||||||
|
|
||||||
final ResultSet rs;
|
final ResultSet rs;
|
||||||
try {
|
try {
|
||||||
jdbcExecuteStatementStart();
|
jdbcExecuteStatementStart();
|
||||||
|
@ -89,25 +78,6 @@ public class ResultSetReturnImpl implements ResultSetReturn {
|
||||||
jdbcCoordinator.getJdbcSessionOwner().getJdbcSessionContext().getObserver().jdbcExecuteStatementStart();
|
jdbcCoordinator.getJdbcSessionOwner().getJdbcSessionContext().getObserver().jdbcExecuteStatementStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isTypeOf(final Statement statement, final Class<? extends Statement> type) {
|
|
||||||
if ( isJdbc4 ) {
|
|
||||||
try {
|
|
||||||
// This is "more correct" than #isInstance, but not always supported.
|
|
||||||
return statement.isWrapperFor( type );
|
|
||||||
}
|
|
||||||
catch (SQLException e) {
|
|
||||||
// No operation
|
|
||||||
}
|
|
||||||
catch (Throwable e) {
|
|
||||||
// No operation. Note that this catches more than just SQLException to
|
|
||||||
// cover edge cases where a driver might throw an UnsupportedOperationException, AbstractMethodError,
|
|
||||||
// etc. If so, skip permanently.
|
|
||||||
isJdbc4 = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return type.isInstance( statement );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResultSet extract(CallableStatement callableStatement) {
|
public ResultSet extract(CallableStatement callableStatement) {
|
||||||
// IMPL NOTE : SQL logged by caller
|
// IMPL NOTE : SQL logged by caller
|
||||||
|
|
|
@ -108,6 +108,8 @@ public abstract class Loader {
|
||||||
|
|
||||||
private final boolean referenceCachingEnabled;
|
private final boolean referenceCachingEnabled;
|
||||||
|
|
||||||
|
private boolean isJdbc4 = true;
|
||||||
|
|
||||||
public Loader(SessionFactoryImplementor factory) {
|
public Loader(SessionFactoryImplementor factory) {
|
||||||
this.factory = factory;
|
this.factory = factory;
|
||||||
this.referenceCachingEnabled = factory.getSessionFactoryOptions().isDirectReferenceCacheEntriesEnabled();
|
this.referenceCachingEnabled = factory.getSessionFactoryOptions().isDirectReferenceCacheEntriesEnabled();
|
||||||
|
@ -1907,15 +1909,54 @@ public abstract class Loader {
|
||||||
sql = preprocessSQL( sql, queryParameters, getFactory().getDialect(), afterLoadActions );
|
sql = preprocessSQL( sql, queryParameters, getFactory().getDialect(), afterLoadActions );
|
||||||
|
|
||||||
final PreparedStatement st = prepareQueryStatement( sql, queryParameters, limitHandler, scroll, session );
|
final PreparedStatement st = prepareQueryStatement( sql, queryParameters, limitHandler, scroll, session );
|
||||||
return new SqlStatementWrapper(
|
|
||||||
st, getResultSet(
|
final ResultSet rs;
|
||||||
|
|
||||||
|
if( queryParameters.isCallable() && isTypeOf( st, CallableStatement.class ) ) {
|
||||||
|
final CallableStatement cs = st.unwrap( CallableStatement.class );
|
||||||
|
|
||||||
|
rs = getResultSet(
|
||||||
|
cs,
|
||||||
|
queryParameters.getRowSelection(),
|
||||||
|
limitHandler,
|
||||||
|
queryParameters.hasAutoDiscoverScalarTypes(),
|
||||||
|
session
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rs = getResultSet(
|
||||||
st,
|
st,
|
||||||
queryParameters.getRowSelection(),
|
queryParameters.getRowSelection(),
|
||||||
limitHandler,
|
limitHandler,
|
||||||
queryParameters.hasAutoDiscoverScalarTypes(),
|
queryParameters.hasAutoDiscoverScalarTypes(),
|
||||||
session
|
session
|
||||||
)
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SqlStatementWrapper(
|
||||||
|
st,
|
||||||
|
rs
|
||||||
);
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTypeOf(final Statement statement, final Class<? extends Statement> type) {
|
||||||
|
if ( isJdbc4 ) {
|
||||||
|
try {
|
||||||
|
// This is "more correct" than #isInstance, but not always supported.
|
||||||
|
return statement.isWrapperFor( type );
|
||||||
|
}
|
||||||
|
catch (SQLException e) {
|
||||||
|
// No operation
|
||||||
|
}
|
||||||
|
catch (Throwable e) {
|
||||||
|
// No operation. Note that this catches more than just SQLException to
|
||||||
|
// cover edge cases where a driver might throw an UnsupportedOperationException, AbstractMethodError,
|
||||||
|
// etc. If so, skip permanently.
|
||||||
|
isJdbc4 = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return type.isInstance( statement );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2121,16 +2162,8 @@ public abstract class Loader {
|
||||||
final SharedSessionContractImplementor session) throws SQLException, HibernateException {
|
final SharedSessionContractImplementor session) throws SQLException, HibernateException {
|
||||||
try {
|
try {
|
||||||
ResultSet rs = session.getJdbcCoordinator().getResultSetReturn().extract( st );
|
ResultSet rs = session.getJdbcCoordinator().getResultSetReturn().extract( st );
|
||||||
rs = wrapResultSetIfEnabled( rs, session );
|
|
||||||
|
|
||||||
if ( !limitHandler.supportsLimitOffset() || !LimitHelper.useLimit( limitHandler, selection ) ) {
|
return processResultSet(rs, selection, limitHandler, autodiscovertypes, session);
|
||||||
advance( rs, selection );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( autodiscovertypes ) {
|
|
||||||
autoDiscoverTypes( rs );
|
|
||||||
}
|
|
||||||
return rs;
|
|
||||||
}
|
}
|
||||||
catch (SQLException | HibernateException e) {
|
catch (SQLException | HibernateException e) {
|
||||||
session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release( st );
|
session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release( st );
|
||||||
|
@ -2139,6 +2172,46 @@ public abstract class Loader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute given <tt>CallableStatement</tt>, advance to the first result and return SQL <tt>ResultSet</tt>.
|
||||||
|
*/
|
||||||
|
protected final ResultSet getResultSet(
|
||||||
|
final CallableStatement st,
|
||||||
|
final RowSelection selection,
|
||||||
|
final LimitHandler limitHandler,
|
||||||
|
final boolean autodiscovertypes,
|
||||||
|
final SharedSessionContractImplementor session) throws SQLException, HibernateException {
|
||||||
|
try {
|
||||||
|
ResultSet rs = session.getJdbcCoordinator().getResultSetReturn().extract( st );
|
||||||
|
|
||||||
|
return processResultSet(rs, selection, limitHandler, autodiscovertypes, session);
|
||||||
|
}
|
||||||
|
catch (SQLException | HibernateException e) {
|
||||||
|
session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release( st );
|
||||||
|
session.getJdbcCoordinator().afterStatementExecution();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResultSet processResultSet(
|
||||||
|
ResultSet rs,
|
||||||
|
final RowSelection selection,
|
||||||
|
final LimitHandler limitHandler,
|
||||||
|
final boolean autodiscovertypes,
|
||||||
|
final SharedSessionContractImplementor session
|
||||||
|
) throws SQLException, HibernateException {
|
||||||
|
rs = wrapResultSetIfEnabled( rs, session );
|
||||||
|
|
||||||
|
if ( !limitHandler.supportsLimitOffset() || !LimitHelper.useLimit( limitHandler, selection ) ) {
|
||||||
|
advance( rs, selection );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( autodiscovertypes ) {
|
||||||
|
autoDiscoverTypes( rs );
|
||||||
|
}
|
||||||
|
return rs;
|
||||||
|
}
|
||||||
|
|
||||||
protected void autoDiscoverTypes(ResultSet rs) {
|
protected void autoDiscoverTypes(ResultSet rs) {
|
||||||
throw new AssertionFailure( "Auto discover types not supported in this loader" );
|
throw new AssertionFailure( "Auto discover types not supported in this loader" );
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue