org.hibernate.internal.FetchingScrollableResultsImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hibernate-core Show documentation
Show all versions of hibernate-core Show documentation
The core O/RM functionality as provided by Hibernate
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.internal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.hql.internal.HolderInstantiator;
import org.hibernate.loader.Loader;
import org.hibernate.type.Type;
/**
* Implementation of ScrollableResults which can handle collection fetches.
*
* @author Steve Ebersole
*/
public class FetchingScrollableResultsImpl extends AbstractScrollableResults {
public FetchingScrollableResultsImpl(
ResultSet rs,
PreparedStatement ps,
SessionImplementor sess,
Loader loader,
QueryParameters queryParameters,
Type[] types,
HolderInstantiator holderInstantiator) throws MappingException {
super( rs, ps, sess, loader, queryParameters, types, holderInstantiator );
}
private Object[] currentRow = null;
private int currentPosition = 0;
private Integer maxPosition = null;
@Override
protected Object[] getCurrentRow() {
return currentRow;
}
/**
* Advance to the next result
*
* @return true if there is another result
*/
public boolean next() throws HibernateException {
if ( maxPosition != null && maxPosition.intValue() <= currentPosition ) {
currentRow = null;
currentPosition = maxPosition.intValue() + 1;
return false;
}
if ( isResultSetEmpty() ) {
currentRow = null;
currentPosition = 0;
return false;
}
Object row = getLoader().loadSequentialRowsForward(
getResultSet(),
getSession(),
getQueryParameters(),
false
);
boolean afterLast;
try {
afterLast = getResultSet().isAfterLast();
}
catch( SQLException e ) {
throw getSession().getFactory().getSQLExceptionHelper().convert(
e,
"exception calling isAfterLast()"
);
}
currentPosition++;
currentRow = new Object[] { row };
if ( afterLast ) {
if ( maxPosition == null ) {
// we just hit the last position
maxPosition = currentPosition;
}
}
afterScrollOperation();
return true;
}
/**
* Retreat to the previous result
*
* @return true if there is a previous result
*/
public boolean previous() throws HibernateException {
if ( currentPosition <= 1 ) {
currentPosition = 0;
currentRow = null;
return false;
}
Object loadResult = getLoader().loadSequentialRowsReverse(
getResultSet(),
getSession(),
getQueryParameters(),
false,
( maxPosition != null && currentPosition > maxPosition.intValue() )
);
currentRow = new Object[] { loadResult };
currentPosition--;
afterScrollOperation();
return true;
}
/**
* Scroll an arbitrary number of locations
*
* @param positions a positive (forward) or negative (backward) number of rows
*
* @return true if there is a result at the new location
*/
public boolean scroll(int positions) throws HibernateException {
boolean more = false;
if ( positions > 0 ) {
// scroll ahead
for ( int i = 0; i < positions; i++ ) {
more = next();
if ( !more ) {
break;
}
}
}
else if ( positions < 0 ) {
// scroll backward
for ( int i = 0; i < ( 0 - positions ); i++ ) {
more = previous();
if ( !more ) {
break;
}
}
}
else {
throw new HibernateException( "scroll(0) not valid" );
}
afterScrollOperation();
return more;
}
/**
* Go to the last result
*
* @return true if there are any results
*/
public boolean last() throws HibernateException {
boolean more = false;
if ( maxPosition != null ) {
if ( currentPosition > maxPosition.intValue() ) {
more = previous();
}
for ( int i = currentPosition; i < maxPosition.intValue(); i++ ) {
more = next();
}
}
else {
try {
if ( isResultSetEmpty() || getResultSet().isAfterLast() ) {
// should not be able to reach last without maxPosition being set
// unless there are no results
return false;
}
while ( !getResultSet().isAfterLast() ) {
more = next();
}
}
catch( SQLException e ) {
throw getSession().getFactory().getSQLExceptionHelper().convert(
e,
"exception calling isAfterLast()"
);
}
}
afterScrollOperation();
return more;
}
/**
* Go to the first result
*
* @return true if there are any results
*/
public boolean first() throws HibernateException {
beforeFirst();
boolean more = next();
afterScrollOperation();
return more;
}
/**
* Go to a location just before first result (this is the initial location)
*/
public void beforeFirst() throws HibernateException {
try {
getResultSet().beforeFirst();
}
catch( SQLException e ) {
throw getSession().getFactory().getSQLExceptionHelper().convert(
e,
"exception calling beforeFirst()"
);
}
currentRow = null;
currentPosition = 0;
}
/**
* Go to a location just after the last result
*/
public void afterLast() throws HibernateException {
// TODO : not sure the best way to handle this.
// The non-performant way :
last();
next();
afterScrollOperation();
}
/**
* Is this the first result?
*
* @return true if this is the first row of results
*
* @throws org.hibernate.HibernateException
*/
public boolean isFirst() throws HibernateException {
return currentPosition == 1;
}
/**
* Is this the last result?
*
* @return true if this is the last row of results
*
* @throws org.hibernate.HibernateException
*/
public boolean isLast() throws HibernateException {
if ( maxPosition == null ) {
// we have not yet hit the last result...
return false;
}
else {
return currentPosition == maxPosition.intValue();
}
}
/**
* Get the current location in the result set. The first row is number 0, contrary to JDBC.
*
* @return the row number, numbered from 0, or -1 if there is no current row
*/
public int getRowNumber() throws HibernateException {
return currentPosition;
}
/**
* Set the current location in the result set, numbered from either the first row (row number 0), or the last
* row (row number -1).
*
* @param rowNumber the row number, numbered from the last row, in the case of a negative row number
*
* @return true if there is a row at that row number
*/
public boolean setRowNumber(int rowNumber) throws HibernateException {
if ( rowNumber == 1 ) {
return first();
}
else if ( rowNumber == -1 ) {
return last();
}
else if ( maxPosition != null && rowNumber == maxPosition.intValue() ) {
return last();
}
return scroll( rowNumber - currentPosition );
}
private boolean isResultSetEmpty() {
try {
return currentPosition == 0 && ! getResultSet().isBeforeFirst() && ! getResultSet().isAfterLast();
}
catch( SQLException e ) {
throw getSession().getFactory().getSQLExceptionHelper().convert(
e,
"Could not determine if resultset is empty due to exception calling isBeforeFirst or isAfterLast()"
);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy