77import java .sql .PreparedStatement ;
88import java .sql .ResultSet ;
99import java .sql .SQLException ;
10- import java .util .Collections ;
1110
1211import org .hibernate .LockMode ;
1312import org .hibernate .LockOptions ;
1413import org .hibernate .dialect .Dialect ;
1514import org .hibernate .dialect .pagination .LimitHandler ;
1615import org .hibernate .dialect .pagination .NoopLimitHandler ;
16+ import org .hibernate .engine .jdbc .spi .JdbcServices ;
1717import org .hibernate .engine .jdbc .spi .SqlStatementLogger ;
1818import org .hibernate .engine .spi .SessionEventListenerManager ;
1919import org .hibernate .engine .spi .SessionFactoryImplementor ;
3333import org .hibernate .sql .exec .spi .JdbcParameterBindings ;
3434import org .hibernate .sql .exec .spi .JdbcSelectExecutor ;
3535
36+ import static java .util .Collections .emptyMap ;
37+
3638/**
3739 * @author Steve Ebersole
3840 */
@@ -62,11 +64,13 @@ public DeferredResultSetAccess(
6264 JdbcSelectExecutor .StatementCreator statementCreator ,
6365 int resultCountEstimate ) {
6466 super ( executionContext .getSession () );
67+ final JdbcServices jdbcServices = executionContext .getSession ().getJdbcServices ();
68+
6569 this .jdbcParameterBindings = jdbcParameterBindings ;
6670 this .executionContext = executionContext ;
6771 this .jdbcSelect = jdbcSelect ;
6872 this .statementCreator = statementCreator ;
69- this .sqlStatementLogger = executionContext . getSession (). getJdbcServices () .getSqlStatementLogger ();
73+ this .sqlStatementLogger = jdbcServices .getSqlStatementLogger ();
7074 this .resultCountEstimate = resultCountEstimate ;
7175
7276 final QueryOptions queryOptions = executionContext .getQueryOptions ();
@@ -79,54 +83,61 @@ public DeferredResultSetAccess(
7983 else {
8084 // Note that limit and lock aren't set for SQM as that is applied during SQL rendering
8185 // But for native queries, we have to adapt the SQL string
82- final Dialect dialect = executionContext .getSession ().getJdbcServices ().getDialect ();
83- String sql ;
86+ final Dialect dialect = jdbcServices .getDialect ();
87+
88+ final String sql = jdbcSelect .getSqlString ();
89+
8490 limit = queryOptions .getLimit ();
85- if ( limit == null || limit .isEmpty () || jdbcSelect .usesLimitParameters () ) {
86- sql = jdbcSelect .getSqlString ();
87- limitHandler = NoopLimitHandler .NO_LIMIT ;
88- }
89- else {
90- limitHandler = dialect .getLimitHandler ();
91- sql = limitHandler .processSql (
92- jdbcSelect .getSqlString (),
93- limit ,
94- queryOptions
95- );
96- }
91+ final boolean hasLimit = isHasLimit ( jdbcSelect );
92+ limitHandler = hasLimit ? NoopLimitHandler .NO_LIMIT : dialect .getLimitHandler ();
93+ final String sqlWithLimit = hasLimit ? sql : limitHandler .processSql ( sql , limit , queryOptions );
9794
9895 final LockOptions lockOptions = queryOptions .getLockOptions ();
9996 final JdbcLockStrategy jdbcLockStrategy = jdbcSelect .getLockStrategy ();
100- if ( jdbcLockStrategy != JdbcLockStrategy . NONE
101- && lockOptions != null && ! lockOptions . isEmpty ( ) ) {
102- usesFollowOnLocking = useFollowOnLocking ( jdbcLockStrategy , sql , queryOptions , lockOptions , dialect );
97+ final String sqlWithLocking ;
98+ if ( hasLocking ( jdbcLockStrategy , lockOptions ) ) {
99+ usesFollowOnLocking = useFollowOnLocking ( jdbcLockStrategy , sqlWithLimit , queryOptions , lockOptions , dialect );
103100 if ( usesFollowOnLocking ) {
104- final LockMode lockMode = determineFollowOnLockMode ( lockOptions );
105- if ( lockMode != LockMode .UPGRADE_SKIPLOCKED ) {
106- // Dialect prefers to perform locking in a separate step
107- if ( lockOptions .getLockMode () != LockMode .NONE ) {
108- LOG .usingFollowOnLocking ();
109- }
110-
111- final LockOptions lockOptionsToUse = new LockOptions ( lockMode );
112- lockOptionsToUse .setTimeOut ( lockOptions .getTimeOut () );
113- lockOptionsToUse .setLockScope ( lockOptions .getLockScope () );
114-
115- registerAfterLoadAction ( executionContext , lockOptionsToUse );
116- }
101+ handleFollowOnLocking ( executionContext , lockOptions );
102+ sqlWithLocking = sqlWithLimit ;
117103 }
118104 else {
119- sql = dialect .applyLocksToSql ( sql , lockOptions , Collections . emptyMap () );
105+ sqlWithLocking = dialect .applyLocksToSql ( sqlWithLimit , lockOptions , emptyMap () );
120106 }
121107 }
122108 else {
123109 usesFollowOnLocking = false ;
110+ sqlWithLocking = sqlWithLimit ;
124111 }
125- finalSql = dialect .addSqlHintOrComment (
126- sql ,
127- queryOptions ,
128- executionContext .getSession ().getFactory ().getSessionFactoryOptions ().isCommentsEnabled ()
129- );
112+
113+ final boolean commentsEnabled =
114+ executionContext .getSession ().getFactory ()
115+ .getSessionFactoryOptions ().isCommentsEnabled ();
116+ finalSql = dialect .addSqlHintOrComment ( sqlWithLocking , queryOptions , commentsEnabled );
117+ }
118+ }
119+
120+ private boolean isHasLimit (JdbcOperationQuerySelect jdbcSelect ) {
121+ return limit == null || limit .isEmpty () || jdbcSelect .usesLimitParameters ();
122+ }
123+
124+ private static boolean hasLocking (JdbcLockStrategy jdbcLockStrategy , LockOptions lockOptions ) {
125+ return jdbcLockStrategy != JdbcLockStrategy .NONE && lockOptions != null && !lockOptions .isEmpty ();
126+ }
127+
128+ private void handleFollowOnLocking (ExecutionContext executionContext , LockOptions lockOptions ) {
129+ final LockMode lockMode = determineFollowOnLockMode ( lockOptions );
130+ if ( lockMode != LockMode .UPGRADE_SKIPLOCKED ) {
131+ // Dialect prefers to perform locking in a separate step
132+ if ( lockOptions .getLockMode () != LockMode .NONE ) {
133+ LOG .usingFollowOnLocking ();
134+ }
135+
136+ final LockOptions lockOptionsToUse = new LockOptions ( lockMode );
137+ lockOptionsToUse .setTimeOut ( lockOptions .getTimeOut () );
138+ lockOptionsToUse .setLockScope ( lockOptions .getLockScope () );
139+
140+ registerAfterLoadAction ( executionContext , lockOptionsToUse );
130141 }
131142 }
132143
@@ -184,20 +195,10 @@ public boolean usesFollowOnLocking() {
184195 }
185196
186197 protected void bindParameters (PreparedStatement preparedStatement ) throws SQLException {
187- final QueryOptions queryOptions = executionContext .getQueryOptions ();
188-
189- // set options
190- if ( queryOptions != null ) {
191- if ( queryOptions .getFetchSize () != null ) {
192- preparedStatement .setFetchSize ( queryOptions .getFetchSize () );
193- }
194- if ( queryOptions .getTimeout () != null ) {
195- preparedStatement .setQueryTimeout ( queryOptions .getTimeout () );
196- }
197- }
198+ setQueryOptions ( preparedStatement );
198199
199200 // bind parameters
200- // todo : validate that all query parameters were bound?
201+ // todo : validate that all query parameters were bound?
201202 int paramBindingPosition = 1 ;
202203 paramBindingPosition += limitHandler .bindLimitParametersAtStartOfQuery ( limit , preparedStatement , paramBindingPosition );
203204 for ( JdbcParameterBinder parameterBinder : jdbcSelect .getParameterBinders () ) {
@@ -208,7 +209,6 @@ protected void bindParameters(PreparedStatement preparedStatement) throws SQLExc
208209 executionContext
209210 );
210211 }
211-
212212 paramBindingPosition += limitHandler .bindLimitParametersAtEndOfQuery ( limit , preparedStatement , paramBindingPosition );
213213
214214 if ( !jdbcSelect .usesLimitParameters () && limit != null && limit .getMaxRows () != null ) {
@@ -222,6 +222,19 @@ protected void bindParameters(PreparedStatement preparedStatement) throws SQLExc
222222 }
223223 }
224224
225+ private void setQueryOptions (PreparedStatement preparedStatement ) throws SQLException {
226+ final QueryOptions queryOptions = executionContext .getQueryOptions ();
227+ // set options
228+ if ( queryOptions != null ) {
229+ if ( queryOptions .getFetchSize () != null ) {
230+ preparedStatement .setFetchSize ( queryOptions .getFetchSize () );
231+ }
232+ if ( queryOptions .getTimeout () != null ) {
233+ preparedStatement .setQueryTimeout ( queryOptions .getTimeout () );
234+ }
235+ }
236+ }
237+
225238 private void executeQuery () {
226239 final LogicalConnectionImplementor logicalConnection =
227240 getPersistenceContext ().getJdbcCoordinator ().getLogicalConnection ();
@@ -234,9 +247,7 @@ private void executeQuery() {
234247
235248 bindParameters ( preparedStatement );
236249
237- final SessionEventListenerManager eventListenerManager = session
238- .getEventListenerManager ();
239-
250+ final SessionEventListenerManager eventListenerManager = session .getEventListenerManager ();
240251 long executeStartNanos = 0 ;
241252 if ( sqlStatementLogger .getLogSlowQuery () > 0 ) {
242253 executeStartNanos = System .nanoTime ();
@@ -257,17 +268,15 @@ private void executeQuery() {
257268 skipRows ( resultSet );
258269 logicalConnection .getResourceRegistry ().register ( resultSet , preparedStatement );
259270 }
260- catch (SQLException e ) {
271+ catch (SQLException exception ) {
261272 try {
262273 release ();
263274 }
264- catch (RuntimeException e2 ) {
265- e .addSuppressed ( e2 );
275+ catch (RuntimeException suppressed ) {
276+ exception .addSuppressed ( suppressed );
266277 }
267- throw session .getJdbcServices ().getSqlExceptionHelper ().convert (
268- e ,
269- "JDBC exception executing SQL [" + finalSql + "]"
270- );
278+ throw session .getJdbcServices ().getSqlExceptionHelper ()
279+ .convert ( exception , "JDBC exception executing SQL [" + finalSql + "]" );
271280 }
272281 }
273282
@@ -277,13 +286,7 @@ private JdbcSessionContext context() {
277286
278287 protected void skipRows (ResultSet resultSet ) throws SQLException {
279288 // For dialects that don't support an offset clause
280- final int rowsToSkip ;
281- if ( !jdbcSelect .usesLimitParameters () && limit != null && limit .getFirstRow () != null && !limitHandler .supportsLimitOffset () ) {
282- rowsToSkip = limit .getFirstRow ();
283- }
284- else {
285- rowsToSkip = jdbcSelect .getRowsToSkip ();
286- }
289+ final int rowsToSkip = getRowsToSkip ();
287290 if ( rowsToSkip != 0 ) {
288291 try {
289292 resultSet .absolute ( rowsToSkip );
@@ -303,13 +306,20 @@ protected void skipRows(ResultSet resultSet) throws SQLException {
303306 }
304307 }
305308
309+ private int getRowsToSkip () {
310+ return !jdbcSelect .usesLimitParameters ()
311+ && limit != null && limit .getFirstRow () != null
312+ && !limitHandler .supportsLimitOffset ()
313+ ? limit .getFirstRow ()
314+ : jdbcSelect .getRowsToSkip ();
315+ }
316+
306317 protected ResultSet wrapResultSet (ResultSet resultSet ) throws SQLException {
307318 return resultSet ;
308319 }
309320
310321 protected LockMode determineFollowOnLockMode (LockOptions lockOptions ) {
311322 final LockMode lockModeToUse = lockOptions .findGreatestLockMode ();
312-
313323 if ( lockOptions .hasAliasSpecificLockModes () ) {
314324 if ( lockOptions .getLockMode () == LockMode .NONE && lockModeToUse == LockMode .NONE ) {
315325 return lockModeToUse ;
@@ -323,8 +333,8 @@ protected LockMode determineFollowOnLockMode(LockOptions lockOptions) {
323333
324334 @ Override
325335 public void release () {
326- final LogicalConnectionImplementor logicalConnection = getPersistenceContext (). getJdbcCoordinator ()
327- .getLogicalConnection ();
336+ final LogicalConnectionImplementor logicalConnection =
337+ getPersistenceContext (). getJdbcCoordinator () .getLogicalConnection ();
328338 if ( resultSet != null ) {
329339 logicalConnection .getResourceRegistry ().release ( resultSet , preparedStatement );
330340 resultSet = null ;
@@ -343,12 +353,14 @@ public int getResultCountEstimate() {
343353 if ( limit != null && limit .getMaxRows () != null ) {
344354 return limit .getMaxRows ();
345355 }
346- if ( jdbcSelect .getLimitParameter () != null ) {
356+ else if ( jdbcSelect .getLimitParameter () != null ) {
347357 return (int ) jdbcParameterBindings .getBinding ( jdbcSelect .getLimitParameter () ).getBindValue ();
348358 }
349- if ( resultCountEstimate > 0 ) {
359+ else if ( resultCountEstimate > 0 ) {
350360 return resultCountEstimate ;
351361 }
352- return super .getResultCountEstimate ();
362+ else {
363+ return super .getResultCountEstimate ();
364+ }
353365 }
354366}
0 commit comments