@Override public LimitHandler getLimitHandler() { return new AbstractLimitHandler() { @Override public boolean supportsLimit() { return true; } @Override public String processSql(String sql, RowSelection selection) { if (LimitHelper.useLimit(this, selection)) { final boolean hasMaxRows = LimitHelper.hasMaxRows(selection); final boolean hasOffset = LimitHelper.hasFirstRow(selection); return sql + (hasMaxRows ? " limit ?" : "") + (hasOffset ? " offset ?" : ""); } return sql; } }; }
private List doTheLoad(String sql, QueryParameters queryParameters, SessionImplementor session) throws SQLException { final RowSelection selection = queryParameters.getRowSelection(); final int maxRows = LimitHelper.hasMaxRows( selection ) ? selection.getMaxRows() : Integer.MAX_VALUE; 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 ); } finally { session.getTransactionCoordinator().getJdbcCoordinator().release( st ); } }
/** * Advance the cursor to the first required row of the <tt>ResultSet</tt> */ private void advance(final ResultSet rs, final RowSelection selection) throws SQLException { final int firstRow = LimitHelper.getFirstRow( selection ); if ( firstRow != 0 ) { if ( getFactory().getSettings().isScrollableResultSetsEnabled() ) { // we can go straight to the first required row rs.absolute( firstRow ); } else { // we need to step through the rows one row at a time (slow) for ( int m = 0; m < firstRow; m++ ) rs.next(); } } }
/** * Execute given <tt>PreparedStatement</tt>, advance to the first result and return SQL <tt>ResultSet</tt>. */ protected final ResultSet getResultSet( final PreparedStatement st, final RowSelection selection, final LimitHandler limitHandler, final boolean autodiscovertypes, final SessionImplementor session) throws SQLException, HibernateException { try { ResultSet rs = session.getTransactionCoordinator().getJdbcCoordinator().getResultSetReturn().extract( st ); rs = wrapResultSetIfEnabled( rs , session ); if ( !limitHandler.supportsLimitOffset() || !LimitHelper.useLimit( limitHandler, selection ) ) { advance( rs, selection ); } if ( autodiscovertypes ) { autoDiscoverTypes( rs ); } return rs; } catch ( SQLException sqle ) { session.getTransactionCoordinator().getJdbcCoordinator().release( st ); throw sqle; } }
private void doTheLoad(String sql, QueryParameters queryParameters, SessionImplementor session) throws SQLException { final RowSelection selection = queryParameters.getRowSelection(); final int maxRows = LimitHelper.hasMaxRows( selection ) ? selection.getMaxRows() : Integer.MAX_VALUE; final List<AfterLoadAction> afterLoadActions = Collections.emptyList(); 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 ); } finally { session.getTransactionCoordinator().getJdbcCoordinator().release( st ); } }
/** * Advance the cursor to the first required row of the <tt>ResultSet</tt> */ protected void advance(final ResultSet rs, final RowSelection selection) throws SQLException { final int firstRow = LimitHelper.getFirstRow( selection ); if ( firstRow != 0 ) { if ( getFactory().getSettings().isScrollableResultSetsEnabled() ) { // we can go straight to the first required row rs.absolute( firstRow ); } else { // we need to step through the rows one row at a time (slow) for ( int m = 0; m < firstRow; m++ ) { rs.next(); } } } }
@Override public String processSql(String sql, RowSelection selection) { if (LimitHelper.hasFirstRow(selection)) { return sql + " limit ? offset ?"; } else { return sql + " limit ?"; } }
@Before public void setup() { limitHandler = new SQLiteLimitHandler(); rowSelection = new RowSelection(); PowerMockito.mockStatic(LimitHelper.class); }
private List doQuery( final SessionImplementor session, final QueryParameters queryParameters, final boolean returnProxies, final ResultTransformer forcedResultTransformer) throws SQLException, HibernateException { final RowSelection selection = queryParameters.getRowSelection(); final int maxRows = LimitHelper.hasMaxRows( selection ) ? selection.getMaxRows() : Integer.MAX_VALUE; final List<AfterLoadAction> afterLoadActions = new ArrayList<AfterLoadAction>(); 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. // // Would need to change the way the max-row stuff is handled (i.e. behind an interface) so // that I could do the control breaking at the means to know when to stop try { return processResultSet( rs, queryParameters, session, returnProxies, forcedResultTransformer, maxRows, afterLoadActions ); } finally { session.getTransactionCoordinator().getJdbcCoordinator().release( st ); } }
@Override public String getProcessedSql() { if ( LimitHelper.useLimit( this, selection ) ) { // useLimitOffset: whether "offset" is set or not; // if set, use "LIMIT offset, row_count" syntax; // if not, use "LIMIT row_count" final boolean useLimitOffset = LimitHelper.hasFirstRow( selection ); return sql + (useLimitOffset ? " limit ? offset ?" : " limit ?"); } else { // or return unaltered SQL return sql; } }
@Test public void processSqlHasOffset() { when(LimitHelper.hasFirstRow(rowSelection)).thenReturn(true); assertEquals("sql limit ? offset ?", limitHandler.processSql("sql", rowSelection)); }
@Test public void processSqlDoesNotHaveOffset() { when(LimitHelper.hasFirstRow(rowSelection)).thenReturn(false); assertEquals("sql limit ?", limitHandler.processSql("sql", rowSelection)); }
@Override public String processSql(String sql, RowSelection selection) { final boolean hasOffset = LimitHelper.hasFirstRow(selection); return sql + (hasOffset ? " limit ? offset ?" : " limit ?"); }
@Override public List extractResults( ResultSet resultSet, final SessionImplementor session, QueryParameters queryParameters, NamedParameterContext namedParameterContext, boolean returnProxies, boolean readOnly, ResultTransformer forcedResultTransformer, List<AfterLoadAction> afterLoadActionList) throws SQLException { handlePotentiallyEmptyCollectionRootReturns( loadPlan, queryParameters.getCollectionKeys(), resultSet, session ); final int maxRows; final RowSelection selection = queryParameters.getRowSelection(); if ( LimitHelper.hasMaxRows( selection ) ) { maxRows = selection.getMaxRows(); LOG.tracef( "Limiting ResultSet processing to just %s rows", maxRows ); } else { maxRows = Integer.MAX_VALUE; } // There are times when the "optional entity information" on QueryParameters should be used and // times when they should be ignored. Loader uses its isSingleRowLoader method to allow // subclasses to override that. Collection initializers, batch loaders, e.g. override that // it to be false. The 'shouldUseOptionalEntityInstance' setting is meant to fill that same role. final boolean shouldUseOptionalEntityInstance = true; // Handles the "FETCH ALL PROPERTIES" directive in HQL final boolean forceFetchLazyAttributes = false; final ResultSetProcessingContextImpl context = new ResultSetProcessingContextImpl( resultSet, session, loadPlan, readOnly, shouldUseOptionalEntityInstance, forceFetchLazyAttributes, returnProxies, queryParameters, namedParameterContext, hadSubselectFetches ); final List loadResults = new ArrayList(); LOG.trace( "Processing result set" ); int count; for ( count = 0; count < maxRows && resultSet.next(); count++ ) { LOG.debugf( "Starting ResultSet row #%s", count ); Object logicalRow = rowReader.readRow( resultSet, context ); // todo : apply transformers here? loadResults.add( logicalRow ); context.finishUpRow(); } LOG.tracev( "Done processing result set ({0} rows)", count ); rowReader.finishUp( context, afterLoadActionList ); context.wrapUp(); session.getPersistenceContext().initializeNonLazyCollections(); return loadResults; }
/** * Obtain a <tt>PreparedStatement</tt> with all parameters pre-bound. * Bind JDBC-style <tt>?</tt> parameters, named parameters, and * limit parameters. */ protected final PreparedStatement prepareQueryStatement( final String sql, final QueryParameters queryParameters, final LimitHandler limitHandler, final boolean scroll, final SessionImplementor session) throws SQLException, HibernateException { final Dialect dialect = getFactory().getDialect(); final RowSelection selection = queryParameters.getRowSelection(); final boolean useLimit = LimitHelper.useLimit( limitHandler, selection ); final boolean hasFirstRow = LimitHelper.hasFirstRow( selection ); final boolean useLimitOffset = hasFirstRow && useLimit && limitHandler.supportsLimitOffset(); final boolean callable = queryParameters.isCallable(); final ScrollMode scrollMode = getScrollMode( scroll, hasFirstRow, useLimitOffset, queryParameters ); final PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator() .getStatementPreparer().prepareQueryStatement( sql, callable, scrollMode ); try { int col = 1; //TODO: can we limit stored procedures ?! col += limitHandler.bindLimitParametersAtStartOfQuery( st, col ); if (callable) { col = dialect.registerResultSetOutParameter( (CallableStatement)st, col ); } col += bindParameterValues( st, queryParameters, col, session ); col += limitHandler.bindLimitParametersAtEndOfQuery( st, col ); limitHandler.setMaxRows( st ); if ( selection != null ) { if ( selection.getTimeout() != null ) { st.setQueryTimeout( selection.getTimeout() ); } if ( selection.getFetchSize() != null ) { st.setFetchSize( selection.getFetchSize() ); } } // handle lock timeout... final LockOptions lockOptions = queryParameters.getLockOptions(); if ( lockOptions != null ) { if ( lockOptions.getTimeOut() != LockOptions.WAIT_FOREVER ) { if ( !dialect.supportsLockTimeouts() ) { if ( log.isDebugEnabled() ) { log.debugf( "Lock timeout [%s] requested but dialect reported to not support lock timeouts", lockOptions.getTimeOut() ); } } else if ( dialect.isLockTimeoutParameterized() ) { st.setInt( col++, lockOptions.getTimeOut() ); } } } if ( log.isTraceEnabled() ) { log.tracev( "Bound [{0}] parameters total", col ); } } catch ( SQLException sqle ) { session.getTransactionCoordinator().getJdbcCoordinator().release( st ); throw sqle; } catch ( HibernateException he ) { session.getTransactionCoordinator().getJdbcCoordinator().release( st ); throw he; } return st; }
/** * Build LIMIT clause handler applicable for given selection criteria. Returns {@link NoopLimitHandler} delegate * if dialect does not support LIMIT expression or processed query does not use pagination. * * @param sql Query string. * @param selection Selection criteria. * @return LIMIT clause delegate. */ protected LimitHandler getLimitHandler(String sql, RowSelection selection) { final LimitHandler limitHandler = getFactory().getDialect().buildLimitHandler( sql, selection ); return LimitHelper.useLimit( limitHandler, selection ) ? limitHandler : new NoopLimitHandler( sql, selection ); }
/** * Build LIMIT clause handler applicable for given selection criteria. Returns {@link org.hibernate.dialect.pagination.NoopLimitHandler} delegate * if dialect does not support LIMIT expression or processed query does not use pagination. * * @param sql Query string. * @param selection Selection criteria. * @return LIMIT clause delegate. */ protected LimitHandler getLimitHandler(String sql, RowSelection selection) { final LimitHandler limitHandler = getFactory().getDialect().buildLimitHandler( sql, selection ); return LimitHelper.useLimit( limitHandler, selection ) ? limitHandler : new NoopLimitHandler( sql, selection ); }