diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/JdbcValuesResultSetImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/JdbcValuesResultSetImpl.java index 2ce2c19854..0d7d82e2d7 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/JdbcValuesResultSetImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/JdbcValuesResultSetImpl.java @@ -7,6 +7,7 @@ package org.hibernate.sql.results.jdbc.internal; import java.sql.ResultSet; +import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.Arrays; import java.util.BitSet; @@ -15,6 +16,7 @@ import org.hibernate.JDBCException; import org.hibernate.QueryTimeoutException; import org.hibernate.cache.spi.QueryKey; import org.hibernate.cache.spi.QueryResultsCache; +import org.hibernate.dialect.OracleDialect; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.exception.DataException; @@ -44,6 +46,7 @@ public class JdbcValuesResultSetImpl extends AbstractJdbcValues { private final SqlSelection[] sqlSelections; private final BitSet initializedIndexes; + private BitSet forceInitializedIndexes; private final Object[] currentRowJdbcValues; private final int[] valueIndexesToCacheIndexes; // Is only meaningful if valueIndexesToCacheIndexes is not null @@ -72,9 +75,36 @@ public class JdbcValuesResultSetImpl extends AbstractJdbcValues { final int rowSize = valuesMapping.getRowSize(); this.sqlSelections = new SqlSelection[rowSize]; - for ( SqlSelection selection : valuesMapping.getSqlSelections() ) { - this.sqlSelections[selection.getValuesArrayPosition()] = selection; + final boolean isOracleDialect = executionContext.getSession().getJdbcServices().getDialect() instanceof OracleDialect; + if ( isOracleDialect ) { + // When LONG RAW and LONG type columns are not read sequentially (e.g. a following column in the ResultSet is read first) + // Oracle raises a `ORA-17027: Stream has already been closed` exception , in order to avoid this + // Hibernate needs force their initialization + final ResultSetMetaData metaData = ( (AbstractResultSetAccess) resultSetAccess ).getMetaData(); + for ( SqlSelection selection : valuesMapping.getSqlSelections() ) { + this.sqlSelections[selection.getValuesArrayPosition()] = selection; + if ( isOracleDialect ) { + try { + int columnType = metaData.getColumnType( selection.getJdbcResultSetIndex() ); + if ( columnType == -4 || columnType == -1 ) { + if ( forceInitializedIndexes == null ) { + forceInitializedIndexes = new BitSet(); + } + forceInitializedIndexes.set( selection.getValuesArrayPosition() ); + } + } + catch (SQLException e) { + // ignore + } + } + } } + else { + for ( SqlSelection selection : valuesMapping.getSqlSelections() ) { + this.sqlSelections[selection.getValuesArrayPosition()] = selection; + } + } + this.initializedIndexes = new BitSet( rowSize ); this.currentRowJdbcValues = new Object[rowSize]; if ( queryCachePutManager == null ) { @@ -324,6 +354,31 @@ public class JdbcValuesResultSetImpl extends AbstractJdbcValues { private void readCurrentRowValues() { initializedIndexes.clear(); + if ( forceInitializedIndexes != null ) { + final ResultSet resultSet = resultSetAccess.getResultSet(); + final SharedSessionContractImplementor session = executionContext.getSession(); + for ( final SqlSelection sqlSelection : sqlSelections ) { + try { + final int valuesArrayPosition = sqlSelection.getValuesArrayPosition(); + if ( forceInitializedIndexes.get( valuesArrayPosition ) ) { + currentRowJdbcValues[valuesArrayPosition] = sqlSelection.getJdbcValueExtractor().extract( + resultSet, + sqlSelection.getJdbcResultSetIndex(), + session + ); + initializedIndexes.set( valuesArrayPosition ); + } + } + catch (SQLException e) { + // do not want to wrap in ExecutionException here + throw executionContext.getSession().getJdbcServices().getSqlExceptionHelper().convert( + e, + "Could not extract column [" + sqlSelection.getJdbcResultSetIndex() + "] from JDBC ResultSet" + ); + } + } + } + } @Override