001: package org.mandarax.jdbc.client;
002:
003: /*
004: * Copyright (C) 1999-2004 <a href="mailto:mandarax@jbdietrich.com">Jens Dietrich</a>
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020:
021: import java.sql.*;
022: import java.util.*;
023:
024: import org.mandarax.jdbc.AbstractReadOnlyResultSet;
025: import org.mandarax.jdbc.rpc.Call;
026: import org.mandarax.jdbc.rpc.Transport;
027:
028: /**
029: * Result set implementation. All update related features are not supported -
030: * a UnsupportedFeatureException will be thrown.
031: * @author <A HREF="mailto:mandarax@jbdietrich.com">Jens Dietrich</A>
032: * @version 3.3.2 <29 December 2004>
033: * @since 3.0
034: */
035:
036: class ResultSetImpl extends AbstractReadOnlyResultSet implements
037: ClientObject {
038:
039: private List records = new Vector();
040: private Statement statement = null;
041: private ResultSetMetaData metaData = null;
042: private int cursor = 0;
043: private int size = -1;
044: private boolean noMoreRows = false;
045: private Map columnIndexesByName = null;
046:
047: // the transport used
048: private Transport transport = null;
049: // the id used to identify the associated server object
050: private String id = null;
051: // this is the number of rows fetched per request (buffer size)
052: private int fetchSize = 1;
053:
054: /**
055: * Constructor.
056: * @param metaData the meta data
057: * @param statement the statement (the factory that produced this result set)
058: * @param transport the transport object used
059: */
060: ResultSetImpl(ResultSetMetaData metaData, Statement statement,
061: Transport transport) throws SQLException {
062: super ();
063: this .metaData = metaData;
064: this .statement = statement;
065: this .transport = transport;
066: columnIndexesByName = new HashMap(metaData.getColumnCount());
067: for (int i = 0; i < metaData.getColumnCount(); i++) {
068: columnIndexesByName.put(metaData.getColumnName(i + 1),
069: new Integer(i + 1));
070: }
071: }
072:
073: /**
074: * Move cursor to the next position.
075: * @return boolean
076: * @throws java.sql.SQLException
077: */
078: public boolean next() throws SQLException {
079: return moveCursor(cursor + 1);
080: }
081:
082: /**
083: * Close the result set.
084: * @throws java.sql.SQLException
085: */
086: public void close() throws SQLException {
087: records = null;
088: transport.perform(new Call(id, "Close"));
089: }
090:
091: /**
092: * Return the result set meta data.
093: * @return java.sql.ResultSetMetaData
094: * @throws java.sql.SQLException
095: */
096: public ResultSetMetaData getMetaData() throws SQLException {
097: return metaData;
098: }
099:
100: /**
101: * Get the object in the result at a certain index.
102: * @param columnIndex
103: * @return java.lang.Object
104: * @throws java.sql.SQLException
105: */
106: public Object getObject(int columnIndex) throws SQLException {
107: if (isValid()) {
108: Record row = (Record) records.get(cursor - 1);
109: return row.getValues()[columnIndex - 1];
110: } else
111: throw new SQLException(
112: "Invalid cursor position - cannot fetch value from null row");
113: }
114:
115: /**
116: * Get the result for a certain slot (column) name.
117: * @param columnName
118: * @return java.lang.Object
119: * @throws java.sql.SQLException
120: */
121: public Object getObject(String columnName) throws SQLException {
122: int colIndex = findColumn(columnName);
123: return getObject(colIndex);
124: }
125:
126: /**
127: * Find the column (=slot) index.
128: * @param columnName
129: * @return int
130: * @throws java.sql.SQLException
131: */
132: public int findColumn(String columnName) throws SQLException {
133: Integer index = (Integer) columnIndexesByName.get(columnName);
134: return index == null ? -1 : index.intValue();
135: }
136:
137: /**
138: * Retrieves whether the cursor is before the first row in this ResultSet object.
139: * @return boolean
140: * @throws java.sql.SQLException
141: */
142: public boolean isBeforeFirst() throws SQLException {
143: return cursor == 0;
144: }
145:
146: /**
147: * Retrieves whether the cursor is after the last row in this ResultSet object.
148: * @return boolean
149: * @throws java.sql.SQLException
150: */
151: public boolean isAfterLast() throws SQLException {
152: return noMoreRows && cursor >= records.size();
153: }
154:
155: /**
156: * Retrieves whether the cursor is on the first row of this ResultSet object.
157: * @return boolean
158: * @throws java.sql.SQLException
159: */
160: public boolean isFirst() throws SQLException {
161: return cursor == 1;
162: }
163:
164: /**
165: * Retrieves whether the cursor is on the last row of this ResultSet object.
166: * @return boolean
167: * @throws java.sql.SQLException
168: */
169: public boolean isLast() throws SQLException {
170: return noMoreRows && cursor == records.size();
171: }
172:
173: /**
174: * Moves the cursor to the front of this ResultSet object,
175: * just before the first row. This method has no effect if the result set contains no rows.
176: * @throws java.sql.SQLException
177: */
178: public void beforeFirst() throws SQLException {
179: moveCursor(-1);
180: }
181:
182: /**
183: * Moves the cursor to the end of this ResultSet object,
184: * just after the last row. This method has no effect if the result set contains no rows.
185: * @throws java.sql.SQLException
186: */
187: public void afterLast() throws SQLException {
188: last();
189: moveCursor(cursor + 1);
190: }
191:
192: /**
193: * Moves the cursor to the first row in this ResultSet object.
194: * @return boolean
195: * @throws java.sql.SQLException
196: */
197: public boolean first() throws SQLException {
198: return moveCursor(1);
199: }
200:
201: /**
202: * Moves the cursor to the last row in this ResultSet object.
203: * @return boolean
204: * @throws java.sql.SQLException
205: */
206: public boolean last() throws SQLException {
207: if (!isValid() && cursor > 0)
208: return previous();
209: while (next()) {
210: }
211: ;
212: return isValid();
213: }
214:
215: /**
216: * Retrieves the current row number. The first row is number 1, the second number 2, and so on.
217: * @return int
218: * @throws java.sql.SQLException
219: */
220: public int getRow() throws SQLException {
221: return cursor;
222: }
223:
224: /**
225: * Moves the cursor to the given result number in this ResultSet object.
226: * @param row
227: * @return boolean
228: * @throws java.sql.SQLException
229: */
230: public boolean absolute(int row) throws SQLException {
231: return moveCursor(row);
232: }
233:
234: /**
235: * Moves the cursor a relative number of results, either positive or negative.
236: * @param rows
237: * @return boolean
238: * @throws java.sql.SQLException
239: */
240: public boolean relative(int rows) throws SQLException {
241: return moveCursor(cursor + rows);
242: }
243:
244: /**
245: * Move the cursor to the previous position.
246: * @return boolean
247: * @throws java.sql.SQLException
248: */
249: public boolean previous() throws SQLException {
250: return moveCursor(cursor - 1);
251: }
252:
253: /**
254: * Get the statement.
255: * @return java.sql.Statement
256: * @throws java.sql.SQLException
257: */
258: public Statement getStatement() throws SQLException {
259: return statement;
260: }
261:
262: /**
263: * Indicates whether the cursor is at a valid position.
264: * @return a boolean
265: */
266: private boolean isValid() {
267: return cursor > 0 && cursor < records.size() + 1;
268: }
269:
270: /**
271: * Move the cursor to a position.
272: * @param position the new (absolute) position
273: * @return a boolean - indicating whether the cursor is on a valid position
274: */
275: private boolean moveCursor(int position) throws SQLException {
276: while (!noMoreRows && position > records.size())
277: fetchMore();
278: cursor = position;
279: return isValid();
280: }
281:
282: /**
283: * Fetch more records.
284: * @throws java.sql.SQLException
285: */
286: private void fetchMore() throws SQLException {
287: List nextRecords = (List) transport.perform(new Call(id,
288: "ResultSet_nextRows", new Object[] { new Integer(
289: this .fetchSize) }));
290: noMoreRows = nextRecords == null || nextRecords.size() == 0;
291: if (!noMoreRows) {
292: records.addAll(nextRecords);
293: }
294: }
295:
296: /**
297: * Get the id.
298: * @return the id
299: */
300: public String getId() {
301: return id;
302: }
303:
304: /**
305: * Set the id.
306: * @param id the new id
307: */
308: public void setId(String id) {
309: this .id = id;
310: }
311:
312: /**
313: * Get the fetch size. This is the number of rows fetched per request (buffer size).
314: * @return a number
315: */
316: public int getFetchSize() {
317: return fetchSize;
318: }
319:
320: /**
321: * Set the fetch size. This is the number of rows fetched per request (buffer size).
322: * @param fetchSize the new fetch size
323: */
324: public void setFetchSize(int fetchSize) {
325: if (fetchSize < 1)
326: throw new IllegalArgumentException(
327: "The fetch size must be >= 1!");
328: this.fetchSize = fetchSize;
329: }
330:
331: }
|