001: // $Id: FetchingScrollableResultsImpl.java 7469 2005-07-14 13:12:19Z steveebersole $
002: package org.hibernate.impl;
003:
004: import org.hibernate.HibernateException;
005: import org.hibernate.MappingException;
006: import org.hibernate.exception.JDBCExceptionHelper;
007: import org.hibernate.hql.HolderInstantiator;
008: import org.hibernate.type.Type;
009: import org.hibernate.loader.Loader;
010: import org.hibernate.engine.SessionImplementor;
011: import org.hibernate.engine.QueryParameters;
012:
013: import java.sql.ResultSet;
014: import java.sql.PreparedStatement;
015: import java.sql.SQLException;
016:
017: /**
018: * Implementation of ScrollableResults which can handle collection fetches.
019: *
020: * @author Steve Ebersole
021: */
022: public class FetchingScrollableResultsImpl extends
023: AbstractScrollableResults {
024:
025: public FetchingScrollableResultsImpl(ResultSet rs,
026: PreparedStatement ps, SessionImplementor sess,
027: Loader loader, QueryParameters queryParameters,
028: Type[] types, HolderInstantiator holderInstantiator)
029: throws MappingException {
030: super (rs, ps, sess, loader, queryParameters, types,
031: holderInstantiator);
032: }
033:
034: private Object[] currentRow = null;
035: private int currentPosition = 0;
036: private Integer maxPosition = null;
037:
038: protected Object[] getCurrentRow() {
039: return currentRow;
040: }
041:
042: /**
043: * Advance to the next result
044: *
045: * @return <tt>true</tt> if there is another result
046: */
047: public boolean next() throws HibernateException {
048: if (maxPosition != null
049: && maxPosition.intValue() <= currentPosition) {
050: currentRow = null;
051: currentPosition = maxPosition.intValue() + 1;
052: return false;
053: }
054:
055: Object row = getLoader().loadSequentialRowsForward(
056: getResultSet(), getSession(), getQueryParameters(),
057: false);
058:
059: boolean afterLast;
060: try {
061: afterLast = getResultSet().isAfterLast();
062: } catch (SQLException e) {
063: throw JDBCExceptionHelper.convert(getSession().getFactory()
064: .getSQLExceptionConverter(), e,
065: "exception calling isAfterLast()");
066: }
067:
068: currentPosition++;
069: currentRow = new Object[] { row };
070:
071: if (afterLast) {
072: if (maxPosition == null) {
073: // we just hit the last position
074: maxPosition = new Integer(currentPosition);
075: }
076: }
077:
078: afterScrollOperation();
079:
080: return true;
081: }
082:
083: /**
084: * Retreat to the previous result
085: *
086: * @return <tt>true</tt> if there is a previous result
087: */
088: public boolean previous() throws HibernateException {
089: if (currentPosition <= 1) {
090: currentPosition = 0;
091: currentRow = null;
092: return false;
093: }
094:
095: Object loadResult = getLoader().loadSequentialRowsReverse(
096: getResultSet(),
097: getSession(),
098: getQueryParameters(),
099: false,
100: (maxPosition != null && currentPosition > maxPosition
101: .intValue()));
102:
103: currentRow = new Object[] { loadResult };
104: currentPosition--;
105:
106: afterScrollOperation();
107:
108: return true;
109:
110: }
111:
112: /**
113: * Scroll an arbitrary number of locations
114: *
115: * @param positions a positive (forward) or negative (backward) number of rows
116: *
117: * @return <tt>true</tt> if there is a result at the new location
118: */
119: public boolean scroll(int positions) throws HibernateException {
120: boolean more = false;
121: if (positions > 0) {
122: // scroll ahead
123: for (int i = 0; i < positions; i++) {
124: more = next();
125: if (!more) {
126: break;
127: }
128: }
129: } else if (positions < 0) {
130: // scroll backward
131: for (int i = 0; i < (0 - positions); i++) {
132: more = previous();
133: if (!more) {
134: break;
135: }
136: }
137: } else {
138: throw new HibernateException("scroll(0) not valid");
139: }
140:
141: afterScrollOperation();
142:
143: return more;
144: }
145:
146: /**
147: * Go to the last result
148: *
149: * @return <tt>true</tt> if there are any results
150: */
151: public boolean last() throws HibernateException {
152: boolean more = false;
153: if (maxPosition != null) {
154: for (int i = currentPosition; i < maxPosition.intValue(); i++) {
155: more = next();
156: }
157: } else {
158: try {
159: if (getResultSet().isAfterLast()) {
160: // should not be able to reach last without maxPosition being set
161: // unless there are no results
162: return false;
163: }
164:
165: while (!getResultSet().isAfterLast()) {
166: more = next();
167: }
168: } catch (SQLException e) {
169: throw JDBCExceptionHelper.convert(getSession()
170: .getFactory().getSQLExceptionConverter(), e,
171: "exception calling isAfterLast()");
172: }
173: }
174:
175: afterScrollOperation();
176:
177: return more;
178: }
179:
180: /**
181: * Go to the first result
182: *
183: * @return <tt>true</tt> if there are any results
184: */
185: public boolean first() throws HibernateException {
186: beforeFirst();
187: boolean more = next();
188:
189: afterScrollOperation();
190:
191: return more;
192: }
193:
194: /**
195: * Go to a location just before first result (this is the initial location)
196: */
197: public void beforeFirst() throws HibernateException {
198: try {
199: getResultSet().beforeFirst();
200: } catch (SQLException e) {
201: throw JDBCExceptionHelper.convert(getSession().getFactory()
202: .getSQLExceptionConverter(), e,
203: "exception calling beforeFirst()");
204: }
205: currentRow = null;
206: currentPosition = 0;
207: }
208:
209: /**
210: * Go to a location just after the last result
211: */
212: public void afterLast() throws HibernateException {
213: // TODO : not sure the best way to handle this.
214: // The non-performant way :
215: last();
216: next();
217: afterScrollOperation();
218: }
219:
220: /**
221: * Is this the first result?
222: *
223: * @return <tt>true</tt> if this is the first row of results
224: *
225: * @throws org.hibernate.HibernateException
226: */
227: public boolean isFirst() throws HibernateException {
228: return currentPosition == 1;
229: }
230:
231: /**
232: * Is this the last result?
233: *
234: * @return <tt>true</tt> if this is the last row of results
235: *
236: * @throws org.hibernate.HibernateException
237: */
238: public boolean isLast() throws HibernateException {
239: if (maxPosition == null) {
240: // we have not yet hit the last result...
241: return false;
242: } else {
243: return currentPosition == maxPosition.intValue();
244: }
245: }
246:
247: /**
248: * Get the current location in the result set. The first row is number <tt>0</tt>, contrary to JDBC.
249: *
250: * @return the row number, numbered from <tt>0</tt>, or <tt>-1</tt> if there is no current row
251: */
252: public int getRowNumber() throws HibernateException {
253: return currentPosition;
254: }
255:
256: /**
257: * Set the current location in the result set, numbered from either the first row (row number <tt>0</tt>), or the last
258: * row (row number <tt>-1</tt>).
259: *
260: * @param rowNumber the row number, numbered from the last row, in the case of a negative row number
261: *
262: * @return true if there is a row at that row number
263: */
264: public boolean setRowNumber(int rowNumber)
265: throws HibernateException {
266: if (rowNumber == 1) {
267: return first();
268: } else if (rowNumber == -1) {
269: return last();
270: } else if (maxPosition != null
271: && rowNumber == maxPosition.intValue()) {
272: return last();
273: }
274: return scroll(rowNumber - currentPosition);
275: }
276: }
|