KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > cjdbc > driver > DriverResultSet


1 /**
2  * C-JDBC: Clustered JDBC.
3  * Copyright (C) 2002-2005 French National Institute For Research In Computer
4  * Science And Control (INRIA).
5  * Contact: c-jdbc@objectweb.org
6  *
7  * This library is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by the
9  * Free Software Foundation; either version 2.1 of the License, or any later
10  * version.
11  *
12  * This library is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
15  * for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation,
19  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20  *
21  * Initial developer(s): Mark Matthews.
22  * Contributor(s): Emmanuel Cecchet, Andre Austin, Marc Wick, Jean-Bernard
23  * van Zuylen, Marc Herbert.
24  */

25
26 package org.objectweb.cjdbc.driver;
27
28 import java.io.ByteArrayInputStream JavaDoc;
29 import java.io.IOException JavaDoc;
30 import java.io.InputStream JavaDoc;
31 import java.io.NotSerializableException JavaDoc;
32 import java.io.ObjectInputStream JavaDoc;
33 import java.math.BigDecimal JavaDoc;
34 import java.math.BigInteger JavaDoc;
35 import java.net.URL JavaDoc;
36 import java.sql.PreparedStatement JavaDoc;
37 import java.sql.Ref JavaDoc;
38 import java.sql.ResultSet JavaDoc;
39 import java.sql.SQLException JavaDoc;
40 import java.sql.SQLWarning JavaDoc;
41 import java.sql.Time JavaDoc;
42 import java.sql.Timestamp JavaDoc;
43 import java.util.ArrayList JavaDoc;
44 import java.util.Calendar JavaDoc;
45 import java.util.Hashtable JavaDoc;
46 import java.util.Iterator JavaDoc;
47
48 import org.objectweb.cjdbc.common.exceptions.NotImplementedException;
49 import org.objectweb.cjdbc.common.exceptions.ProtocolException;
50 import org.objectweb.cjdbc.common.stream.CJDBCInputStream;
51 import org.objectweb.cjdbc.common.stream.CJDBCOutputStream;
52 import org.objectweb.cjdbc.driver.protocol.SQLDataSerialization;
53 import org.objectweb.cjdbc.driver.protocol.TypeTag;
54
55 /**
56  * A <code>ResultSet</code> provides access to a table of data generated by
57  * executing a Statement. The table rows are retrieved in sequence. Within a row
58  * its column values can be accessed in any order.
59  * <p>
60  * A <code>ResultSet</code> maintains a cursor pointing to its current row of
61  * data. Initially the cursor is positioned before the first row. The 'next'
62  * method moves the cursor to the next row.
63  * <p>
64  * The <code>getXXX</code> methods retrieve column values for the current row.
65  * You can retrieve values either using the index number of the column, or by
66  * using the name of the column. In general using the column index will be more
67  * efficient. Columns are numbered from 1.
68  * <p>
69  * For maximum portability, <code>ResultSet</code> columns within each row
70  * should be read in left-to-right order and each column should be read only
71  * once.
72  * <p>
73  * For the <code>getXXX</code> methods, the JDBC driver attempts to convert
74  * the underlying data to the specified Java type and returns a suitable Java
75  * value. See the JDBC specification for allowable mappings from SQL types to
76  * Java types with the <code>ResultSet</code> <code>getXXX</code> methods.
77  * <p>
78  * Column names used as input to <code>getXXX</code> methods are case
79  * insenstive. When performing a <code>getXXX</code> using a column name, if
80  * several columns have the same name, then the value of the first matching
81  * column will be returned. The column name option is designed to be used when
82  * column names are used in the SQL Query. For columns that are NOT explicitly
83  * named in the query, it is best to use column numbers. If column names were
84  * used there is no way for the programmer to guarentee that they actually refer
85  * to the intended columns.
86  * <P>
87  * A <code>ResultSet</code> is automatically closed by the
88  * <code>Statement</code> that generated it when that <code>Statement</code>
89  * is closed, re-executed, or is used to retrieve the next result from a
90  * sequence of multiple results.
91  * <P>
92  * The number, types and properties of a ResultSet's columns are provided by the
93  * <code>ResultSetMetaData</code> object returned by the
94  * <code>getMetaData</code> method.
95  *
96  * @see java.sql.ResultSetMetaData
97  * @see java.sql.ResultSet
98  * @author Mark Matthews <mmatthew@worldserver.com>
99  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
100  * @author <a HREF="mailto:alexander.laamanen@tecnomen.com">Alexander Laamanen
101  * </a>
102  * @author <a HREF="mailto:Nicolas.Modrzyk@inrialpes.fr">Nicolas Modrzyk </a>
103  * @author <a HREF="mailto:jbvanzuylen@transwide.com">Jean-Bernard van Zuylen
104  * </a>
105  * @author <a HREF="mailto:Marc.Herbert@emicnetworks.com">Marc Herbert </a>
106  * @version 1.0
107  */

108 public class DriverResultSet
109     implements
110       java.sql.ResultSet JavaDoc,
111       java.io.Serializable JavaDoc,
112       java.lang.Cloneable JavaDoc
113 {
114   private static final long serialVersionUID = 7408879935608629886L;
115
116   /** Cursor to current row */
117   protected int currentRow = -1;
118   /** Number of rows */
119   protected int nbOfRows = -1;
120   /** Number of columns */
121   protected int nbOfColumns = -1;
122   /** The results */
123   protected ArrayList JavaDoc data;
124   /** True if there is more data to fetch from the controller */
125   private boolean hasMoreData;
126   /** The fetch direction (not used yet) */
127   protected int fetchDirection = FETCH_FORWARD;
128   /** The fetch size */
129   protected int fetchSize = 0;
130   /** ResultSet cursor name */
131   private String JavaDoc cursorName;
132
133   /** The fields */
134   protected Field[] fields;
135
136   /** Pointers to column-specific de/serializer */
137   private SQLDataSerialization.Serializer[] serializers;
138
139   /** for wasNull() */
140   protected boolean wasNullFlag = false;
141   /** column name -> index in ResultSet data array */
142   protected transient Hashtable JavaDoc columnNameToIndex = null;
143   /** full column name -> index in ResultSet data array */
144   protected transient Hashtable JavaDoc fullColumnNameToIndex = null;
145
146   /** Type of ResultSet */
147   protected int resultSetType = 0;
148   /** Concurrency for this ResultSet */
149   protected int resultSetConcurrency = 0;
150   /** the warning chain */
151   protected SQLWarning JavaDoc warnings = null;
152   /** Statement corresponding to this ResultSet, if any (not for metadata) */
153   protected transient Statement owningStatement;
154   /** The driver connection we were received from (null on the controller side) */
155   private final Connection connection;
156
157   private boolean isClosed = true;
158
159   /** Statement for deleting rows with Updatable ResultSets * */
160   private transient PreparedStatement deleteStatement = null;
161   /** Statement for inserting rows with Updatable ResultSets * */
162   private transient PreparedStatement insertStatement = null;
163   /** Statement for refreshing rows with Updatable ResultSets * */
164   private transient PreparedStatement refreshStatement = null;
165   /** Statement for updating rows with Updatable ResultSets * */
166   private transient PreparedStatement updateStatement = null;
167   /** Indicates whether cursor is on the insert row * */
168   private transient boolean inserting = false;
169   /** Indicates if the current row is being updated * */
170   private transient boolean updating = false;
171   /** Temporary object for not yet comitted ResultSet updates * */
172   private transient Object JavaDoc[] tempRow = null;
173   /** Cache the columns forming the primary key * */
174   private transient String JavaDoc[] primaryKeyColumns = null;
175
176   private static final String JavaDoc UPDATEABLE_MESSAGE = "ResultSet not updateable. The "
177                                                                       + "query that generated this result set must select only one table, and must "
178                                                                       + "select all primary keys from that table. See the JDBC 2.1 API Specification, "
179                                                                       + "section 5.6 for more details.";
180
181   // ---------------------------------------------------------------------
182
// Traversal/Positioning
183
// ---------------------------------------------------------------------
184

185   /**
186    * A ResultSet is initially positioned before its first row, the first call to
187    * next makes the first row the current row; the second call makes the second
188    * row the current row, etc.
189    * <p>
190    * If an input stream from the previous row is open, it is implicitly closed.
191    * The ResultSet's warning chain is cleared when a new row is read
192    *
193    * @return <code>true</code> if the new current is valid; <code>false</code>
194    * if there are no more rows
195    * @exception java.sql.SQLException if a database access error occurs
196    */

197   public boolean next() throws java.sql.SQLException JavaDoc
198   {
199     checkIfClosed();
200
201     if (inserting)
202     {
203       insertStatement.clearParameters();
204       tempRow = null;
205       inserting = false;
206     }
207
208     if (updating)
209       cancelRowUpdates();
210
211     if (nbOfRows == 0)
212       return false;
213
214     if (currentRow + 1 >= nbOfRows)
215     {
216       if (hasMoreData)
217       {
218         this.connection.fetchNextData(cursorName, fetchSize, this);
219         currentRow = 0;
220         if (data == null)
221         {
222           nbOfRows = 0;
223           return false;
224         }
225         else
226         {
227           nbOfRows = data.size();
228           return true;
229         }
230       }
231
232       // force scroll past end
233
currentRow = nbOfRows;
234       return false;
235     }
236
237     clearWarnings();
238     currentRow++;
239     return true;
240   }
241
242   /**
243    * The prev method is not part of JDBC, but because of the architecture of
244    * this driver it is possible to move both forward and backward within the
245    * result set.
246    * <p>
247    * If an input stream from the previous row is open, it is implicitly closed.
248    * The ResultSet's warning chain is cleared when a new row is read
249    *
250    * @return <code>true</code> if the new current is valid; <code>false</code>
251    * if there are no more rows
252    * @exception SQLException if a database access error occurs
253    */

254   public boolean prev() throws SQLException JavaDoc
255   {
256     checkIfClosed();
257
258     if (inserting)
259     {
260       insertStatement.clearParameters();
261       tempRow = null;
262       inserting = false;
263     }
264
265     if (updating)
266       cancelRowUpdates();
267
268     if (currentRow - 1 >= 0)
269     {
270       currentRow--;
271       return true;
272     }
273
274     return false;
275   }
276
277   /**
278    * JDBC 2.0.
279    * <p>
280    * Determine if the cursor is before the first row in the result set.
281    *
282    * @return <code>true</code> if before the first row, <code>false</code>
283    * otherwise. Returns <code>false</code> when the result set
284    * contains no rows.
285    * @exception SQLException if a database-access error occurs.
286    */

287   public boolean isBeforeFirst() throws SQLException JavaDoc
288   {
289     checkIfClosed();
290     if (nbOfRows == 0)
291       return false;
292     else
293       return (currentRow == -1);
294   }
295
296   /**
297    * JDBC 2.0
298    * <p>
299    * Determine if the cursor is after the last row in the result set.
300    *
301    * @return <code>true</code> if after the last row, <code>false</code>
302    * otherwise. Returns <code>false</code> when the result set
303    * contains no rows.
304    * @exception SQLException if a database-access error occurs.
305    */

306   public boolean isAfterLast() throws SQLException JavaDoc
307   {
308     checkIfClosed();
309     if (nbOfRows == 0)
310       return false;
311     else
312       return (currentRow >= nbOfRows);
313   }
314
315   /**
316    * JDBC 2.0
317    * <p>
318    * Determine if the cursor is on the first row of the result set.
319    *
320    * @return <code>true</code> if on the first row, <code>false</code>
321    * otherwise.
322    * @exception SQLException if a database-access error occurs.
323    */

324   public boolean isFirst() throws SQLException JavaDoc
325   {
326     checkIfClosed();
327     if (nbOfRows == 0)
328       return false;
329     else
330       return (currentRow == 0);
331   }
332
333   /**
334    * JDBC 2.0
335    * <p>
336    * Determine if the cursor is on the last row of the result set. Note: Calling
337    * isLast() may be expensive since the JDBC driver might need to fetch ahead
338    * one row in order to determine whether the current row is the last row in
339    * the result set.
340    *
341    * @return <code>true</code> if on the last row, <code>false</code>
342    * otherwise.
343    * @exception SQLException if a database-access error occurs.
344    */

345   public boolean isLast() throws SQLException JavaDoc
346   {
347     checkIfClosed();
348     if (nbOfRows == 0)
349       return false;
350     else
351       return (currentRow == nbOfRows - 1);
352   }
353
354   /**
355    * JDBC 2.0
356    * <p>
357    * Moves to the front of the result set, just before the first row. Has no
358    * effect if the result set contains no rows.
359    *
360    * @exception SQLException if a database-access error occurs, or result set
361    * type is TYPE_FORWARD_ONLY
362    */

363   public void beforeFirst() throws SQLException JavaDoc
364   {
365     checkIfClosed();
366
367     if (inserting)
368     {
369       insertStatement.clearParameters();
370       tempRow = null;
371       inserting = false;
372     }
373
374     if (updating)
375       cancelRowUpdates();
376
377     currentRow = -1;
378   }
379
380   /**
381    * JDBC 2.0
382    * <p>
383    * Moves to the end of the result set, just after the last row. Has no effect
384    * if the result set contains no rows.
385    *
386    * @exception SQLException if a database-access error occurs, or result set
387    * type is TYPE_FORWARD_ONLY.
388    */

389   public void afterLast() throws SQLException JavaDoc
390   {
391     checkIfClosed();
392
393     if (inserting)
394     {
395       insertStatement.clearParameters();
396       tempRow = null;
397       inserting = false;
398     }
399
400     if (updating)
401       cancelRowUpdates();
402
403     if (nbOfRows != 0)
404       currentRow = nbOfRows;
405   }
406
407   /**
408    * JDBC 2.0
409    * <p>
410    * Moves to the first row in the result set.
411    *
412    * @return <code>true</code> if on a valid row, false if no rows in the
413    * result set.
414    * @exception SQLException if a database-access error occurs, or result set
415    * type is TYPE_FORWARD_ONLY.
416    */

417   public boolean first() throws SQLException JavaDoc
418   {
419     checkIfClosed();
420
421     if (inserting)
422     {
423       insertStatement.clearParameters();
424       tempRow = null;
425       inserting = false;
426     }
427
428     if (updating)
429       cancelRowUpdates();
430
431     if (nbOfRows == 0)
432       return false;
433
434     currentRow = 0;
435     return true;
436   }
437
438   /**
439    * JDBC 2.0
440    * <p>
441    * Moves to the last row in the result set.
442    *
443    * @return <code>true</code> if on a valid row, false if no rows in the
444    * result set.
445    * @exception SQLException if a database-access error occurs, or result set
446    * type is TYPE_FORWARD_ONLY.
447    */

448   public boolean last() throws SQLException JavaDoc
449   {
450     checkIfClosed();
451
452     if (inserting)
453     {
454       insertStatement.clearParameters();
455       tempRow = null;
456       inserting = false;
457     }
458
459     if (updating)
460       cancelRowUpdates();
461
462     if (nbOfRows == 0)
463       return false;
464
465     currentRow = nbOfRows - 1;
466     return true;
467   }
468
469   /**
470    * JDBC 2.0
471    * <p>
472    * Determine the current row number. The first row is number 1, the second
473    * number 2, etc.
474    *
475    * @return the current row number, else return 0 if there is no current row
476    * @exception SQLException if a database-access error occurs.
477    */

478   public int getRow() throws SQLException JavaDoc
479   {
480     checkIfClosed();
481     if (currentRow < 0 || currentRow >= nbOfRows || nbOfRows == 0)
482       return 0;
483     else
484       return currentRow + 1;
485   }
486
487   /**
488    * JDBC 2.0
489    * <p>
490    * Move to an absolute row number in the result set.
491    * <p>
492    * If row is positive, moves to an absolute row with respect to the beginning
493    * of the result set. The first row is row 1, the second is row 2, etc.
494    * <p>
495    * If row is negative, moves to an absolute row position with respect to the
496    * end of result set. For example, calling absolute(-1) positions the cursor
497    * on the last row, absolute(-2) indicates the next-to-last row, etc.
498    * <p>
499    * An attempt to position the cursor beyond the first/last row in the result
500    * set, leaves the cursor before/after the first/last row, respectively.
501    * <p>
502    * Note: Calling absolute(1) is the same as calling first(). Calling
503    * absolute(-1) is the same as calling last().
504    *
505    * @param row the row to move to
506    * @return <code>true</code> if on the result set, false if off.
507    * @exception SQLException if a database-access error occurs, or row is 0, or
508    * result set type is TYPE_FORWARD_ONLY.
509    */

510   public boolean absolute(int row) throws SQLException JavaDoc
511   {
512     checkIfClosed();
513
514     if (inserting)
515     {
516       insertStatement.clearParameters();
517       tempRow = null;
518       inserting = false;
519     }
520
521     if (updating)
522       cancelRowUpdates();
523
524     if (nbOfRows == 0)
525       return false;
526
527     if (row == 0)
528       throw new SQLException JavaDoc("Cannot absolute position to row 0");
529
530     if (row == 1)
531       return first();
532
533     if (row == -1)
534       return last();
535
536     if (row > nbOfRows)
537     {
538       afterLast();
539       return false;
540     }
541
542     if (row < 0)
543     { // adjust to reflect after end of result set
544
int newRowPosition = nbOfRows + row + 1;
545
546       if (newRowPosition <= 0)
547       {
548         beforeFirst();
549         return false;
550       }
551
552       return absolute(newRowPosition);
553     }
554     else
555     {
556       row--; // adjust for index difference
557
currentRow = row;
558       return true;
559     }
560   }
561
562   /**
563    * JDBC 2.0
564    * <p>
565    * Moves a relative number of rows, either positive or negative. Attempting to
566    * move beyond the first/last row in the result set positions the cursor
567    * before/after the the first/last row. Calling relative(0) is valid, but does
568    * not change the cursor position.
569    * <p>
570    * Note: Calling relative(1) is different than calling next() since is makes
571    * sense to call next() when there is no current row, for example, when the
572    * cursor is positioned before the first row or after the last row of the
573    * result set.
574    *
575    * @param rows the number of rows
576    * @return <code>true</code> if on a row, false otherwise.
577    * @exception SQLException if a database-access error occurs, or there is no
578    * current row, or result set type is TYPE_FORWARD_ONLY.
579    */

580   public boolean relative(int rows) throws SQLException JavaDoc
581   {
582     checkIfClosed();
583
584     if (inserting)
585     {
586       insertStatement.clearParameters();
587       tempRow = null;
588       inserting = false;
589     }
590
591     if (updating)
592       cancelRowUpdates();
593
594     if (nbOfRows == 0)
595       return false;
596
597     return absolute(currentRow + rows + 1);
598   }
599
600   /**
601    * JDBC 2.0
602    * <p>
603    * Moves to the previous row in the result set.
604    * <p>
605    * Note: previous() is not the same as relative(-1) since it makes sense to
606    * call previous() when there is no current row.
607    *
608    * @return <code>true</code> if on a valid row, false if off the result set.
609    * @exception SQLException if a database-access error occurs, or result set
610    * type is TYPE_FORWAR_DONLY.
611    */

612   public boolean previous() throws SQLException JavaDoc
613   {
614     return prev();
615   }
616
617   /**
618    * JDBC 2.0 Give a hint as to the direction in which the rows in this result
619    * set will be processed. The initial value is determined by the statement
620    * that produced the result set. The fetch direction may be changed at any
621    * time.
622    *
623    * @param direction the fetch direction
624    * @exception SQLException if a database-access error occurs, or the result
625    * set type is TYPE_FORWARD_ONLY and direction is not
626    * FETCH_FORWARD. MM.MySQL actually ignores this, because it has
627    * the whole result set anyway, so the direction is immaterial.
628    */

629   public void setFetchDirection(int direction) throws SQLException JavaDoc
630   {
631     if (direction != FETCH_FORWARD && direction != FETCH_REVERSE)
632       throw new SQLException JavaDoc("Illegal value for fetch direction");
633     else
634       fetchDirection = direction;
635   }
636
637   /**
638    * JDBC 2.0 Return the fetch direction for this result set.
639    *
640    * @return the fetch direction
641    * @exception SQLException if a database-access error occurs
642    */

643   public int getFetchDirection() throws SQLException JavaDoc
644   {
645     return fetchDirection;
646   }
647
648   /**
649    * JDBC 2.0 Give the JDBC driver a hint as to the number of rows that should
650    * be fetched from the database when more rows are needed for this result set.
651    * If the fetch size specified is zero, then the JDBC driver ignores the
652    * value, and is free to make its own best guess as to what the fetch size
653    * should be. The default value is set by the statement that creates the
654    * result set. The fetch size may be changed at any time.
655    *
656    * @param rows the number of rows to fetch
657    * @exception SQLException if a database-access error occurs, or the condition
658    * 0 <= rows <= statement.getMaxRows() is not satisfied.
659    * Currently ignored by this driver.
660    */

661   public void setFetchSize(int rows) throws SQLException JavaDoc
662   {
663     // This is just a hint afterall, let's not try to throw exceptions for
664
// nothing
665
if (rows < 0)
666       throw new SQLException JavaDoc("Value must be between 0 and getMaxRows()");
667
668     fetchSize = rows;
669   }
670
671   /**
672    * JDBC 2.0 Return the fetch size for this result set.
673    *
674    * @return the fetch size
675    * @exception SQLException if a database-access error occurs
676    */

677   public int getFetchSize() throws SQLException JavaDoc
678   {
679     return fetchSize;
680   }
681
682   //
683
// ---------------------------------------------------------------------
684
// Getter's and Setter's
685
// ---------------------------------------------------------------------
686
//
687

688   /**
689    * Get the value of a column in the current row as a Java String
690    *
691    * @param columnIndex the first column is 1, the second is 2...
692    * @return the column value, null for SQL NULL
693    * @exception SQLException if a database access error occurs
694    */

695   public String JavaDoc getString(int columnIndex) throws SQLException JavaDoc
696   {
697     checkRowAndColPosAndSetNullFlag(columnIndex);
698
699     if (wasNullFlag)
700       return null;
701
702     if (inserting || updating)
703       return tempRow[columnIndex - 1].toString();
704     else
705       return (((Object JavaDoc[]) data.get(currentRow))[columnIndex - 1]).toString();
706   }
707
708   /**
709    * Get the value of a column in the current row as a Java boolean
710    *
711    * @param columnIndex the first column is 1, the second is 2...
712    * @return the column value, false for SQL NULL
713    * @exception SQLException if a database access error occurs
714    */

715   public boolean getBoolean(int columnIndex) throws SQLException JavaDoc
716   {
717     checkRowAndColPosAndSetNullFlag(columnIndex);
718
719     if (wasNullFlag)
720       return false;
721
722     Object JavaDoc object;
723     if (inserting || updating)
724       object = tempRow[columnIndex - 1];
725     else
726       object = (((Object JavaDoc[]) data.get(currentRow))[columnIndex - 1]);
727
728     String JavaDoc stringVal = object.toString();
729     if ((stringVal != null) && (stringVal.length() > 0))
730     {
731       stringVal = stringVal.toLowerCase();
732
733       // first we check the connection values to be consistent
734
if (this.connection.getPreparedStatementBooleanTrue().equals(
735           stringVal))
736       {
737         return true;
738       }
739       else if (this.connection.getPreparedStatementBooleanFalse()
740           .equals(stringVal))
741       {
742         return false;
743       }
744
745       // now we check some other possible string representations of boolean
746
else if ("t".equals(stringVal))
747       {
748         return true;
749       }
750       else if ("f".equals(stringVal))
751       {
752         return false;
753       }
754       else if ("true".equals(stringVal))
755       {
756         return true;
757       }
758       else if ("false".equals(stringVal))
759       {
760         return false;
761       }
762       else if ("1".equals(stringVal))
763       {
764         return true;
765       }
766       else if ("0".equals(stringVal))
767       {
768         return false;
769       }
770       else if ("y".equals(stringVal))
771       {
772         return true;
773       }
774       else if ("n".equals(stringVal))
775       {
776         return false;
777       }
778       else if ("yes".equals(stringVal))
779       {
780         return true;
781       }
782       else if ("no".equals(stringVal))
783       {
784         return false;
785       }
786       else if (object instanceof Number JavaDoc)
787       {
788         int value = ((Number JavaDoc) object).intValue();
789         if (value == 0)
790           return false;
791         else if (value == 1)
792           return true;
793         // else other value throw an exception
794
}
795
796       // we didn't find anything reasonable and throw an exception
797
throw new SQLException JavaDoc("column value " + stringVal
798           + " could not be converted to boolean");
799     }
800     else
801     {
802       return false;
803     }
804   }
805
806   /**
807    * Get the value of a column in the current row as a Java short.
808    *
809    * @param columnIndex the first column is 1, the second is 2,...
810    * @return the column value; 0 if SQL NULL
811    * @exception SQLException if a database access error occurs
812    */

813   public short getShort(int columnIndex) throws SQLException JavaDoc
814   {
815     checkRowAndColPosAndSetNullFlag(columnIndex);
816
817     if (wasNullFlag)
818       return 0;
819
820     Object JavaDoc obj;
821     if (inserting || updating)
822       obj = tempRow[columnIndex - 1];
823     else
824       obj = ((Object JavaDoc[]) data.get(currentRow))[columnIndex - 1];
825
826     if (obj instanceof Number JavaDoc)
827     {
828       return ((Number JavaDoc) obj).shortValue();
829     }
830
831     // the object is not of type number we parse the string representation
832
try
833     {
834       String JavaDoc string = obj.toString();
835       string = string.trim();
836       return Short.parseShort(string);
837     }
838     catch (NumberFormatException JavaDoc e)
839     {
840       throw new SQLException JavaDoc("the value " + obj.toString()
841           + " is not a valid short number");
842     }
843   }
844
845   /**
846    * Get the value of a column in the current row as a Java int.
847    *
848    * @param columnIndex the first column is 1, the second is 2,...
849    * @return the column value; 0 if SQL NULL
850    * @exception SQLException if a database access error occurs
851    */

852   public int getInt(int columnIndex) throws SQLException JavaDoc
853   {
854     checkRowAndColPosAndSetNullFlag(columnIndex);
855
856     if (wasNullFlag)
857       return 0;
858
859     Object JavaDoc obj;
860     if (inserting || updating)
861       obj = tempRow[columnIndex - 1];
862     else
863       obj = ((Object JavaDoc[]) data.get(currentRow))[columnIndex - 1];
864
865     if (obj instanceof Number JavaDoc)
866     {
867       return ((Number JavaDoc) obj).intValue();
868     }
869
870     // the object is not of type number we parse the string representation
871
try
872     {
873       String JavaDoc string = obj.toString();
874       string = string.trim();
875       return Integer.parseInt(string);
876     }
877     catch (NumberFormatException JavaDoc e)
878     {
879       throw new SQLException JavaDoc("the value " + obj.toString()
880           + " is not a valid int number");
881     }
882   }
883
884   /**
885    * Get the value of a column in the current row as a Java long.
886    *
887    * @param columnIndex the first column is 1, the second is 2,...
888    * @return the column value; 0 if SQL NULL
889    * @exception SQLException if a database access error occurs
890    */

891   public long getLong(int columnIndex) throws SQLException JavaDoc
892   {
893     checkRowAndColPosAndSetNullFlag(columnIndex);
894
895     if (wasNullFlag)
896       return 0;
897
898     Object JavaDoc obj;
899     if (inserting || updating)
900       obj = tempRow[columnIndex - 1];
901     else
902       obj = ((Object JavaDoc[]) data.get(currentRow))[columnIndex - 1];
903
904     if (obj instanceof Number JavaDoc)
905     {
906       return ((Number JavaDoc) obj).longValue();
907     }
908
909     // the object is not of type number we parse the string representation
910
try
911     {
912       String JavaDoc string = obj.toString();
913       string = string.trim();
914       return Long.parseLong(string);
915     }
916     catch (NumberFormatException JavaDoc e)
917     {
918       throw new SQLException JavaDoc("the value " + obj.toString()
919           + " is not a valid long number");
920     }
921   }
922
923   /**
924    * Get the value of a column in the current row as a Java float.
925    *
926    * @param columnIndex the first column is 1, the second is 2,...
927    * @return the column value; 0 if SQL NULL
928    * @exception SQLException if a database access error occurs
929    */

930   public float getFloat(int columnIndex) throws SQLException JavaDoc
931   {
932     checkRowAndColPosAndSetNullFlag(columnIndex);
933
934     if (wasNullFlag)
935       return 0;
936
937     Object JavaDoc obj;
938     if (inserting || updating)
939       obj = tempRow[columnIndex - 1];
940     else
941       obj = ((Object JavaDoc[]) data.get(currentRow))[columnIndex - 1];
942
943     if (obj instanceof Number JavaDoc)
944     {
945       return ((Number JavaDoc) obj).floatValue();
946     }
947
948     // the object is not of type number we parse the string representation
949
try
950     {
951       String JavaDoc string = obj.toString();
952       string = string.trim();
953       return Float.parseFloat(string);
954     }
955     catch (NumberFormatException JavaDoc e)
956     {
957       throw new SQLException JavaDoc("the value " + obj.toString()
958           + " is not a valid float number");
959     }
960   }
961
962   /**
963    * Get the value of a column in the current row as a Java double.
964    *
965    * @param columnIndex the first column is 1, the second is 2,...
966    * @return the column value; 0 if SQL NULL
967    * @exception SQLException if a database access error occurs
968    */

969   public double getDouble(int columnIndex) throws SQLException JavaDoc
970   {
971     checkRowAndColPosAndSetNullFlag(columnIndex);
972
973     if (wasNullFlag)
974       return 0;
975
976     Object JavaDoc obj;
977     if (inserting || updating)
978       obj = tempRow[columnIndex - 1];
979     else
980       obj = ((Object JavaDoc[]) data.get(currentRow))[columnIndex - 1];
981
982     if (obj instanceof Number JavaDoc)
983     {
984       return ((Number JavaDoc) obj).doubleValue();
985     }
986
987     // the object is not of type number we parse the string representation
988
try
989     {
990       String JavaDoc string = obj.toString();
991       string = string.trim();
992       return Double.parseDouble(string);
993     }
994     catch (NumberFormatException JavaDoc e)
995     {
996       throw new SQLException JavaDoc("the value " + obj.toString()
997           + " is not a valid double number");
998     }
999   }
1000
1001  /**
1002   * Get the value of a column in the current row as a java.lang.BigDecimal
1003   * object
1004   *
1005   * @param columnIndex the first column is 1, the second is 2...
1006   * @param scale the number of digits to the right of the decimal
1007   * @return the column value; if the value is SQL NULL, null
1008   * @exception SQLException if a database access error occurs
1009   * @deprecated
1010   */

1011  public BigDecimal JavaDoc getBigDecimal(int columnIndex, int scale)
1012      throws SQLException JavaDoc
1013  {
1014    BigDecimal JavaDoc bigDecimal = getBigDecimal(columnIndex);
1015    if (bigDecimal == null)
1016      return null;
1017    else
1018      return bigDecimal.setScale(scale);
1019  }
1020
1021  /**
1022   * Get the value of a column in the current row as a Java byte array.
1023   * <p>
1024   * <b>Be warned </b> If the blob is huge, then you may run out of memory.
1025   *
1026   * @param columnIndex the first column is 1, the second is 2, ...
1027   * @return the column value; if the value is SQL NULL, the result is null
1028   * @exception SQLException if a database access error occurs
1029   */

1030  public byte[] getBytes(int columnIndex) throws SQLException JavaDoc
1031  {
1032    checkRowAndColPosAndSetNullFlag(columnIndex);
1033
1034    if (wasNullFlag)
1035      return null;
1036
1037    Object JavaDoc o;
1038    if (inserting || updating)
1039      o = tempRow[columnIndex - 1];
1040    else
1041      o = ((Object JavaDoc[]) data.get(currentRow))[columnIndex - 1];
1042
1043    byte[] tmp;
1044    if (o instanceof java.lang.String JavaDoc)
1045    {
1046      tmp = ((String JavaDoc) o).getBytes();
1047    }
1048    else
1049    {
1050      tmp = (byte[]) o;
1051    }
1052
1053    if (this.connection.isDriverProcessed())
1054      return this.connection.getBlobFilter().decode(tmp);
1055    else
1056      return tmp;
1057  }
1058
1059  /**
1060   * Get the value of a column in the current row as a java.sql.Date object
1061   *
1062   * @param columnIndex the first column is 1, the second is 2...
1063   * @return the column value; null if SQL NULL
1064   * @exception SQLException if a database access error occurs
1065   */

1066  public java.sql.Date JavaDoc getDate(int columnIndex) throws SQLException JavaDoc
1067  {
1068    checkRowAndColPosAndSetNullFlag(columnIndex);
1069
1070    if (wasNullFlag)
1071      return null;
1072
1073    // we may be reading a timestamp column and have to convert it to date
1074
// the client is asking for the date field only, we have to make sure
1075
// hour,minutes,... are cleared
1076
String JavaDoc dateString;
1077    if (inserting || updating)
1078      dateString = tempRow[columnIndex - 1].toString();
1079    else
1080      dateString = ((Object JavaDoc[]) data.get(currentRow))[columnIndex - 1]
1081          .toString();
1082
1083    if (dateString.length() == 10)
1084      return java.sql.Date.valueOf(dateString);
1085    else
1086      return java.sql.Date.valueOf(dateString.substring(0, 10));
1087  }
1088
1089  /**
1090   * Get the value of a column in the current row as a java.sql.Time object
1091   *
1092   * @param columnIndex the first column is 1, the second is 2...
1093   * @return the column value; null if SQL NULL
1094   * @exception SQLException if a database access error occurs
1095   */

1096  public Time JavaDoc getTime(int columnIndex) throws SQLException JavaDoc
1097  {
1098    checkRowAndColPosAndSetNullFlag(columnIndex);
1099
1100    if (wasNullFlag)
1101      return null;
1102
1103    Object JavaDoc obj;
1104    if (inserting || updating)
1105      obj = tempRow[columnIndex - 1];
1106    else
1107      obj = ((Object JavaDoc[]) data.get(currentRow))[columnIndex - 1];
1108
1109    if (obj instanceof java.util.Date JavaDoc)
1110    {
1111      java.util.Date JavaDoc time = (java.util.Date JavaDoc) obj;
1112      // the driver returns the format of the column, but we are asking for
1113
// the time values only.
1114
String JavaDoc timeString = time.toString();
1115      if (timeString.length() == 8)
1116      {
1117        // ok we have got a timefield of the format HH:mm:ss, exactly the way
1118
// we need it, no further processing is required
1119
return new Time JavaDoc(time.getTime());
1120      }
1121
1122      // we have got the date fields too and have to clear the year, month and
1123
// date field
1124
Calendar JavaDoc cal = Calendar.getInstance();
1125      cal.setTime(time);
1126      cal.clear(Calendar.YEAR);
1127      cal.clear(Calendar.MONTH);
1128      cal.clear(Calendar.DATE);
1129      cal.clear(Calendar.MILLISECOND);
1130      return new Time JavaDoc(cal.getTimeInMillis());
1131    }
1132
1133    // the object is not of type date we parse the string representation
1134
try
1135    {
1136      String JavaDoc string = obj.toString();
1137      string = string.trim();
1138      return Time.valueOf(string);
1139    }
1140    catch (IllegalArgumentException JavaDoc e)
1141    {
1142      throw new SQLException JavaDoc("the value " + obj.toString()
1143          + " is not a valid time");
1144    }
1145  }
1146
1147  /**
1148   * Get the value of a column in the current row as a java.sql.Timestamp object
1149   *
1150   * @param columnIndex the first column is 1, the second is 2...
1151   * @return the column value; null if SQL NULL
1152   * @exception SQLException if a database access error occurs
1153   */

1154  public Timestamp JavaDoc getTimestamp(int columnIndex) throws SQLException JavaDoc
1155  {
1156    checkRowAndColPosAndSetNullFlag(columnIndex);
1157
1158    if (wasNullFlag)
1159      return null;
1160
1161    Object JavaDoc obj;
1162    if (inserting || updating)
1163      obj = tempRow[columnIndex - 1];
1164    else
1165      obj = ((Object JavaDoc[]) data.get(currentRow))[columnIndex - 1];
1166
1167    if (obj instanceof java.util.Date JavaDoc)
1168    {
1169      return new Timestamp JavaDoc(((java.util.Date JavaDoc) obj).getTime());
1170    }
1171
1172    // the object is not of type timestamp we parse the string representation
1173
try
1174    {
1175      String JavaDoc string = obj.toString();
1176      string = string.trim();
1177      return Timestamp.valueOf(string);
1178    }
1179    catch (IllegalArgumentException JavaDoc e)
1180    {
1181      throw new SQLException JavaDoc("the value " + obj.toString()
1182          + " is not a valid timestamp");
1183    }
1184  }
1185
1186  /**
1187   * A column value can be retrieved as a stream of ASCII characters and then
1188   * read in chunks from the stream. This method is particulary suitable for
1189   * retrieving large LONGVARCHAR values. The JDBC driver will do any necessary
1190   * conversion from the database format into ASCII.
1191   * <p>
1192   * <B>Note: </B> All the data in the returned stream must be read prior to
1193   * getting the value of any other column. The next call to a get method
1194   * implicitly closes the stream. Also, a stream may return 0 for available()
1195   * whether there is data available or not.
1196   *
1197   * @param columnIndex the first column is 1, the second is 2, ...
1198   * @return a Java InputStream that delivers the database column value as a
1199   * stream of one byte ASCII characters. If the value is SQL NULL then
1200   * the result is null
1201   * @exception SQLException if a database access error occurs
1202   * @see #getBinaryStream(int)
1203   */

1204  public InputStream JavaDoc getAsciiStream(int columnIndex) throws SQLException JavaDoc
1205  {
1206    checkRowAndColPosAndSetNullFlag(columnIndex);
1207
1208    return getBinaryStream(columnIndex);
1209  }
1210
1211  /**
1212   * A column value can also be retrieved as a stream of Unicode characters. We
1213   * implement this as a binary stream.
1214   *
1215   * @param columnIndex the first column is 1, the second is 2...
1216   * @return a Java InputStream that delivers the database column value as a
1217   * stream of two byte Unicode characters. If the value is SQL NULL,
1218   * then the result is null
1219   * @exception SQLException if a database access error occurs
1220   * @deprecated
1221   * @see #getAsciiStream
1222   * @see #getBinaryStream(int)
1223   */

1224  public InputStream JavaDoc getUnicodeStream(int columnIndex) throws SQLException JavaDoc
1225  {
1226    checkRowAndColPosAndSetNullFlag(columnIndex);
1227
1228    return getBinaryStream(columnIndex);
1229  }
1230
1231  /**
1232   * A column value can also be retrieved as a binary strea. This method is
1233   * suitable for retrieving LONGVARBINARY values.
1234   *
1235   * @param columnIndex the first column is 1, the second is 2...
1236   * @return a Java InputStream that delivers the database column value as a
1237   * stream of bytes. If the value is SQL NULL, then the result is null
1238   * @exception SQLException if a database access error occurs
1239   * @see #getAsciiStream(int)
1240   * @see #getUnicodeStream(int)
1241   */

1242
1243  public InputStream JavaDoc getBinaryStream(int columnIndex) throws SQLException JavaDoc
1244  {
1245    checkRowAndColPosAndSetNullFlag(columnIndex);
1246
1247    byte[] b = getBytes(columnIndex);
1248    if (b != null)
1249      return new ByteArrayInputStream JavaDoc(b);
1250    else
1251      return null; // SQL NULL
1252
}
1253
1254  /**
1255   * The following routines simply convert the columnName into a columnIndex and
1256   * then call the appropriate routine above.
1257   *
1258   * @param columnName is the SQL name of the column
1259   * @return the column value
1260   * @exception SQLException if a database access error occurs
1261   */

1262  public String JavaDoc getString(String JavaDoc columnName) throws SQLException JavaDoc
1263  {
1264    return this.getString(findColumn(columnName));
1265  }
1266
1267  /**
1268   * @see java.sql.ResultSet#getBoolean(java.lang.String)
1269   */

1270  public boolean getBoolean(String JavaDoc columnName) throws SQLException JavaDoc
1271  {
1272    return getBoolean(findColumn(columnName));
1273  }
1274
1275  /**
1276   * @see java.sql.ResultSet#getByte(java.lang.String)
1277   */

1278  public byte getByte(String JavaDoc columnName) throws SQLException JavaDoc
1279  {
1280    return getByte(findColumn(columnName));
1281  }
1282
1283  /**
1284   * @see java.sql.ResultSet#getShort(java.lang.String)
1285   */

1286  public short getShort(String JavaDoc columnName) throws SQLException JavaDoc
1287  {
1288    return getShort(findColumn(columnName));
1289  }
1290
1291  /**
1292   * @see java.sql.ResultSet#getInt(java.lang.String)
1293   */

1294  public int getInt(String JavaDoc columnName) throws SQLException JavaDoc
1295  {
1296    return getInt(findColumn(columnName));
1297  }
1298
1299  /**
1300   * @see java.sql.ResultSet#getLong(java.lang.String)
1301   */

1302  public long getLong(String JavaDoc columnName) throws SQLException JavaDoc
1303  {
1304    return getLong(findColumn(columnName));
1305  }
1306
1307  /**
1308   * @see java.sql.ResultSet#getFloat(java.lang.String)
1309   */

1310  public float getFloat(String JavaDoc columnName) throws SQLException JavaDoc
1311  {
1312    return getFloat(findColumn(columnName));
1313  }
1314
1315  /**
1316   * @see java.sql.ResultSet#getDouble(java.lang.String)
1317   */

1318  public double getDouble(String JavaDoc columnName) throws SQLException JavaDoc
1319  {
1320    return getDouble(findColumn(columnName));
1321  }
1322
1323  /**
1324   * @see java.sql.ResultSet#getBigDecimal(String, int)
1325   * @deprecated
1326   */

1327  public BigDecimal JavaDoc getBigDecimal(String JavaDoc columnName, int scale)
1328      throws SQLException JavaDoc
1329  {
1330    return getBigDecimal(findColumn(columnName), scale);
1331  }
1332
1333  /**
1334   * @see java.sql.ResultSet#getBytes(java.lang.String)
1335   */

1336  public byte[] getBytes(String JavaDoc columnName) throws SQLException JavaDoc
1337  {
1338    return getBytes(findColumn(columnName));
1339  }
1340
1341  /**
1342   * @see java.sql.ResultSet#getDate(java.lang.String)
1343   */

1344  public java.sql.Date JavaDoc getDate(String JavaDoc columnName) throws SQLException JavaDoc
1345  {
1346    return getDate(findColumn(columnName));
1347  }
1348
1349  /**
1350   * @see java.sql.ResultSet#getTime(java.lang.String)
1351   */

1352  public Time JavaDoc getTime(String JavaDoc columnName) throws SQLException JavaDoc
1353  {
1354    return getTime(findColumn(columnName));
1355  }
1356
1357  /**
1358   * @see java.sql.ResultSet#getTimestamp(java.lang.String)
1359   */

1360  public Timestamp JavaDoc getTimestamp(String JavaDoc columnName) throws SQLException JavaDoc
1361  {
1362    return getTimestamp(findColumn(columnName));
1363  }
1364
1365  /**
1366   * @see java.sql.ResultSet#getAsciiStream(java.lang.String)
1367   */

1368  public InputStream JavaDoc getAsciiStream(String JavaDoc columnName) throws SQLException JavaDoc
1369  {
1370    return getAsciiStream(findColumn(columnName));
1371  }
1372
1373  /**
1374   * @see java.sql.ResultSet#getUnicodeStream(String)
1375   * @deprecated
1376   */

1377  public InputStream JavaDoc getUnicodeStream(String JavaDoc columnName) throws SQLException JavaDoc
1378  {
1379    return getUnicodeStream(findColumn(columnName));
1380  }
1381
1382  /**
1383   * @see java.sql.ResultSet#getBinaryStream(java.lang.String)
1384   */

1385  public InputStream JavaDoc getBinaryStream(String JavaDoc columnName) throws SQLException JavaDoc
1386  {
1387    return getBinaryStream(findColumn(columnName));
1388  }
1389
1390  /**
1391   * The first warning reported by calls on this ResultSet is returned.
1392   * Subsequent ResultSet warnings will be chained to this java.sql.SQLWarning.
1393   * <p>
1394   * The warning chain is automatically cleared each time a new row is read.
1395   * <p>
1396   * <B>Note: </B> This warning chain only covers warnings caused by ResultSet
1397   * methods. Any warnings caused by statement methods (such as reading OUT
1398   * parameters) will be chained on the Statement object.
1399   *
1400   * @return the first java.sql.SQLWarning or null;
1401   * @exception SQLException if a database access error occurs.
1402   */

1403  public java.sql.SQLWarning JavaDoc getWarnings() throws SQLException JavaDoc
1404  {
1405    return warnings;
1406  }
1407
1408  /**
1409   * After this call, getWarnings returns null until a new warning is reported
1410   * for this ResultSet
1411   *
1412   * @exception SQLException if a database access error occurs
1413   */

1414
1415  public void clearWarnings() throws SQLException JavaDoc
1416  {
1417    warnings = null;
1418  }
1419
1420  /**
1421   * @see java.sql.ResultSet#getCursorName()
1422   */

1423  public String JavaDoc getCursorName() throws SQLException JavaDoc
1424  {
1425    return cursorName;
1426  }
1427
1428  /**
1429   * Get the value of a column in the current row as a Java object
1430   * <p>
1431   * This method will return the value of the given column as a Java object. The
1432   * type of the Java object will be the default Java Object type corresponding
1433   * to the column's SQL type, following the mapping specified in the JDBC
1434   * specification.
1435   * <p>
1436   * This method may also be used to read database specific abstract data types.
1437   *
1438   * @param columnIndex the first column is 1, the second is 2...
1439   * @return a Object holding the column value
1440   * @exception SQLException if a database access error occurs
1441   */

1442  public Object JavaDoc getObject(int columnIndex) throws SQLException JavaDoc
1443  {
1444    checkRowAndColPosAndSetNullFlag(columnIndex);
1445
1446    if (wasNullFlag)
1447      return null;
1448
1449    Object JavaDoc o;
1450    if (inserting || updating)
1451      o = tempRow[columnIndex];
1452    else
1453      o = ((Object JavaDoc[]) data.get(currentRow))[columnIndex - 1];
1454
1455    if (owningStatement != null)
1456    {
1457      /**
1458       * We make the bet that a byte array is a blob we have encoded
1459       * {@link Blob}, and not some XXXBINARY returned by the backend driver.
1460       * TODO: could we use some magic number ? Look at the SQL type ?
1461       */

1462      if (this.connection.isDriverProcessed() && o instanceof byte[])
1463      {
1464        try
1465        {
1466          byte[] b = this.connection.getBlobFilter().decode((byte[]) o);
1467          return new ObjectInputStream JavaDoc(new ByteArrayInputStream JavaDoc(b))
1468              .readObject();
1469        }
1470        catch (ClassNotFoundException JavaDoc e)
1471        {
1472          e.printStackTrace();
1473          throw new SQLException JavaDoc("Missing class while deserializing Blob" + e);
1474        }
1475        catch (IOException JavaDoc e)
1476        {
1477          e.printStackTrace();
1478          throw new SQLException JavaDoc("IOException while deserializing Blob" + e);
1479        }
1480      }
1481    }
1482    return o;
1483  }
1484
1485  /**
1486   * Get the value of a column in the current row as a Java object
1487   * <p>
1488   * This method will return the value of the given column as a Java object. The
1489   * type of the Java object will be the default Java Object type corresponding
1490   * to the column's SQL type, following the mapping specified in the JDBC
1491   * specification.
1492   * <p>
1493   * This method may also be used to read database specific abstract data types.
1494   *
1495   * @param columnName is the SQL name of the column
1496   * @return a Object holding the column value
1497   * @exception SQLException if a database access error occurs
1498   */

1499  public Object JavaDoc getObject(String JavaDoc columnName) throws SQLException JavaDoc
1500  {
1501    return getObject(findColumn(columnName));
1502  }
1503
1504  // --------------------------JDBC 2.0-----------------------------------
1505

1506  /**
1507   * @see java.sql.ResultSet#getCharacterStream(int)
1508   */

1509  public java.io.Reader JavaDoc getCharacterStream(int columnIndex) throws SQLException JavaDoc
1510  {
1511    String JavaDoc s = getString(columnIndex);
1512    if (s == null)
1513      return null;
1514    char[] content = s.toCharArray();
1515    return new java.io.CharArrayReader JavaDoc(content);
1516  }
1517
1518  /**
1519   * @see java.sql.ResultSet#getCharacterStream(java.lang.String)
1520   */

1521  public java.io.Reader JavaDoc getCharacterStream(String JavaDoc columnName)
1522      throws SQLException JavaDoc
1523  {
1524    return getCharacterStream(findColumn(columnName));
1525  }
1526
1527  /**
1528   * JDBC 2.0 Get the value of a column in the current row as a
1529   * java.math.BigDecimal object.
1530   *
1531   * @param columnIndex the first column is 1, the second is 2, ...
1532   * @return the column value (full precision); if the value is SQL NULL, the
1533   * result is null
1534   * @exception SQLException if a database-access error occurs.
1535   */

1536  public BigDecimal JavaDoc getBigDecimal(int columnIndex) throws SQLException JavaDoc
1537  {
1538    checkRowAndColPosAndSetNullFlag(columnIndex);
1539
1540    if (wasNullFlag)
1541      return null;
1542
1543    Object JavaDoc obj;
1544    if (inserting || updating)
1545      obj = tempRow[columnIndex - 1];
1546    else
1547      obj = ((Object JavaDoc[]) data.get(currentRow))[columnIndex - 1];
1548
1549    if (obj instanceof BigDecimal JavaDoc)
1550      return (BigDecimal JavaDoc) obj;
1551    else if (obj instanceof Long JavaDoc)
1552    {
1553      return new BigDecimal JavaDoc(((Long JavaDoc) obj).longValue());
1554    }
1555    else if (obj instanceof BigInteger JavaDoc)
1556    {
1557      return new BigDecimal JavaDoc(((BigInteger JavaDoc) obj));
1558    }
1559    else if (obj instanceof Short JavaDoc)
1560    {
1561      return new BigDecimal JavaDoc(((Short JavaDoc) obj).shortValue());
1562    }
1563    else if (obj instanceof Integer JavaDoc)
1564    {
1565      return new BigDecimal JavaDoc(((Integer JavaDoc) obj).intValue());
1566    }
1567    else if (obj instanceof String JavaDoc)
1568    {
1569      return new BigDecimal JavaDoc((String JavaDoc) obj);
1570    }
1571    else if (obj instanceof Number JavaDoc)
1572    {
1573      // float and double have to be converted via string
1574
// othwerwise we produce errors
1575
// javadoc for BigDecimal :
1576
// Note: the results of this constructor can be somewhat unpredictable.
1577
// One might assume that new BigDecimal(.1) is exactly equal to .1, but
1578
// it is actually equal to
1579
// .1000000000000000055511151231257827021181583404541015625. This is so
1580
// because .1 cannot be represented exactly as a double (or, for that
1581
// matter, as a binary fraction of any finite length). Thus, the long
1582
// value that is being passed in to the constructor is not exactly equal
1583
// to .1, appearances nonwithstanding.
1584

1585      // The (String) constructor, on the other hand, is perfectly
1586
// predictable: new BigDecimal(".1") is exactly equal to .1, as one
1587
// would expect. Therefore, it is generally recommended that the
1588
// (String) constructor be used in preference to this one.
1589
return new BigDecimal JavaDoc(obj.toString());
1590    }
1591    else
1592    {
1593      throw new SQLException JavaDoc("Type " + obj.getClass().getName()
1594          + " is not compatible with BigDecimal");
1595    }
1596  }
1597
1598  /**
1599   * @see java.sql.ResultSet#getBigDecimal(java.lang.String)
1600   */

1601  public BigDecimal JavaDoc getBigDecimal(String JavaDoc columnName) throws SQLException JavaDoc
1602  {
1603    return getBigDecimal(findColumn(columnName));
1604  }
1605
1606  /**
1607   * JDBC 2.0 Returns the value of column as a Java object. Use the map to
1608   * determine the class from which to construct data of SQL structured and
1609   * distinct types.
1610   *
1611   * @param i the first column is 1, the second is 2, ...
1612   * @param map the mapping from SQL type names to Java classes
1613   * @return an object representing the SQL value
1614   * @exception SQLException if a database-access error occurs.
1615   */

1616  public Object JavaDoc getObject(int i, java.util.Map JavaDoc map) throws SQLException JavaDoc
1617  {
1618    throw new NotImplementedException("getObject(int, java.util.Map)");
1619  }
1620
1621  /**
1622   * JDBC 2.0 Get a REF(&lt;structured-type&gt;) column.
1623   *
1624   * @param i the first column is 1, the second is 2, ...
1625   * @return an object representing data of an SQL REF type
1626   * @exception SQLException if a database-access error occurs.
1627   */

1628  public java.sql.Ref JavaDoc getRef(int i) throws SQLException JavaDoc
1629  {
1630    checkRowAndColPosAndSetNullFlag(i);
1631
1632    if (wasNullFlag)
1633      return null;
1634
1635    if (inserting || updating)
1636      return (Ref JavaDoc) tempRow[i - 1];
1637    else
1638      return (Ref JavaDoc) (((Object JavaDoc[]) data.get(currentRow))[i - 1]);
1639  }
1640
1641  /**
1642   * JDBC 2.0 Gets a BLOB column.
1643   *
1644   * @param columnIndex the first column is 1, the second is 2, ...
1645   * @return an object representing a BLOB
1646   * @exception SQLException if a database-access error occurs.
1647   */

1648  public java.sql.Blob JavaDoc getBlob(int columnIndex) throws SQLException JavaDoc
1649  {
1650    checkRowAndColPosAndSetNullFlag(columnIndex);
1651
1652    if (wasNullFlag)
1653      return null;
1654
1655    Object JavaDoc o;
1656    if (inserting || updating)
1657      o = tempRow[columnIndex - 1];
1658    else
1659      o = (((Object JavaDoc[]) data.get(currentRow))[columnIndex - 1]);
1660
1661    // Test if the type of the Blob is indeed a Blob else we assume these are
1662
// just bytes.
1663
if (o instanceof Blob)
1664      return (java.sql.Blob JavaDoc) o;
1665    else
1666      return new Blob(getBytes(columnIndex));
1667  }
1668
1669  /**
1670   * JDBC 2.0 Gets a CLOB column.
1671   *
1672   * @param columnIndex the first column is 1, the second is 2, ...
1673   * @return an object representing a CLOB
1674   * @exception SQLException if a database-access error occurs.
1675   */

1676  public java.sql.Clob JavaDoc getClob(int columnIndex) throws SQLException JavaDoc
1677  {
1678    checkRowAndColPosAndSetNullFlag(columnIndex);
1679
1680    if (wasNullFlag)
1681      return null;
1682
1683    Object JavaDoc o;
1684    if (inserting || updating)
1685      o = tempRow[columnIndex - 1];
1686    else
1687      o = (((Object JavaDoc[]) data.get(currentRow))[columnIndex - 1]);
1688
1689    // Test if the type of the Clob is indeed a Clob or just a String
1690
// throw new SQLException("Class:"+o.getClass());
1691
if (o instanceof String JavaDoc)
1692      return new Clob((String JavaDoc) o);
1693    else if (o instanceof Clob)
1694      return (java.sql.Clob JavaDoc) o;
1695    else
1696      return new Clob(new String JavaDoc(o.toString()));
1697  }
1698
1699  /**
1700   * JDBC 2.0 Gets an array column.
1701   *
1702   * @param columnIndex the first column is 1, the second is 2, ...
1703   * @return an object representing an SQL array
1704   * @exception SQLException if a database-access error occurs.
1705   */

1706  public java.sql.Array JavaDoc getArray(int columnIndex) throws SQLException JavaDoc
1707  {
1708    checkRowAndColPosAndSetNullFlag(columnIndex);
1709
1710    if (wasNullFlag)
1711      return null;
1712
1713    if (inserting || updating)
1714      return (java.sql.Array JavaDoc) tempRow[columnIndex - 1];
1715    else
1716      return (java.sql.Array JavaDoc) (((Object JavaDoc[]) data.get(currentRow))[columnIndex - 1]);
1717  }
1718
1719  /**
1720   * JDBC 2.0 Returns the value of column as a Java object. Use the map to
1721   * determine the class from which to construct data of SQL structured and
1722   * distinct types.
1723   *
1724   * @param colName the column name
1725   * @param map the mapping from SQL type names to Java classes
1726   * @return an object representing the SQL value
1727   * @exception SQLException if a database-access error occurs.
1728   */

1729  public Object JavaDoc getObject(String JavaDoc colName, java.util.Map JavaDoc map)
1730      throws SQLException JavaDoc
1731  {
1732    return getObject(findColumn(colName), map);
1733  }
1734
1735  /**
1736   * JDBC 2.0 Get a REF(&lt;structured-type&gt;) column.
1737   *
1738   * @param colName the column name
1739   * @return an object representing data of an SQL REF type
1740   * @exception SQLException if a database-access error occurs.
1741   */

1742  public java.sql.Ref JavaDoc getRef(String JavaDoc colName) throws SQLException JavaDoc
1743  {
1744    return getRef(findColumn(colName));
1745  }
1746
1747  /**
1748   * JDBC 2.0 Get a BLOB column.
1749   *
1750   * @param colName the column name
1751   * @return an object representing a BLOB
1752   * @exception SQLException if a database-access error occurs.
1753   */

1754  public java.sql.Blob JavaDoc getBlob(String JavaDoc colName) throws SQLException JavaDoc
1755  {
1756    return getBlob(findColumn(colName));
1757  }
1758
1759  /**
1760   * JDBC 2.0 Get a CLOB column.
1761   *
1762   * @param colName the column name
1763   * @return an object representing a CLOB
1764   * @exception SQLException if a database-access error occurs.
1765   */

1766  public java.sql.Clob JavaDoc getClob(String JavaDoc colName) throws SQLException JavaDoc
1767  {
1768    return getClob(findColumn(colName));
1769  }
1770
1771  /**
1772   * JDBC 2.0 Get an array column.
1773   *
1774   * @param colName the column name
1775   * @return an object representing an SQL array
1776   * @exception SQLException if a database-access error occurs.
1777   */

1778  public java.sql.Array JavaDoc getArray(String JavaDoc colName) throws SQLException JavaDoc
1779  {
1780    return getArray(findColumn(colName));
1781  }
1782
1783  /**
1784   * JDBC 2.0 Get the value of a column in the current row as a java.sql.Date
1785   * object. Use the calendar to construct an appropriate millisecond value for
1786   * the Date, if the underlying database doesn't store timezone information.
1787   *
1788   * @param columnIndex the first column is 1, the second is 2, ...
1789   * @param cal the calendar to use in constructing the date (ignored)
1790   * @return the column value; if the value is SQL NULL, the result is null
1791   * @exception SQLException if a database-access error occurs.
1792   */

1793  public java.sql.Date JavaDoc getDate(int columnIndex, Calendar JavaDoc cal)
1794      throws SQLException JavaDoc
1795  {
1796    return getDate(columnIndex);
1797  }
1798
1799  /**
1800   * Get the value of a column in the current row as a java.sql.Date object. Use
1801   * the calendar to construct an appropriate millisecond value for the Date, if
1802   * the underlying database doesn't store timezone information.
1803   *
1804   * @param columnName is the SQL name of the column
1805   * @param cal the calendar to use in constructing the date
1806   * @return the column value; if the value is SQL NULL, the result is null
1807   * @exception SQLException if a database-access error occurs.
1808   */

1809  public java.sql.Date JavaDoc getDate(String JavaDoc columnName, Calendar JavaDoc cal)
1810      throws SQLException JavaDoc
1811  {
1812    return getDate(findColumn(columnName), cal);
1813  }
1814
1815  /**
1816   * Get the value of a column in the current row as a java.sql.Time object. Use
1817   * the calendar to construct an appropriate millisecond value for the Time, if
1818   * the underlying database doesn't store timezone information.
1819   *
1820   * @param columnIndex the first column is 1, the second is 2, ...
1821   * @param cal the calendar to use in constructing the time
1822   * @return the column value; if the value is SQL NULL, the result is null
1823   * @exception SQLException if a database-access error occurs.
1824   */

1825  public java.sql.Time JavaDoc getTime(int columnIndex, Calendar JavaDoc cal)
1826      throws SQLException JavaDoc
1827  {
1828    return getTime(columnIndex);
1829  }
1830
1831  /**
1832   * Get the value of a column in the current row as a java.sql.Time object. Use
1833   * the calendar to construct an appropriate millisecond value for the Time, if
1834   * the underlying database doesn't store timezone information.
1835   *
1836   * @param columnName is the SQL name of the column
1837   * @param cal the calendar to use in constructing the time
1838   * @return the column value; if the value is SQL NULL, the result is null
1839   * @exception SQLException if a database-access error occurs.
1840   */

1841  public java.sql.Time JavaDoc getTime(String JavaDoc columnName, Calendar JavaDoc cal)
1842      throws SQLException JavaDoc
1843  {
1844    return getTime(findColumn(columnName), cal);
1845  }
1846
1847  /**
1848   * Get the value of a column in the current row as a java.sql.Timestamp
1849   * object. Use the calendar to construct an appropriate millisecond value for
1850   * the Timestamp, if the underlying database doesn't store timezone
1851   * information.
1852   *
1853   * @param columnIndex the first column is 1, the second is 2, ...
1854   * @param cal the calendar to use in constructing the timestamp (ignored)
1855   * @return the column value; if the value is SQL NULL, the result is null
1856   * @exception SQLException if a database-access error occurs.
1857   */

1858  public java.sql.Timestamp JavaDoc getTimestamp(int columnIndex, Calendar JavaDoc cal)
1859      throws SQLException JavaDoc
1860  {
1861    return getTimestamp(columnIndex);
1862  }
1863
1864  /**
1865   * Get the value of a column in the current row as a java.sql.Timestamp
1866   * object. Use the calendar to construct an appropriate millisecond value for
1867   * the Timestamp, if the underlying database doesn't store timezone
1868   * information.
1869   *
1870   * @param columnName is the SQL name of the column
1871   * @param cal the calendar to use in constructing the timestamp
1872   * @return the column value; if the value is SQL NULL, the result is null
1873   * @exception SQLException if a database-access error occurs.
1874   */

1875  public java.sql.Timestamp JavaDoc getTimestamp(String JavaDoc columnName, Calendar JavaDoc cal)
1876      throws SQLException JavaDoc
1877  {
1878    return getTimestamp(findColumn(columnName), cal);
1879  }
1880
1881  // ---------------------------------------------------------------------
1882
// Updates
1883
// ---------------------------------------------------------------------
1884

1885  /**
1886   * JDBC 2.0 Determine if the current row has been updated. The value returned
1887   * depends on whether or not the result set can detect updates.
1888   *
1889   * @return <code>true</code> if the row has been visibly updated by the
1890   * owner or another, and updates are detected
1891   * @exception SQLException if a database-access error occurs
1892   * @see DatabaseMetaData#updatesAreDetected
1893   */

1894  public boolean rowUpdated() throws SQLException JavaDoc
1895  {
1896    throw new NotImplementedException("rowUpdated");
1897  }
1898
1899  /**
1900   * JDBC 2.0 Determine if the current row has been inserted. The value returned
1901   * depends on whether or not the result set can detect visible inserts.
1902   *
1903   * @return <code>true</code> if inserted and inserts are detected
1904   * @exception SQLException if a database-access error occurs
1905   * @see DatabaseMetaData#insertsAreDetected
1906   */

1907  public boolean rowInserted() throws SQLException JavaDoc
1908  {
1909    throw new NotImplementedException("rowInserted");
1910  }
1911
1912  /**
1913   * JDBC 2.0 Determine if this row has been deleted. A deleted row may leave a
1914   * visible "hole" in a result set. This method can be used to detect holes in
1915   * a result set. The value returned depends on whether or not the result set
1916   * can detect deletions.
1917   *
1918   * @return <code>true</code> if deleted and deletes are detected
1919   * @exception SQLException if a database-access error occurs
1920   * @see DatabaseMetaData#deletesAreDetected
1921   */

1922  public boolean rowDeleted() throws SQLException JavaDoc
1923  {
1924    throw new NotImplementedException("rowDeleted");
1925  }
1926
1927  /**
1928   * JDBC 2.0 Give a nullable column a null value. The updateXXX() methods are
1929   * used to update column values in the current row, or the insert row. The
1930   * updateXXX() methods do not update the underlying database, instead the
1931   * updateRow() or insertRow() methods are called to update the database.
1932   *
1933   * @param columnIndex the first column is 1, the second is 2, ...
1934   * @exception SQLException if a database-access error occurs
1935   */

1936  public void updateNull(int columnIndex) throws SQLException JavaDoc
1937  {
1938    checkIfClosed();
1939
1940    if (inserting)
1941      insertStatement
1942          .setNull(columnIndex, fields[columnIndex - 1].getSqlType());
1943    else
1944    {
1945      checkUpdateFlagAndPrepareUpdateIfNeeded();
1946      updateStatement
1947          .setNull(columnIndex, fields[columnIndex - 1].getSqlType());
1948    }
1949
1950    tempRow[columnIndex - 1] = null;
1951  }
1952
1953  /**
1954   * JDBC 2.0 Update a column with a boolean value. The updateXXX() methods are
1955   * used to update column values in the current row, or the insert row. The
1956   * updateXXX() methods do not update the underlying database, instead the
1957   * updateRow() or insertRow() methods are called to update the database.
1958   *
1959   * @param columnIndex the first column is 1, the second is 2, ...
1960   * @param x the new column value
1961   * @exception SQLException if a database-access error occurs
1962   */

1963
1964  public void updateBoolean(int columnIndex, boolean x) throws SQLException JavaDoc
1965  {
1966    checkIfClosed();
1967
1968    if (inserting)
1969      insertStatement.setBoolean(columnIndex, x);
1970    else
1971    {
1972      checkUpdateFlagAndPrepareUpdateIfNeeded();
1973      updateStatement.setBoolean(columnIndex, x);
1974    }
1975
1976    tempRow[columnIndex - 1] = Boolean.valueOf(x);
1977  }
1978
1979  /**
1980   * JDBC 2.0 Update a column with a byte value. The updateXXX() methods are
1981   * used to update column values in the current row, or the insert row. The
1982   * updateXXX() methods do not update the underlying database, instead the
1983   * updateRow() or insertRow() methods are called to update the database.
1984   *
1985   * @param columnIndex the first column is 1, the second is 2, ...
1986   * @param x the new column value
1987   * @exception SQLException if a database-access error occurs
1988   */

1989  public void updateByte(int columnIndex, byte x) throws SQLException JavaDoc
1990  {
1991    checkIfClosed();
1992
1993    if (inserting)
1994      insertStatement.setByte(columnIndex, x);
1995    else
1996    {
1997      checkUpdateFlagAndPrepareUpdateIfNeeded();
1998      updateStatement.setByte(columnIndex, x);
1999    }
2000
2001    tempRow[columnIndex - 1] = new Byte JavaDoc(x);
2002  }
2003
2004  /**
2005   * JDBC 2.0 Update a column with a short value. The updateXXX() methods are
2006   * used to update column values in the current row, or the insert row. The
2007   * updateXXX() methods do not update the underlying database, instead the
2008   * updateRow() or insertRow() methods are called to update the database.
2009   *
2010   * @param columnIndex the first column is 1, the second is 2, ...
2011   * @param x the new column value
2012   * @exception SQLException if a database-access error occurs
2013   */

2014  public void updateShort(int columnIndex, short x) throws SQLException JavaDoc
2015  {
2016    checkIfClosed();
2017
2018    if (inserting)
2019      insertStatement.setShort(columnIndex, x);
2020    else
2021    {
2022      checkUpdateFlagAndPrepareUpdateIfNeeded();
2023      updateStatement.setShort(columnIndex, x);
2024    }
2025
2026    tempRow[columnIndex - 1] = new Short JavaDoc(x);
2027  }
2028
2029  /**
2030   * JDBC 2.0 Update a column with an integer value. The updateXXX() methods are
2031   * used to update column values in the current row, or the insert row. The
2032   * updateXXX() methods do not update the underlying database, instead the
2033   * updateRow() or insertRow() methods are called to update the database.
2034   *
2035   * @param columnIndex the first column is 1, the second is 2, ...
2036   * @param x the new column value
2037   * @exception SQLException if a database-access error occurs
2038   */

2039  public void updateInt(int columnIndex, int x) throws SQLException JavaDoc
2040  {
2041    checkIfClosed();
2042
2043    if (inserting)
2044      insertStatement.setInt(columnIndex, x);
2045    else
2046    {
2047      checkUpdateFlagAndPrepareUpdateIfNeeded();
2048      updateStatement.setInt(columnIndex, x);
2049    }
2050
2051    tempRow[columnIndex - 1] = new Integer JavaDoc(x);
2052  }
2053
2054  /**
2055   * JDBC 2.0 Update a column with a long value. The updateXXX() methods are
2056   * used to update column values in the current row, or the insert row. The
2057   * updateXXX() methods do not update the underlying database, instead the
2058   * updateRow() or insertRow() methods are called to update the database.
2059   *
2060   * @param columnIndex the first column is 1, the second is 2, ...
2061   * @param x the new column value
2062   * @exception SQLException if a database-access error occurs
2063   */

2064  public void updateLong(int columnIndex, long x) throws SQLException JavaDoc
2065  {
2066    checkIfClosed();
2067
2068    if (inserting)
2069      insertStatement.setLong(columnIndex, x);
2070    else
2071    {
2072      checkUpdateFlagAndPrepareUpdateIfNeeded();
2073      updateStatement.setLong(columnIndex, x);
2074    }
2075
2076    tempRow[columnIndex - 1] = new Long JavaDoc(x);
2077  }
2078
2079  /**
2080   * JDBC 2.0 Update a column with a float value. The updateXXX() methods are
2081   * used to update column values in the current row, or the insert row. The
2082   * updateXXX() methods do not update the underlying database, instead the
2083   * updateRow() or insertRow() methods are called to update the database.
2084   *
2085   * @param columnIndex the first column is 1, the second is 2, ...
2086   * @param x the new column value
2087   * @exception SQLException if a database-access error occurs
2088   */

2089  public void updateFloat(int columnIndex, float x) throws SQLException JavaDoc
2090  {
2091    checkIfClosed();
2092
2093    if (inserting)
2094      insertStatement.setFloat(columnIndex, x);
2095    else
2096    {
2097      checkUpdateFlagAndPrepareUpdateIfNeeded();
2098      updateStatement.setFloat(columnIndex, x);
2099    }
2100
2101    tempRow[columnIndex - 1] = new Float JavaDoc(x);
2102  }
2103
2104  /**
2105   * JDBC 2.0 Update a column with a Double value. The updateXXX() methods are
2106   * used to update column values in the current row, or the insert row. The
2107   * updateXXX() methods do not update the underlying database, instead the
2108   * updateRow() or insertRow() methods are called to update the database.
2109   *
2110   * @param columnIndex the first column is 1, the second is 2, ...
2111   * @param x the new column value
2112   * @exception SQLException if a database-access error occurs
2113   */

2114  public void updateDouble(int columnIndex, double x) throws SQLException JavaDoc
2115  {
2116    checkIfClosed();
2117
2118    if (inserting)
2119      insertStatement.setDouble(columnIndex, x);
2120    else
2121    {
2122      checkUpdateFlagAndPrepareUpdateIfNeeded();
2123      updateStatement.setDouble(columnIndex, x);
2124    }
2125
2126    tempRow[columnIndex - 1] = new Double JavaDoc(x);
2127  }
2128
2129  /**
2130   * JDBC 2.0 Update a column with a BigDecimal value. The updateXXX() methods
2131   * are used to update column values in the current row, or the insert row. The
2132   * updateXXX() methods do not update the underlying database, instead the
2133   * updateRow() or insertRow() methods are called to update the database.
2134   *
2135   * @param columnIndex the first column is 1, the second is 2, ...
2136   * @param x the new column value
2137   * @exception SQLException if a database-access error occurs
2138   */

2139  public void updateBigDecimal(int columnIndex, BigDecimal JavaDoc x)
2140      throws SQLException JavaDoc
2141  {
2142    checkIfClosed();
2143
2144    if (inserting)
2145      insertStatement.setBigDecimal(columnIndex, x);
2146    else
2147    {
2148      checkUpdateFlagAndPrepareUpdateIfNeeded();
2149      updateStatement.setBigDecimal(columnIndex, x);
2150    }
2151
2152    tempRow[columnIndex - 1] = x;
2153  }
2154
2155  /**
2156   * JDBC 2.0 Update a column with a String value. The updateXXX() methods are
2157   * used to update column values in the current row, or the insert row. The
2158   * updateXXX() methods do not update the underlying database, instead the
2159   * updateRow() or insertRow() methods are called to update the database.
2160   *
2161   * @param columnIndex the first column is 1, the second is 2, ...
2162   * @param x the new column value
2163   * @exception SQLException if a database-access error occurs
2164   */

2165  public void updateString(int columnIndex, String JavaDoc x) throws SQLException JavaDoc
2166  {
2167    checkIfClosed();
2168
2169    if (inserting)
2170      insertStatement.setString(columnIndex, x);
2171    else
2172    {
2173      checkUpdateFlagAndPrepareUpdateIfNeeded();
2174      updateStatement.setString(columnIndex, x);
2175    }
2176
2177    tempRow[columnIndex - 1] = x;
2178  }
2179
2180  /**
2181   * JDBC 2.0 Update a column with a byte array value. The updateXXX() methods
2182   * are used to update column values in the current row, or the insert row. The
2183   * updateXXX() methods do not update the underlying database, instead the
2184   * updateRow() or insertRow() methods are called to update the database.
2185   *
2186   * @param columnIndex the first column is 1, the second is 2, ...
2187   * @param x the new column value
2188   * @exception SQLException if a database-access error occurs
2189   */

2190  public void updateBytes(int columnIndex, byte[] x) throws SQLException JavaDoc
2191  {
2192    checkIfClosed();
2193
2194    if (inserting)
2195      insertStatement.setBytes(columnIndex, x);
2196    else
2197    {
2198      checkUpdateFlagAndPrepareUpdateIfNeeded();
2199      updateStatement.setBytes(columnIndex, x);
2200    }
2201
2202    tempRow[columnIndex - 1] = x;
2203  }
2204
2205  /**
2206   * JDBC 2.0 Update a column with a Date value. The updateXXX() methods are
2207   * used to update column values in the current row, or the insert row. The
2208   * updateXXX() methods do not update the underlying database, instead the
2209   * updateRow() or insertRow() methods are called to update the database.
2210   *
2211   * @param columnIndex the first column is 1, the second is 2, ...
2212   * @param x the new column value
2213   * @exception SQLException if a database-access error occurs
2214   */

2215  public void updateDate(int columnIndex, java.sql.Date JavaDoc x) throws SQLException JavaDoc
2216  {
2217    checkIfClosed();
2218
2219    if (inserting)
2220      insertStatement.setDate(columnIndex, x);
2221    else
2222    {
2223      checkUpdateFlagAndPrepareUpdateIfNeeded();
2224      updateStatement.setDate(columnIndex, x);
2225    }
2226
2227    tempRow[columnIndex - 1] = x;
2228  }
2229
2230  /**
2231   * JDBC 2.0 Update a column with a Time value. The updateXXX() methods are
2232   * used to update column values in the current row, or the insert row. The
2233   * updateXXX() methods do not update the underlying database, instead the
2234   * updateRow() or insertRow() methods are called to update the database.
2235   *
2236   * @param columnIndex the first column is 1, the second is 2, ...
2237   * @param x the new column value
2238   * @exception SQLException if a database-access error occurs
2239   */

2240  public void updateTime(int columnIndex, java.sql.Time JavaDoc x) throws SQLException JavaDoc
2241  {
2242    checkIfClosed();
2243
2244    if (inserting)
2245      insertStatement.setTime(columnIndex, x);
2246    else
2247    {
2248      checkUpdateFlagAndPrepareUpdateIfNeeded();
2249      updateStatement.setTime(columnIndex, x);
2250    }
2251
2252    tempRow[columnIndex - 1] = x;
2253  }
2254
2255  /**
2256   * JDBC 2.0 Update a column with a Timestamp value. The updateXXX() methods
2257   * are used to update column values in the current row, or the insert row. The
2258   * updateXXX() methods do not update the underlying database, instead the
2259   * updateRow() or insertRow() methods are called to update the database.
2260   *
2261   * @param columnIndex the first column is 1, the second is 2, ...
2262   * @param x the new column value
2263   * @exception SQLException if a database-access error occurs
2264   */

2265  public void updateTimestamp(int columnIndex, java.sql.Timestamp JavaDoc x)
2266      throws SQLException JavaDoc
2267  {
2268    checkIfClosed();
2269
2270    if (inserting)
2271      insertStatement.setTimestamp(columnIndex, x);
2272    else
2273    {
2274      checkUpdateFlagAndPrepareUpdateIfNeeded();
2275      updateStatement.setTimestamp(columnIndex, x);
2276    }
2277
2278    tempRow[columnIndex - 1] = x;
2279  }
2280
2281  /**
2282   * JDBC 2.0 Update a column with an ascii stream value. The updateXXX()
2283   * methods are used to update column values in the current row, or the insert
2284   * row. The updateXXX() methods do not update the underlying database, instead
2285   * the updateRow() or insertRow() methods are called to update the database.
2286   *
2287   * @param columnIndex the first column is 1, the second is 2, ...
2288   * @param x the new column value
2289   * @param length the length of the stream
2290   * @exception SQLException if a database-access error occurs
2291   */

2292  public void updateAsciiStream(int columnIndex, java.io.InputStream JavaDoc x,
2293      int length) throws SQLException JavaDoc
2294  {
2295    this.updateBinaryStream(columnIndex, x, length);
2296  }
2297
2298  /**
2299   * JDBC 2.0 Update a column with a binary stream value. The updateXXX()
2300   * methods are used to update column values in the current row, or the insert
2301   * row. The updateXXX() methods do not update the underlying database, instead
2302   * the updateRow() or insertRow() methods are called to update the database.
2303   *
2304   * @param columnIndex the first column is 1, the second is 2, ...
2305   * @param x the new column value
2306   * @param length the length of the stream
2307   * @exception SQLException if a database-access error occurs
2308   */

2309  public void updateBinaryStream(int columnIndex, java.io.InputStream JavaDoc x,
2310      int length) throws SQLException JavaDoc
2311  {
2312    checkIfClosed();
2313
2314    byte[] content = new byte[length];
2315    try
2316    {
2317      x.read(content, 0, length);
2318    }
2319    catch (Exception JavaDoc ioe)
2320    {
2321      throw new SQLException JavaDoc("Problem with streaming of data");
2322    }
2323
2324    this.updateBytes(columnIndex, content);
2325  }
2326
2327  /**
2328   * JDBC 2.0 Update a column with a character stream value. The updateXXX()
2329   * methods are used to update column values in the current row, or the insert
2330   * row. The updateXXX() methods do not update the underlying database, instead
2331   * the updateRow() or insertRow() methods are called to update the database.
2332   *
2333   * @param columnIndex the first column is 1, the second is 2, ...
2334   * @param x the new column value
2335   * @param length the length of the stream
2336   * @exception SQLException if a database-access error occurs
2337   */

2338  public void updateCharacterStream(int columnIndex, java.io.Reader JavaDoc x,
2339      int length) throws SQLException JavaDoc
2340  {
2341    checkIfClosed();
2342
2343    char[] content = new char[length];
2344    try
2345    {
2346      x.read(content, 0, length);
2347    }
2348    catch (Exception JavaDoc ioe)
2349    {
2350      throw new SQLException JavaDoc("Problem with streaming of data");
2351    }
2352
2353    this.updateString(columnIndex, new String JavaDoc(content));
2354  }
2355
2356  /**
2357   * JDBC 2.0 Update a column with an Object value. The updateXXX() methods are
2358   * used to update column values in the current row, or the insert row. The
2359   * updateXXX() methods do not update the underlying database, instead the
2360   * updateRow() or insertRow() methods are called to update the database.
2361   *
2362   * @param columnIndex the first column is 1, the second is 2, ...
2363   * @param x the new column value
2364   * @param scale For java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types
2365   * this is the number of digits after the decimal. For all other
2366   * types this value will be ignored.
2367   * @exception SQLException if a database-access error occurs
2368   */

2369  public void updateObject(int columnIndex, Object JavaDoc x, int scale)
2370      throws SQLException JavaDoc
2371  {
2372    checkIfClosed();
2373
2374    if (inserting)
2375      insertStatement.setObject(columnIndex, x, scale);
2376    else
2377    {
2378      checkUpdateFlagAndPrepareUpdateIfNeeded();
2379      updateStatement.setObject(columnIndex, x, scale);
2380    }
2381
2382    tempRow[columnIndex - 1] = x;
2383  }
2384
2385  /**
2386   * JDBC 2.0 Update a column with an Object value. The updateXXX() methods are
2387   * used to update column values in the current row, or the insert row. The
2388   * updateXXX() methods do not update the underlying database, instead the
2389   * updateRow() or insertRow() methods are called to update the database.
2390   *
2391   * @param columnIndex the first column is 1, the second is 2, ...
2392   * @param x the new column value
2393   * @exception SQLException if a database-access error occurs
2394   */

2395  public void updateObject(int columnIndex, Object JavaDoc x) throws SQLException JavaDoc
2396  {
2397    checkIfClosed();
2398
2399    if (inserting)
2400      insertStatement.setObject(columnIndex, x);
2401    else
2402    {
2403      checkUpdateFlagAndPrepareUpdateIfNeeded();
2404      updateStatement.setObject(columnIndex, x);
2405    }
2406
2407    tempRow[columnIndex - 1] = x;
2408  }
2409
2410  /**
2411   * JDBC 2.0 Update a column with a null value. The updateXXX() methods are
2412   * used to update column values in the current row, or the insert row. The
2413   * updateXXX() methods do not update the underlying database, instead the
2414   * updateRow() or insertRow() methods are called to update the database.
2415   *
2416   * @param columnName the name of the column
2417   * @exception SQLException if a database-access error occurs
2418   */

2419
2420  public void updateNull(String JavaDoc columnName) throws SQLException JavaDoc
2421  {
2422    this.updateNull(findColumn(columnName));
2423  }
2424
2425  /**
2426   * JDBC 2.0 Update a column with a boolean value. The updateXXX() methods are
2427   * used to update column values in the current row, or the insert row. The
2428   * updateXXX() methods do not update the underlying database, instead the
2429   * updateRow() or insertRow() methods are called to update the database.
2430   *
2431   * @param columnName the name of the column
2432   * @param x the new column value
2433   * @exception SQLException if a database-access error occurs
2434   */

2435  public void updateBoolean(String JavaDoc columnName, boolean x) throws SQLException JavaDoc
2436  {
2437    this.updateBoolean(findColumn(columnName), x);
2438  }
2439
2440  /**
2441   * JDBC 2.0 Update a column with a byte value. The updateXXX() methods are
2442   * used to update column values in the current row, or the insert row. The
2443   * updateXXX() methods do not update the underlying database, instead the
2444   * updateRow() or insertRow() methods are called to update the database.
2445   *
2446   * @param columnName the name of the column
2447   * @param x the new column value
2448   * @exception SQLException if a database-access error occurs
2449   */

2450  public void updateByte(String JavaDoc columnName, byte x) throws SQLException JavaDoc
2451  {
2452    this.updateByte(findColumn(columnName), x);
2453  }
2454
2455  /**
2456   * JDBC 2.0 Update a column with a short value. The updateXXX() methods are
2457   * used to update column values in the current row, or the insert row. The
2458   * updateXXX() methods do not update the underlying database, instead the
2459   * updateRow() or insertRow() methods are called to update the database.
2460   *
2461   * @param columnName the name of the column
2462   * @param x the new column value
2463   * @exception SQLException if a database-access error occurs
2464   */

2465  public void updateShort(String JavaDoc columnName, short x) throws SQLException JavaDoc
2466  {
2467    this.updateShort(findColumn(columnName), x);
2468  }
2469
2470  /**
2471   * JDBC 2.0 Update a column with an integer value. The updateXXX() methods are
2472   * used to update column values in the current row, or the insert row. The
2473   * updateXXX() methods do not update the underlying database, instead the
2474   * updateRow() or insertRow() methods are called to update the database.
2475   *
2476   * @param columnName the name of the column
2477   * @param x the new column value
2478   * @exception SQLException if a database-access error occurs
2479   */

2480  public void updateInt(String JavaDoc columnName, int x) throws SQLException JavaDoc
2481  {
2482    this.updateInt(findColumn(columnName), x);
2483  }
2484
2485  /**
2486   * JDBC 2.0 Update a column with a long value. The updateXXX() methods are
2487   * used to update column values in the current row, or the insert row. The
2488   * updateXXX() methods do not update the underlying database, instead the
2489   * updateRow() or insertRow() methods are called to update the database.
2490   *
2491   * @param columnName the name of the column
2492   * @param x the new column value
2493   * @exception SQLException if a database-access error occurs
2494   */

2495  public void updateLong(String JavaDoc columnName, long x) throws SQLException JavaDoc
2496  {
2497    this.updateLong(findColumn(columnName), x);
2498  }
2499
2500  /**
2501   * JDBC 2.0 Update a column with a float value. The updateXXX() methods are
2502   * used to update column values in the current row, or the insert row. The
2503   * updateXXX() methods do not update the underlying database, instead the
2504   * updateRow() or insertRow() methods are called to update the database.
2505   *
2506   * @param columnName the name of the column
2507   * @param x the new column value
2508   * @exception SQLException if a database-access error occurs
2509   */

2510  public void updateFloat(String JavaDoc columnName, float x) throws SQLException JavaDoc
2511  {
2512    this.updateFloat(findColumn(columnName), x);
2513  }
2514
2515  /**
2516   * JDBC 2.0 Update a column with a double value. The updateXXX() methods are
2517   * used to update column values in the current row, or the insert row. The
2518   * updateXXX() methods do not update the underlying database, instead the
2519   * updateRow() or insertRow() methods are called to update the database.
2520   *
2521   * @param columnName the name of the column
2522   * @param x the new column value
2523   * @exception SQLException if a database-access error occurs
2524   */

2525  public void updateDouble(String JavaDoc columnName, double x) throws SQLException JavaDoc
2526  {
2527    this.updateDouble(findColumn(columnName), x);
2528  }
2529
2530  /**
2531   * JDBC 2.0 Update a column with a BigDecimal value. The updateXXX() methods
2532   * are used to update column values in the current row, or the insert row. The
2533   * updateXXX() methods do not update the underlying database, instead the
2534   * updateRow() or insertRow() methods are called to update the database.
2535   *
2536   * @param columnName the name of the column
2537   * @param x the new column value
2538   * @exception SQLException if a database-access error occurs
2539   */

2540  public void updateBigDecimal(String JavaDoc columnName, BigDecimal JavaDoc x)
2541      throws SQLException JavaDoc
2542  {
2543    this.updateBigDecimal(findColumn(columnName), x);
2544  }
2545
2546  /**
2547   * JDBC 2.0 Update a column with a String value. The updateXXX() methods are
2548   * used to update column values in the current row, or the insert row. The
2549   * updateXXX() methods do not update the underlying database, instead the
2550   * updateRow() or insertRow() methods are called to update the database.
2551   *
2552   * @param columnName the name of the column
2553   * @param x the new column value
2554   * @exception SQLException if a database-access error occurs
2555   */

2556  public void updateString(String JavaDoc columnName, String JavaDoc x) throws SQLException JavaDoc
2557  {
2558    this.updateString(findColumn(columnName), x);
2559  }
2560
2561  /**
2562   * JDBC 2.0 Update a column with a byte array value. The updateXXX() methods
2563   * are used to update column values in the current row, or the insert row. The
2564   * updateXXX() methods do not update the underlying database, instead the
2565   * updateRow() or insertRow() methods are called to update the database.
2566   *
2567   * @param columnName the name of the column
2568   * @param x the new column value
2569   * @exception SQLException if a database-access error occurs
2570   */

2571  public void updateBytes(String JavaDoc columnName, byte[] x) throws SQLException JavaDoc
2572  {
2573    this.updateBytes(findColumn(columnName), x);
2574  }
2575
2576  /**
2577   * JDBC 2.0 Update a column with a Date value. The updateXXX() methods are
2578   * used to update column values in the current row, or the insert row. The
2579   * updateXXX() methods do not update the underlying database, instead the
2580   * updateRow() or insertRow() methods are called to update the database.
2581   *
2582   * @param columnName the name of the column
2583   * @param x the new column value
2584   * @exception SQLException if a database-access error occurs
2585   */

2586  public void updateDate(String JavaDoc columnName, java.sql.Date JavaDoc x)
2587      throws SQLException JavaDoc
2588  {
2589    this.updateDate(findColumn(columnName), x);
2590  }
2591
2592  /**
2593   * JDBC 2.0 Update a column with a Time value. The updateXXX() methods are
2594   * used to update column values in the current row, or the insert row. The
2595   * updateXXX() methods do not update the underlying database, instead the
2596   * updateRow() or insertRow() methods are called to update the database.
2597   *
2598   * @param columnName the name of the column
2599   * @param x the new column value
2600   * @exception SQLException if a database-access error occurs
2601   */

2602  public void updateTime(String JavaDoc columnName, java.sql.Time JavaDoc x)
2603      throws SQLException JavaDoc
2604  {
2605    this.updateTime(findColumn(columnName), x);
2606  }
2607
2608  /**
2609   * JDBC 2.0 Update a column with a Timestamp value. The updateXXX() methods
2610   * are used to update column values in the current row, or the insert row. The
2611   * updateXXX() methods do not update the underlying database, instead the
2612   * updateRow() or insertRow() methods are called to update the database.
2613   *
2614   * @param columnName the name of the column
2615   * @param x the new column value
2616   * @exception SQLException if a database-access error occurs
2617   */

2618  public void updateTimestamp(String JavaDoc columnName, java.sql.Timestamp JavaDoc x)
2619      throws SQLException JavaDoc
2620  {
2621    this.updateTimestamp(findColumn(columnName), x);
2622  }
2623
2624  /**
2625   * JDBC 2.0 Update a column with an ascii stream value. The updateXXX()
2626   * methods are used to update column values in the current row, or the insert
2627   * row. The updateXXX() methods do not update the underlying database, instead
2628   * the updateRow() or insertRow() methods are called to update the database.
2629   *
2630   * @param columnName the name of the column
2631   * @param x the new column value
2632   * @param length of the stream
2633   * @exception SQLException if a database-access error occurs
2634   */

2635  public void updateAsciiStream(String JavaDoc columnName, java.io.InputStream JavaDoc x,
2636      int length) throws SQLException JavaDoc
2637  {
2638    this.updateAsciiStream(findColumn(columnName), x, length);
2639  }
2640
2641  /**
2642   * JDBC 2.0 Update a column with a binary stream value. The updateXXX()
2643   * methods are used to update column values in the current row, or the insert
2644   * row. The updateXXX() methods do not update the underlying database, instead
2645   * the updateRow() or insertRow() methods are called to update the database.
2646   *
2647   * @param columnName the name of the column
2648   * @param x the new column value
2649   * @param length of the stream
2650   * @exception SQLException if a database-access error occurs
2651   */

2652  public void updateBinaryStream(String JavaDoc columnName, java.io.InputStream JavaDoc x,
2653      int length) throws SQLException JavaDoc
2654  {
2655    this.updateBinaryStream(findColumn(columnName), x, length);
2656  }
2657
2658  /**
2659   * JDBC 2.0 Update a column with a character stream value. The updateXXX()
2660   * methods are used to update column values in the current row, or the insert
2661   * row. The updateXXX() methods do not update the underlying database, instead
2662   * the updateRow() or insertRow() methods are called to update the database.
2663   *
2664   * @param columnName the name of the column
2665   * @param reader the stream
2666   * @param length of the stream
2667   * @exception SQLException if a database-access error occurs
2668   */

2669  public void updateCharacterStream(String JavaDoc columnName, java.io.Reader JavaDoc reader,
2670      int length) throws SQLException JavaDoc
2671  {
2672    this.updateCharacterStream(findColumn(columnName), reader, length);
2673  }
2674
2675  /**
2676   * JDBC 2.0 Update a column with an Object value. The updateXXX() methods are
2677   * used to update column values in the current row, or the insert row. The
2678   * updateXXX() methods do not update the underlying database, instead the
2679   * updateRow() or insertRow() methods are called to update the database.
2680   *
2681   * @param columnName the name of the column
2682   * @param x the new column value
2683   * @param scale For java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types
2684   * this is the number of digits after the decimal. For all other
2685   * types this value will be ignored.
2686   * @exception SQLException if a database-access error occurs
2687   */

2688  public void updateObject(String JavaDoc columnName, Object JavaDoc x, int scale)
2689      throws SQLException JavaDoc
2690  {
2691    this.updateObject(findColumn(columnName), x, scale);
2692  }
2693
2694  /**
2695   * JDBC 2.0 Update a column with an Object value. The updateXXX() methods are
2696   * used to update column values in the current row, or the insert row. The
2697   * updateXXX() methods do not update the underlying database, instead the
2698   * updateRow() or insertRow() methods are called to update the database.
2699   *
2700   * @param columnName the name of the column
2701   * @param x the new column value
2702   * @exception SQLException if a database-access error occurs
2703   */

2704  public void updateObject(String JavaDoc columnName, Object JavaDoc x) throws SQLException JavaDoc
2705  {
2706    this.updateObject(findColumn(columnName), x);
2707  }
2708
2709  /**
2710   * JDBC 2.0 Insert the contents of the insert row into the result set and the
2711   * database. Must be on the insert row when this method is called.
2712   *
2713   * @exception SQLException if a database-access error occurs, if called when
2714   * not on the insert row, or if all non-nullable columns in the
2715   * insert row have not been given a value
2716   */

2717  public void insertRow() throws SQLException JavaDoc
2718  {
2719    checkIfClosed();
2720
2721    if (!inserting)
2722      throw new SQLException JavaDoc("insertRow cannot be called "
2723          + "when the cursor is not on the insert row");
2724
2725    // Insert row in underlying database
2726
try
2727    {
2728      insertStatement.executeUpdate();
2729    }
2730    finally
2731    {
2732      // Clean up
2733
insertStatement.clearParameters();
2734    }
2735
2736    // Insert row in this ResultSet
2737
if (data == null)
2738      data = new ArrayList JavaDoc();
2739    data.add(tempRow);
2740    nbOfRows++;
2741
2742    // Prepare for a new insert
2743
tempRow = new Object JavaDoc[nbOfColumns];
2744  }
2745
2746  /**
2747   * JDBC 2.0 Update the underlying database with the new contents of the
2748   * current row. Cannot be called when on the insert row.
2749   *
2750   * @exception SQLException if a database-access error occurs, or if called
2751   * when on the insert row
2752   */

2753  public void updateRow() throws SQLException JavaDoc
2754  {
2755    checkIfClosed();
2756
2757    if (inserting)
2758      throw new SQLException JavaDoc("updateRow cannot be called "
2759          + "when the cursor is on the insert row");
2760
2761    if (!updating)
2762      return;
2763
2764    // Add primary key info from current row
2765
for (int i = 0; i < primaryKeyColumns.length; ++i)
2766      updateStatement.setObject(nbOfColumns + i + 1, ((Object JavaDoc[]) data
2767          .get(currentRow))[findColumn(primaryKeyColumns[i]) - 1]);
2768
2769    // Update row in underlying database
2770
try
2771    {
2772      updateStatement.executeUpdate();
2773    }
2774    finally
2775    {
2776      // Clean up
2777
updateStatement.clearParameters();
2778    }
2779
2780    // Update row in this ResultSet
2781
data.set(currentRow, tempRow);
2782
2783    // Clean up
2784
tempRow = null;
2785    updating = false;
2786  }
2787
2788  /**
2789   * JDBC 2.0 Delete the current row from the result set and the underlying
2790   * database. Cannot be called when on the insert row.
2791   *
2792   * @exception SQLException if a database-access error occurs, or if called
2793   * when on the insert row.
2794   */

2795  public void deleteRow() throws SQLException JavaDoc
2796  {
2797    checkIfClosed();
2798
2799    if (inserting)
2800      throw new SQLException JavaDoc("deleteRow cannot be called "
2801          + "when the cursor is on the insert row");
2802
2803    this.checkRowPos();
2804
2805    if (deleteStatement == null)
2806      this.buildDeleteStatement();
2807
2808    // Add primary key info from current row
2809
for (int i = 0; i < primaryKeyColumns.length; ++i)
2810      deleteStatement
2811          .setObject(
2812              i + 1,
2813              ((Object JavaDoc[]) data.get(currentRow))[findColumn(primaryKeyColumns[i]) - 1]);
2814
2815    // Delete row from underlying database
2816
try
2817    {
2818      deleteStatement.executeUpdate();
2819    }
2820    finally
2821    {
2822      // Clean up
2823
deleteStatement.clearParameters();
2824    }
2825
2826    // Delete row from this ResultSet
2827
data.remove(currentRow);
2828    nbOfRows--;
2829
2830    // Deleting cancels all updates on the row
2831
if (updating)
2832      this.cancelRowUpdates();
2833  }
2834
2835  /**
2836   * JDBC 2.0 Refresh the value of the current row with its current value in the
2837   * database. Cannot be called when on the insert row. The refreshRow() method
2838   * provides a way for an application to explicitly tell the JDBC driver to
2839   * refetch a row(s) from the database. An application may want to call
2840   * refreshRow() when caching or prefetching is being done by the JDBC driver
2841   * to fetch the latest value of a row from the database. The JDBC driver may
2842   * actually refresh multiple rows at once if the fetch size is greater than
2843   * one. All values are refetched subject to the transaction isolation level
2844   * and cursor sensitivity. If refreshRow() is called after calling
2845   * updateXXX(), but before calling updateRow() then the updates made to the
2846   * row are lost. Calling refreshRow() frequently will likely slow performance.
2847   *
2848   * @exception SQLException if a database-access error occurs, or if called
2849   * when on the insert row.
2850   */

2851  public void refreshRow() throws SQLException JavaDoc
2852  {
2853    checkIfClosed();
2854
2855    if (inserting)
2856      throw new SQLException JavaDoc("refreshRow cannot be called "
2857          + "when the cursor is on the insert row");
2858
2859    this.checkRowPos();
2860
2861    if (refreshStatement == null)
2862      this.buildRefreshStatement();
2863
2864    // Add primary key info from current row
2865
for (int i = 0; i < primaryKeyColumns.length; ++i)
2866      refreshStatement
2867          .setObject(
2868              i + 1,
2869              ((Object JavaDoc[]) data.get(currentRow))[findColumn(primaryKeyColumns[i]) - 1]);
2870
2871    // Retrieve row from underlying database
2872
DriverResultSet res;
2873    try
2874    {
2875      res = (DriverResultSet) refreshStatement.executeQuery();
2876    }
2877    finally
2878    {
2879      // Clean up
2880
refreshStatement.clearParameters();
2881    }
2882
2883    // Refresh row in this ResultSet
2884
try
2885    {
2886      data.set(currentRow, res.data.get(0));
2887    }
2888    catch (NullPointerException JavaDoc e)
2889    {
2890      throw new SQLException JavaDoc("The current row has been "
2891          + "removed from the database");
2892    }
2893    finally
2894    {
2895      // Clean up
2896
res.close();
2897    }
2898
2899    // Refreshing cancels all updates on the row
2900
if (updating)
2901      this.cancelRowUpdates();
2902  }
2903
2904  /**
2905   * JDBC 2.0 The cancelRowUpdates() method may be called after calling an
2906   * updateXXX() method(s) and before calling updateRow() to rollback the
2907   * updates made to a row. If no updates have been made or updateRow() has
2908   * already been called, then this method has no effect.
2909   *
2910   * @exception SQLException if a database-access error occurs, or if called
2911   * when on the insert row.
2912   */

2913  public void cancelRowUpdates() throws SQLException JavaDoc
2914  {
2915    checkIfClosed();
2916
2917    if (inserting)
2918      throw new SQLException JavaDoc("cancelRowUpdates cannot be "
2919          + "called when the cursor is on the insert row");
2920
2921    if (!updating)
2922      return;
2923
2924    updateStatement.clearParameters();
2925    tempRow = null;
2926    updating = false;
2927  }
2928
2929  /**
2930   * JDBC 2.0 Move to the insert row. The current cursor position is remembered
2931   * while the cursor is positioned on the insert row. The insert row is a
2932   * special row associated with an updatable result set. It is essentially a
2933   * buffer where a new row may be constructed by calling the updateXXX()
2934   * methods prior to inserting the row into the result set. Only the
2935   * updateXXX(), getXXX(), and insertRow() methods may be called when the
2936   * cursor is on the insert row. All of the columns in a result set must be
2937   * given a value each time this method is called before calling insertRow().
2938   * UpdateXXX()must be called before getXXX() on a column.
2939   *
2940   * @exception SQLException if a database-access error occurs, or the result
2941   * set is not updatable
2942   */

2943  public void moveToInsertRow() throws SQLException JavaDoc
2944  {
2945    checkIfClosed();
2946
2947    if (inserting)
2948      return;
2949
2950    if (insertStatement == null)
2951      this.buildInsertStatement();
2952
2953    tempRow = new Object JavaDoc[nbOfColumns];
2954    inserting = true;
2955  }
2956
2957  /**
2958   * JDBC 2.0 Move the cursor to the remembered cursor position, usually the
2959   * current row. Has no effect unless the cursor is on the insert row.
2960   *
2961   * @exception SQLException if a database-access error occurs, or the result
2962   * set is not updatable
2963   */

2964  public void moveToCurrentRow() throws SQLException JavaDoc
2965  {
2966    checkIfClosed();
2967
2968    if (!inserting)
2969      return;
2970
2971    insertStatement.clearParameters();
2972    tempRow = null;
2973    inserting = false;
2974  }
2975
2976  //
2977
// ------------------------------------------
2978
// ResultSet meta-data related functions
2979
// ------------------------------------------
2980
//
2981

2982  /**
2983   * JDBC 2.0 Return the type of this result set. The type is determined based
2984   * on the statement that created the result set.
2985   *
2986   * @return TYPE_FORWARD_ONLY, TYPE_SCROLL_INSENSITIVE, or
2987   * TYPE_SCROLL_SENSITIVE
2988   * @exception SQLException if a database-access error occurs
2989   */

2990  public int getType() throws SQLException JavaDoc
2991  {
2992    return resultSetType;
2993  }
2994
2995  /**
2996   * JDBC 2.0 Return the concurrency of this result set. The concurrency used is
2997   * determined by the statement that created the result set.
2998   *
2999   * @return CONCUR_READ_ONLY or CONCUR_UPDATABLE
3000   * @exception SQLException if a database-access error occurs
3001   */

3002
3003  public int getConcurrency() throws SQLException JavaDoc
3004  {
3005    return resultSetConcurrency;
3006  }
3007
3008  /**
3009   * Closes the remote ResultSet if the ResultSet was streamed else just closes
3010   * the ResultSet locally.
3011   *
3012   * @exception SQLException if a database access error occurs
3013   */

3014  public void close() throws SQLException JavaDoc
3015  {
3016    if (hasMoreData)
3017      this.connection.closeRemoteResultSet(cursorName);
3018    isClosed = true;
3019  }
3020
3021  /**
3022   * A column may have the value of SQL NULL; wasNull() reports whether the last
3023   * column read had this special value. Note that you must first call getXXX on
3024   * a column to try to read its value and then call wasNull() to find if the
3025   * value was SQL NULL
3026   *
3027   * @return <code>true</code> if the last column read was SQL NULL
3028   * @exception SQLException if a database access error occurred
3029   */

3030
3031  public boolean wasNull() throws SQLException JavaDoc
3032  {
3033    return wasNullFlag;
3034  }
3035
3036  /**
3037   * JDBC 2.0 Return the <code>Statement</code> that produced the
3038   * <code>ResultSet</code>.
3039   *
3040   * @return the <code>Statement</code> that produced the
3041   * <code>ResultSet</code>, or null if the result was produced some
3042   * other way.
3043   * @exception SQLException if a database-access error occurs
3044   */

3045  public java.sql.Statement JavaDoc getStatement() throws SQLException JavaDoc
3046  {
3047    return owningStatement;
3048  }
3049
3050  /**
3051   * Set the ResultSet data with the given ArrayList. This function is used by
3052   * the ResultSet streaming feature.
3053   * <p>
3054   * Note that metadata (currentRow, nbOfRows, ...) are not updated.
3055   *
3056   * @param newData new ResultSet data
3057   */

3058  public void setData(ArrayList JavaDoc newData)
3059  {
3060    this.data = newData;
3061    if (newData == null)
3062      this.nbOfRows = 0;
3063    else
3064      this.nbOfRows = newData.size();
3065  }
3066
3067  /**
3068   * Set the hasMoreData boolean (is there more data to fetch from the
3069   * controller). This function is used by the ResultSet streaming feature.
3070   *
3071   * @param hasMore new value for hasMoreData
3072   */

3073  public void setHasMoreData(boolean hasMore)
3074  {
3075    hasMoreData = hasMore;
3076  }
3077
3078  /**
3079   * The numbers, types and properties of a <code>ResultSet</code>'s columns
3080   * are provided by the <code>getMetaData</code> method
3081   *
3082   * @return a description of the <code>ResultSet</code>'s columns
3083   * @exception SQLException if a database access error occurs
3084   */

3085  public java.sql.ResultSetMetaData JavaDoc getMetaData() throws SQLException JavaDoc
3086  {
3087    return new ResultSetMetaData(this);
3088  }
3089
3090  /**
3091   * Map a <code>ResultSet</code> column name to a <code>ResultSet</code>
3092   * column index
3093   *
3094   * @param columnName the name of the column
3095   * @return the column index
3096   * @exception SQLException if a database access error occurs
3097   */

3098  public int findColumn(String JavaDoc columnName) throws SQLException JavaDoc
3099  {
3100    if (columnNameToIndex == null)
3101      buildIndexMapping();
3102
3103    Integer JavaDoc index = (Integer JavaDoc) columnNameToIndex.get(columnName);
3104
3105    if (index == null)
3106      index = (Integer JavaDoc) fullColumnNameToIndex.get(columnName);
3107
3108    if (index != null)
3109      return index.intValue() + 1;
3110    else
3111    {
3112      // Try this inefficient way, now
3113
String JavaDoc columnNameUC = columnName.toUpperCase();
3114      for (int i = 0; i < nbOfColumns; i++)
3115      {
3116        if (fields[i].getFieldName().toUpperCase().equals(columnNameUC))
3117          return i + 1;
3118        else if (fields[i].getFullName().toUpperCase().equals(columnNameUC))
3119          return i + 1;
3120      }
3121      throw new java.sql.SQLException JavaDoc("Column '" + columnName + "' not found.");
3122    }
3123  }
3124
3125  // ****************************************************************
3126
//
3127
// END OF PUBLIC INTERFACE
3128
//
3129
// ****************************************************************
3130

3131  /**
3132   * Initialize serializers based on the analysis of actual Java Objects of the
3133   * ResultSet to send (typically issued by backend's driver readObject()
3134   * method).
3135   */

3136  private void initSerializers() throws NotSerializableException JavaDoc
3137  {
3138    /* we don't expect the column types of "this" result set to change */
3139    if (this.serializers != null)
3140      return;
3141
3142    this.serializers = new SQLDataSerialization.Serializer[nbOfColumns];
3143
3144    for (int col = 0; col < nbOfColumns; col++)
3145    {
3146      int rowIdx = -1;
3147      while (serializers[col] == null)
3148      {
3149        rowIdx++;
3150
3151        // We browsed the whole column and found nothing but NULLs
3152
if (rowIdx >= nbOfRows) // ? || rowIdx > 100)
3153
break;
3154
3155        Object JavaDoc[] row = (Object JavaDoc[]) data.get(rowIdx);
3156        Object JavaDoc sqlObj = row[col];
3157
3158        /*
3159         * If SQL was NULL, we only have a null reference and can't do much with
3160         * it. Move down to next row
3161         */

3162        if (sqlObj == null)
3163          continue;
3164
3165        try
3166        {
3167          serializers[col] = SQLDataSerialization.getSerializer(sqlObj);
3168        }
3169        catch (NotImplementedException nie)
3170        {
3171          if (sqlObj instanceof Short JavaDoc)
3172          {
3173            /**
3174             * This is a workaround for a bug in (at least) PostgreSQL's driver.
3175             * This bug has been only very recently fixed: 8 jun 2005 in version
3176             * 1.75 of source file
3177             * pgjdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java
3178             * http://jdbc.postgresql.org/development/cvs.html.
3179             * <p>
3180             * It seems this java.lang.Short bug happens with multiple DBMS:
3181             * http://archives.postgresql.org/pgsql-jdbc/2005-07/threads.php#00382
3182             */

3183
3184            // Unfortunately we have not access to any logger at this point.
3185
// TODO: append the following SQLwarning() to this resultset
3186
// "Buggy backend driver returns a java.lang.Short"
3187
// + " for column number " + col + ", converting to Integer"
3188

3189            try
3190            {
3191              serializers[col] = SQLDataSerialization
3192                  .getSerializer(TypeTag.INTEGER);
3193            }
3194            catch (NotImplementedException e)
3195            {
3196              throw new IllegalArgumentException JavaDoc("Internal bug");
3197            }
3198          }
3199          else
3200          {
3201            NotSerializableException JavaDoc nse = new NotSerializableException JavaDoc(
3202                "Backend driver gave an object of an unsupported java type:"
3203                    + sqlObj.getClass().getName() + ", at colum number " + col
3204                    + " of name " + fields[col].getFieldName());
3205            nse.initCause(nie);
3206            throw nse;
3207          }
3208        }
3209
3210      } // while (row)
3211

3212      if (serializers[col] == null) // we found nothing
3213
{
3214        // TODO: add the following SQLWarning() to this resultset
3215
// "The whole column number " + col + " was null"
3216

3217        /**
3218         * The whole column is null. Fall back on the JDBC type provided by
3219         * backend's metaData.getColumnType(), hoping it's right. Since we are
3220         * sending just nulls, a wrong typing should not do much harm anyway ?
3221         *
3222         * @see org.objectweb.cjdbc.controller.virtualdatabase.ControllerResultSet#ControllerResultSet(AbstractRequest,
3223         * java.sql.ResultSet, MetadataCache, Statement)
3224         */

3225        /**
3226         * We could (should ?) also use {@link Field#getColumnClassName()}, and
3227         * do some reflection instead. This is depending on the behaviour and
3228         * quality of the JDBC driver of the backends we want to support.
3229         */

3230
3231        TypeTag javaObjectType = TypeTag.jdbcToJavaObjectType(fields[col]
3232            .getSqlType());
3233
3234        if (javaObjectType != TypeTag.TYPE_ERROR)
3235          try
3236          {
3237            serializers[col] = SQLDataSerialization
3238                .getSerializer(javaObjectType);
3239          }
3240          catch (NotImplementedException nie)
3241          {
3242            // since we passed a TypeTag it's really impossible to come here
3243
IllegalArgumentException JavaDoc ipe = new IllegalArgumentException JavaDoc(
3244                "Really incredible bug, TypeTag was: " + javaObjectType);
3245            ipe.initCause(nie);
3246            throw ipe;
3247          }
3248        else
3249        { // javaObjectType == TypeTag.TYPE_ERROR
3250
throw new NotSerializableException JavaDoc(
3251              "Could not guess type of column number " + col
3252                  + "whole column is null and backend does not provide "
3253                  + "a known JDBC type");
3254        }
3255      }
3256
3257    } // for (column)
3258

3259  }
3260
3261  /**
3262   * Creates a new <code>DriverResultSet</code> from a non-null ArrayList of
3263   * rows. Allowed only on the controller side. We could use a resultset factory
3264   * instead in order to be more cleanly isolated from the controller.
3265   *
3266   * @param fields an array of <code>Field</code> objects (basically, the
3267   * <code>ResultSet</code> meta data)
3268   * @param resultData ArrayList of Object[] rows.
3269   * @throws IllegalArgumentException if resultData argument is null
3270   */

3271  public DriverResultSet(Field[] fields, ArrayList JavaDoc resultData)
3272      throws IllegalArgumentException JavaDoc
3273  {
3274    if (resultData == null)
3275      throw new IllegalArgumentException JavaDoc(
3276          "Cannot build a DriverResultSet with null data ArrayList");
3277
3278    this.data = resultData;
3279    currentRow = -1;
3280    this.fields = fields;
3281
3282    nbOfRows = resultData.size();
3283    nbOfColumns = fields.length;
3284    isClosed = false;
3285    // this constructor is allowed only on the controller side.
3286
this.connection = null;
3287  }
3288
3289  /**
3290   * Creates a new <code>DriverResultSet</code> object from information we get
3291   * back from a ControllerResultSet. Allowed only on the controller side.
3292   *
3293   * @param fields an array of <code>Field</code> objects (basically, the
3294   * <code>ResultSet</code> meta data)
3295   * @param resultData ArrayList of the actual data. Cannot be null.
3296   * @param crsHasMoreData true if remote ControllerResultSet has more data to
3297   * fetch
3298   * @param cursorName cursor name for a streamable ResultSet
3299   * @throws IllegalArgumentException if resultData argument is null
3300   */

3301  public DriverResultSet(Field[] fields, ArrayList JavaDoc resultData,
3302      boolean crsHasMoreData, String JavaDoc cursorName)
3303      throws IllegalArgumentException JavaDoc
3304  {
3305    this(fields, resultData);
3306    this.cursorName = cursorName;
3307    hasMoreData = crsHasMoreData;
3308  }
3309
3310  /**
3311   * Creates a new <code>DriverResultSet</code> object, deserializing it from
3312   * an input stream. Has to mirror the serialization method below.
3313   *
3314   * @param conn the connection we read from and belong to
3315   * @throws IOException if a network problem occurs
3316   * @throws ProtocolException if a protocol error occurs
3317   */

3318
3319  public DriverResultSet(Connection conn) throws IOException JavaDoc, ProtocolException
3320  {
3321    this.connection = conn;
3322    CJDBCInputStream input = this.connection.socketInput;
3323    // Get the ResultSet metadata, deserialize columns information
3324
this.nbOfColumns = input.readInt();
3325    this.fields = new Field[nbOfColumns];
3326    for (int f = 0; f < this.nbOfColumns; f++)
3327      this.fields[f] = new Field(input);
3328
3329    if (!TypeTag.COL_TYPES.equals(new TypeTag(input)))
3330      throw new ProtocolException("Column types were expected");
3331
3332    this.nbOfRows = input.readInt();
3333
3334    // Receive java types
3335
if (this.nbOfRows > 0)
3336    {
3337      this.serializers = new SQLDataSerialization.Serializer[nbOfColumns];
3338      for (int col = 0; col < this.nbOfColumns; col++)
3339      {
3340        TypeTag tag = new TypeTag(input);
3341        try
3342        {
3343          serializers[col] = SQLDataSerialization.getSerializer(tag);
3344        }
3345        catch (NotImplementedException nie)
3346        {
3347          // since we passed a TypeTag it's really impossible to come here
3348
IllegalArgumentException JavaDoc ipe = new IllegalArgumentException JavaDoc(
3349              "Really incredible bug, TypeTag was: " + tag);
3350          ipe.initCause(nie);
3351          throw ipe;
3352        }
3353        catch (IllegalArgumentException JavaDoc iae)
3354        {
3355          ProtocolException pe = new ProtocolException(
3356              "Protocol corruption: received unknown TypeTag " + tag
3357                  + " for column " + col);
3358          pe.initCause(iae);
3359          throw pe;
3360        }
3361      }
3362    }
3363
3364    receiveRows(input);
3365
3366    if (this.hasMoreData)
3367      this.cursorName = input.readUTF();
3368
3369    this.isClosed = false;
3370
3371  }
3372
3373  /**
3374   * Serialize the <code>DriverResultSet</code> on the output stream by
3375   * sending only the needed parameters to reconstruct it on the driver. Has to
3376   * mirror the deserialization method above.
3377   *
3378   * @param output destination stream
3379   * @throws IOException if a network error occurs
3380   */

3381
3382  public void sendToStream(
3383      org.objectweb.cjdbc.common.stream.CJDBCOutputStream output)
3384      throws IOException JavaDoc
3385  {
3386    // serialize columns information
3387
output.writeInt(this.nbOfColumns);
3388    for (int f = 0; f < this.nbOfColumns; f++)
3389      this.fields[f].sendToStream(output);
3390
3391    TypeTag.COL_TYPES.sendToStream(output);
3392    output.writeInt(this.nbOfRows);
3393
3394    // Send Java columns type. We need to do it only once: not for every row!
3395
if (this.nbOfRows > 0)
3396    {
3397      initSerializers();
3398
3399      for (int col = 0; col < this.nbOfColumns; col++)
3400        serializers[col].getTypeTag().sendToStream(output);
3401    }
3402
3403    // Finally send the actual data
3404
sendRowsToStream(output);
3405
3406    if (this.hasMoreData)
3407    { // Send the cursor name for further references
3408
output.writeUTF(this.cursorName);
3409    }
3410    output.flush();
3411  }
3412
3413  /**
3414   * De-serialize only data rows, not any metadata. Useful for streaming.
3415   *
3416   * @param input the stream to read from
3417   * @throws IOException stream error
3418   * @throws ProtocolException protocol corruption
3419   */

3420
3421  void receiveRows(CJDBCInputStream input) throws IOException JavaDoc,
3422      ProtocolException
3423  {
3424
3425    this.nbOfRows = input.readInt();
3426
3427    boolean[] nulls = new boolean[this.nbOfColumns];
3428
3429    // Receive the actual data
3430
this.data = new ArrayList JavaDoc(this.nbOfRows);
3431
3432    for (int r = 0; r < this.nbOfRows; r++)
3433    {
3434      if (!TypeTag.ROW.equals(new TypeTag(input)))
3435        throw new ProtocolException("A row was expected");
3436
3437      // First let's flag null values using a burst of booleans
3438
// TODO: we should compress this
3439
for (int col = 0; col < nbOfColumns; col++)
3440        nulls[col] = input.readBoolean();
3441
3442      Object JavaDoc[] row = new Object JavaDoc[this.nbOfColumns];
3443
3444      /**
3445       * Here we are sure that serializers are initialized because
3446       *
3447       * @see #sendRowsToStream(CJDBCOutputStream) just below.
3448       */

3449      for (int col = 0; col < this.nbOfColumns; col++)
3450        if (nulls[col])
3451          row[col] = null;
3452        else
3453          row[col] = serializers[col].receiveFromStream(input);
3454
3455      this.data.add(row);
3456    }
3457
3458    this.hasMoreData = input.readBoolean();
3459  }
3460
3461  /**
3462   * Serialize only rows, not any metadata. Useful for streaming. Called by the
3463   * controller side.
3464   *
3465   * @param output destination stream
3466   * @throws IOException on stream error
3467   */

3468  public void sendRowsToStream(CJDBCOutputStream output) throws IOException JavaDoc
3469  {
3470
3471    output.writeInt(this.nbOfRows);
3472
3473    boolean[] nulls = new boolean[nbOfColumns];
3474
3475    Iterator JavaDoc rowsIter = this.data.iterator();
3476    while (rowsIter.hasNext())
3477    {
3478      Object JavaDoc[] row = (Object JavaDoc[]) rowsIter.next();
3479      TypeTag.ROW.sendToStream(output);
3480
3481      // first flag null values
3482
for (int col = 0; col < row.length; col++)
3483      {
3484        if (null == row[col])
3485          nulls[col] = true;
3486        else
3487          nulls[col] = false;
3488        // we should compress this
3489
output.writeBoolean(nulls[col]);
3490      }
3491
3492      for (int col = 0; col < row.length; col++)
3493        if (!nulls[col]) // send only non-nulls
3494
{
3495          try
3496          {
3497            /**
3498             * Here we are sure that serializers are initialized because:
3499             * <p>
3500             * (1) we went through
3501             * {@link #sendToStream(CJDBCOutputStream)} at least once before
3502             * <p>
3503             * (2) and there was a non-zero ResultSet transfered, else we would
3504             * not come here again.
3505             */

3506            serializers[col].sendToStream(row[col], output);
3507          }
3508          catch (ClassCastException JavaDoc cce1)
3509          {
3510            ClassCastException JavaDoc cce2 = new ClassCastException JavaDoc("Serializer "
3511                + serializers[col] + " failed on Java object: " + row[col]
3512                + " found in column: " + col + ", because of unexpected type "
3513                + row[col].getClass().getName());
3514            cce2.initCause(cce1);
3515            throw cce2;
3516          }
3517        } // if !null
3518

3519    } // while (rows)
3520

3521    output.writeBoolean(this.hasMoreData);
3522    output.flush();
3523  }
3524
3525  /**
3526   * Set the statement.
3527   *
3528   * @param stmt The statement to set
3529   * @throws SQLException if an error occurs
3530   */

3531  protected void setStatement(Statement stmt) throws SQLException JavaDoc
3532  {
3533    owningStatement = stmt;
3534    fetchSize = stmt.getFetchSize();
3535    resultSetConcurrency = stmt.getResultSetConcurrency();
3536    resultSetType = stmt.getResultSetType();
3537  }
3538
3539  /**
3540   * Builds a hash between column names and their indices for fast retrieval.
3541   */

3542  private void buildIndexMapping()
3543  {
3544    int numFields = nbOfColumns;
3545
3546    columnNameToIndex = new Hashtable JavaDoc();
3547    fullColumnNameToIndex = new Hashtable JavaDoc();
3548
3549    for (int i = 0; i < numFields; i++)
3550    {
3551      Integer JavaDoc index = new Integer JavaDoc(i);
3552
3553      String JavaDoc columnName = fields[i].getFieldName();
3554      String JavaDoc fullColumnName = fields[i].getFullName();
3555      if (columnName != null)
3556      {
3557        columnNameToIndex.put(fields[i].getFieldName(), index);
3558        columnNameToIndex.put(fields[i].getFieldName().toUpperCase(), index);
3559        columnNameToIndex.put(fields[i].getFieldName().toLowerCase(), index);
3560      }
3561
3562      if (fullColumnName != null)
3563      {
3564        fullColumnNameToIndex.put(fields[i].getFullName(), index);
3565        fullColumnNameToIndex.put(fields[i].getFullName().toUpperCase(), index);
3566        fullColumnNameToIndex.put(fields[i].getFullName().toLowerCase(), index);
3567      }
3568    }
3569  }
3570
3571  /**
3572   * Builds a delete statement for deleting rows with Updatable ResultSets
3573   *
3574   * @throws SQLException
3575   */

3576  private void buildDeleteStatement() throws SQLException JavaDoc
3577  {
3578    // Check that ResultSet can be updated
3579
this.checkUpdatability();
3580
3581    // Build delete statement for this ResultSet
3582
StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
3583    sb.append("DELETE FROM ");
3584    sb.append(fields[0].getTableName());
3585    sb.append(" WHERE ");
3586    for (int i = 0; i < primaryKeyColumns.length; ++i)
3587    {
3588      if (i > 0)
3589        sb.append(" AND ");
3590      sb.append(primaryKeyColumns[i]);
3591      sb.append(" = ?");
3592    }
3593
3594    // set delete statement
3595
deleteStatement = this.connection.prepareStatement(sb.toString());
3596  }
3597
3598  /**
3599   * Builds a insert statement for inserting rows with Updatable ResultSets
3600   *
3601   * @throws SQLException
3602   */

3603  private void buildInsertStatement() throws SQLException JavaDoc
3604  {
3605    // Check that ResultSet can be updated
3606
this.checkUpdatability();
3607
3608    // Build insert statement for this ResultSet
3609
StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
3610    sb.append("INSERT INTO ");
3611    sb.append(fields[0].getTableName());
3612    sb.append(" (");
3613    for (int i = 0; i < fields.length; ++i)
3614    {
3615      if (i > 0)
3616        sb.append(", ");
3617      sb.append(fields[i].getFieldName());
3618    }
3619    sb.append(") VALUES (");
3620    for (int i = 0; i < fields.length; ++i)
3621    {
3622      if (i > 0)
3623        sb.append(", ");
3624      sb.append("?");
3625    }
3626    sb.append(")");
3627
3628    // set insert statement
3629
insertStatement = this.connection.prepareStatement(sb.toString());
3630  }
3631
3632  /**
3633   * Builds a select statement for refreshing rows in Updatable ResultSets
3634   *
3635   * @throws SQLException
3636   */

3637  private void buildRefreshStatement() throws SQLException JavaDoc
3638  {
3639    // Check that ResultSet can be updated
3640
this.checkUpdatability();
3641
3642    // Build refresh statement for this ResultSet
3643
StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
3644    sb.append("SELECT ");
3645    for (int i = 0; i < fields.length; ++i)
3646    {
3647      if (i > 0)
3648        sb.append(", ");
3649      sb.append(fields[i].getFieldName());
3650    }
3651    sb.append(" FROM ");
3652    sb.append(fields[0].getTableName());
3653    sb.append(" WHERE ");
3654    for (int i = 0; i < primaryKeyColumns.length; ++i)
3655    {
3656      if (i > 0)
3657        sb.append(" AND ");
3658      sb.append(primaryKeyColumns[i]);
3659      sb.append(" = ?");
3660    }
3661
3662    // set refresh statement
3663
refreshStatement = this.connection.prepareStatement(sb.toString());
3664  }
3665
3666  /**
3667   * Builds an update statement for updating rows with Updatable ResultSets
3668   *
3669   * @throws SQLException
3670   */

3671  private void buildUpdateStatement() throws SQLException JavaDoc
3672  {
3673    // Check that ResultSet can be updated
3674
this.checkUpdatability();
3675
3676    // Build update statement for this ResultSet
3677
StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
3678    sb.append("UPDATE ");
3679    sb.append(fields[0].getTableName());
3680    sb.append(" SET ");
3681    for (int i = 0; i < fields.length; ++i)
3682    {
3683      if (i > 0)
3684        sb.append(", ");
3685      sb.append(fields[i].getFieldName());
3686      sb.append(" = ?");
3687    }
3688    sb.append(" WHERE ");
3689    for (int i = 0; i < primaryKeyColumns.length; ++i)
3690    {
3691      if (i > 0)
3692        sb.append(" AND ");
3693      sb.append(primaryKeyColumns[i]);
3694      sb.append(" = ?");
3695    }
3696
3697    // set update statement
3698
updateStatement = this.connection.prepareStatement(sb.toString());
3699  }
3700
3701  /**
3702   * Retrieves the primary key for the table referenced by this ResultSet
3703   *
3704   * @throws SQLException
3705   */

3706  private void extractPrimaryKey() throws SQLException JavaDoc
3707  {
3708    ResultSet JavaDoc res = this.connection.getPrimaryKeys(null, null, fields[0].getTableName());
3709
3710    try
3711    {
3712      primaryKeyColumns = new String JavaDoc[((DriverResultSet) res).nbOfRows];
3713      while (res.next())
3714        primaryKeyColumns[res.getRow() - 1] = res.getString(4);
3715    }
3716    finally
3717    {
3718      // Clean up
3719
res.close();
3720    }
3721  }
3722
3723  /**
3724   * Basic checks for Updatable ResultSets
3725   *
3726   * @throws SQLException
3727   */

3728  private void checkUpdatability() throws SQLException JavaDoc
3729  {
3730    // Check ResultSet Concurrency type
3731
switch (resultSetConcurrency)
3732    {
3733      case ResultSet.CONCUR_READ_ONLY :
3734        throw new SQLException JavaDoc("Cannot update ResultSet with "
3735            + "concurrency mode CONCUR_READ_ONLY");
3736      case ResultSet.CONCUR_UPDATABLE :
3737        break;
3738      default :
3739        throw new SQLException JavaDoc("Invalid ResultSet concurrency mode: "
3740            + resultSetConcurrency);
3741    }
3742
3743    // Check that the query selects only one table
3744
String JavaDoc tableName = fields[0].getTableName();
3745    for (int i = 1; i < nbOfColumns; ++i)
3746      if (!tableName.equals(fields[i].getTableName()))
3747        throw new SQLException JavaDoc(UPDATEABLE_MESSAGE);
3748
3749    // Check if need to get primary keys
3750
if (primaryKeyColumns == null)
3751      this.extractPrimaryKey();
3752
3753    // Check that the query selects the full primary key
3754
for (int i = 0; i < primaryKeyColumns.length; ++i)
3755      try
3756      {
3757        findColumn(primaryKeyColumns[i]);
3758      }
3759      catch (SQLException JavaDoc e)
3760      {
3761        throw new SQLException JavaDoc(UPDATEABLE_MESSAGE);
3762      }
3763  }
3764
3765  /**
3766   * Sanity checks for result parsing
3767   *
3768   * @param columnIndex the column to check
3769   * @throws SQLException if an error occurs
3770   */

3771  private void checkRowAndColPosAndSetNullFlag(int columnIndex)
3772      throws SQLException JavaDoc
3773  {
3774    checkIfClosed();
3775
3776    if (!inserting)
3777      checkRowPos();
3778
3779    if (fields == null)
3780      throw new java.sql.SQLException JavaDoc("Query generated no fields for ResultSet");
3781
3782    if (columnIndex < 1 || columnIndex > nbOfColumns)
3783      throw new java.sql.SQLException JavaDoc("Column Index out of range ( "
3784          + columnIndex + " > " + nbOfColumns + ").");
3785
3786    try
3787    {
3788      Object JavaDoc obj;
3789      if (inserting || updating)
3790        obj = tempRow[columnIndex - 1];
3791      else
3792        obj = ((Object JavaDoc[]) data.get(currentRow))[columnIndex - 1];
3793
3794      if (obj == null)
3795        wasNullFlag = true;
3796      else
3797        wasNullFlag = false;
3798    }
3799    catch (NullPointerException JavaDoc e)
3800    {
3801      wasNullFlag = true;
3802    }
3803  }
3804
3805  /**
3806   * Checks that the cursor is on row in the ResultSet
3807   *
3808   * @throws SQLException
3809   */

3810  private void checkRowPos() throws SQLException JavaDoc
3811  {
3812    if (currentRow < 0)
3813      throw new SQLException JavaDoc("Before start of result set");
3814
3815    if (currentRow == nbOfRows)
3816      throw new SQLException JavaDoc("After end of result set");
3817  }
3818
3819  /**
3820   * Checks that the update flag is set when updating a row. The first time an
3821   * update is done on a row this method will prepare the ResultSet for update
3822   *
3823   * @throws SQLException
3824   */

3825  private void checkUpdateFlagAndPrepareUpdateIfNeeded() throws SQLException JavaDoc
3826  {
3827    if (updating)
3828      return;
3829
3830    this.checkRowPos();
3831
3832    if (updateStatement == null)
3833      this.buildUpdateStatement();
3834
3835    tempRow = (Object JavaDoc[]) ((Object JavaDoc[]) data.get(currentRow)).clone();
3836
3837    for (int i = 0; i < nbOfColumns; ++i)
3838      updateStatement.setObject(i + 1, tempRow[i]);
3839
3840    updating = true;
3841  }
3842
3843  /**
3844   * Check if the ResultSet if closed and throws a SQLException if so.
3845   *
3846   * @throws SQLException if the ResultSet is closed
3847   */

3848  private void checkIfClosed() throws SQLException JavaDoc
3849  {
3850    if (isClosed)
3851      throw new SQLException JavaDoc("Trying to access a closed ResultSet");
3852  }
3853
3854  // -------------------------- JDBC 3.0
3855
// ----------------------------------------
3856

3857  /**
3858   * Retrieves the value of the designated column in the current row of this
3859   * <code>ResultSet</code> object as a <code>java.net.URL</code> object in
3860   * the Java programming language.
3861   *
3862   * @param columnIndex the index of the column 1 is the first, 2 is the
3863   * second,...
3864   * @return the column value as a <code>java.net.URL</code> object; if the
3865   * value is SQL <code>NULL</code>, the value returned is
3866   * <code>null</code> in the Java programming language
3867   * @exception SQLException if a database access error occurs, or if a URL is
3868   * malformed
3869   * @since JDK 1.4
3870   */

3871  public java.net.URL JavaDoc getURL(int columnIndex) throws SQLException JavaDoc
3872  {
3873    checkRowAndColPosAndSetNullFlag(columnIndex);
3874
3875    if (wasNullFlag)
3876      return null;
3877
3878    if (inserting || updating)
3879      return (URL JavaDoc) tempRow[columnIndex - 1];
3880    else
3881      return (URL JavaDoc) (((Object JavaDoc[]) data.get(currentRow))[columnIndex - 1]);
3882  }
3883
3884  /**
3885   * Retrieves the value of the designated column in the current row of this
3886   * <code>ResultSet</code> object as a <code>java.net.URL</code> object in
3887   * the Java programming language.
3888   *
3889   * @param columnName the SQL name of the column
3890   * @return the column value as a <code>java.net.URL</code> object; if the
3891   * value is SQL <code>NULL</code>, the value returned is
3892   * <code>null</code> in the Java programming language
3893   * @exception SQLException if a database access error occurs or if a URL is
3894   * malformed
3895   * @since JDK 1.4
3896   */

3897  public java.net.URL JavaDoc getURL(String JavaDoc columnName) throws SQLException JavaDoc
3898  {
3899    return getURL(findColumn(columnName));
3900  }
3901
3902  /**
3903   * Updates the designated column with a <code>java.sql.Ref</code> value. The
3904   * updater methods are used to update column values in the current row or the
3905   * insert row. The updater methods do not update the underlying database;
3906   * instead the <code>updateRow</code> or <code>insertRow</code> methods
3907   * are called to update the database.
3908   *
3909   * @param columnIndex the first column is 1, the second is 2, ...
3910   * @param x the new column value
3911   * @exception SQLException if a database access error occurs
3912   * @since JDK 1.4
3913   */

3914  public void updateRef(int columnIndex, java.sql.Ref JavaDoc x) throws SQLException JavaDoc
3915  {
3916    throw new NotImplementedException("updateRef");
3917  }
3918
3919  /**
3920   * Updates the designated column with a <code>java.sql.Ref</code> value. The
3921   * updater methods are used to update column values in the current row or the
3922   * insert row. The updater methods do not update the underlying database;
3923   * instead the <code>updateRow</code> or <code>insertRow</code> methods
3924   * are called to update the database.
3925   *
3926   * @param columnName the name of the column
3927   * @param x the new column value
3928   * @exception SQLException if a database access error occurs
3929   * @since JDK 1.4
3930   */

3931  public void updateRef(String JavaDoc columnName, java.sql.Ref JavaDoc x) throws SQLException JavaDoc
3932  {
3933    updateRef(findColumn(columnName), x);
3934  }
3935
3936  /**
3937   * Updates the designated column with a <code>java.sql.Blob</code> value.
3938   * The updater methods are used to update column values in the current row or
3939   * the insert row. The updater methods do not update the underlying database;
3940   * instead the <code>updateRow</code> or <code>insertRow</code> methods
3941   * are called to update the database.
3942   *
3943   * @param columnIndex the first column is 1, the second is 2, ...
3944   * @param x the new column value
3945   * @exception SQLException if a database access error occurs
3946   * @since JDK 1.4
3947   */

3948  public void updateBlob(int columnIndex, java.sql.Blob JavaDoc x) throws SQLException JavaDoc
3949  {
3950    throw new NotImplementedException("updateBlob");
3951  }
3952
3953  /**
3954   * Updates the designated column with a <code>java.sql.Blob</code> value.
3955   * The updater methods are used to update column values in the current row or
3956   * the insert row. The updater methods do not update the underlying database;
3957   * instead the <code>updateRow</code> or <code>insertRow</code> methods
3958   * are called to update the database.
3959   *
3960   * @param columnName the name of the column
3961   * @param x the new column value
3962   * @exception SQLException if a database access error occurs
3963   * @since JDK 1.4
3964   */

3965  public void updateBlob(String JavaDoc columnName, java.sql.Blob JavaDoc x)
3966      throws SQLException JavaDoc
3967  {
3968    updateBlob(findColumn(columnName), x);
3969  }
3970
3971  /**
3972   * Updates the designated column with a <code>java.sql.Clob</code> value.
3973   * The updater methods are used to update column values in the current row or
3974   * the insert row. The updater methods do not update the underlying database;
3975   * instead the <code>updateRow</code> or <code>insertRow</code> methods
3976   * are called to update the database.
3977   *
3978   * @param columnIndex the first column is 1, the second is 2, ...
3979   * @param x the new column value
3980   * @exception SQLException if a database access error occurs
3981   * @since JDK 1.4
3982   */

3983  public void updateClob(int columnIndex, java.sql.Clob JavaDoc x) throws SQLException JavaDoc
3984  {
3985    throw new NotImplementedException("updateClob");
3986  }
3987
3988  /**
3989   * Updates the designated column with a <code>java.sql.Clob</code> value.
3990   * The updater methods are used to update column values in the current row or
3991   * the insert row. The updater methods do not update the underlying database;
3992   * instead the <code>updateRow</code> or <code>insertRow</code> methods
3993   * are called to update the database.
3994   *
3995   * @param columnName the name of the column
3996   * @param x the new column value
3997   * @exception SQLException if a database access error occurs
3998   * @since JDK 1.4
3999   */

4000  public void updateClob(String JavaDoc columnName, java.sql.Clob JavaDoc x)
4001      throws SQLException JavaDoc
4002  {
4003    updateClob(findColumn(columnName), x);
4004  }
4005
4006  /**
4007   * Updates the designated column with a <code>java.sql.Array</code> value.
4008   * The updater methods are used to update column values in the current row or
4009   * the insert row. The updater methods do not update the underlying database;
4010   * instead the <code>updateRow</code> or <code>insertRow</code> methods
4011   * are called to update the database.
4012   *
4013   * @param columnIndex the first column is 1, the second is 2, ...
4014   * @param x the new column value
4015   * @exception SQLException if a database access error occurs
4016   * @since JDK 1.4
4017   */

4018  public void updateArray(int columnIndex, java.sql.Array JavaDoc x)
4019      throws SQLException JavaDoc
4020  {
4021    throw new NotImplementedException("updateArray");
4022  }
4023
4024  /**
4025   * Updates the designated column with a <code>java.sql.Array</code> value.
4026   * The updater methods are used to update column values in the current row or
4027   * the insert row. The updater methods do not update the underlying database;
4028   * instead the <code>updateRow</code> or <code>insertRow</code> methods
4029   * are called to update the database.
4030   *
4031   * @param columnName the name of the column
4032   * @param x the new column value
4033   * @exception SQLException if a database access error occurs
4034   * @since JDK 1.4
4035   */

4036  public void updateArray(String JavaDoc columnName, java.sql.Array JavaDoc x)
4037      throws SQLException JavaDoc
4038  {
4039    updateArray(findColumn(columnName), x);
4040  }
4041
4042  /**
4043   * Get the value of a column in the current row as a Java byte.
4044   *
4045   * @param columnIndex the first column is 1, the second is 2,...
4046   * @return the column value; 0 if SQL NULL
4047   * @exception SQLException if a database access error occurs
4048   */

4049  public byte getByte(int columnIndex) throws SQLException JavaDoc
4050  {
4051    checkRowAndColPosAndSetNullFlag(columnIndex);
4052
4053    if (wasNullFlag)
4054      return 0;
4055
4056    Object JavaDoc obj;
4057    if (inserting || updating)
4058      obj = tempRow[columnIndex - 1];
4059    else
4060      obj = ((Object JavaDoc[]) data.get(currentRow))[columnIndex - 1];
4061
4062    if (obj instanceof Number JavaDoc)
4063    {
4064      return ((Number JavaDoc) obj).byteValue();
4065    }
4066
4067    // the object is not of type number we parse the string representation
4068
try
4069    {
4070      String JavaDoc string = obj.toString();
4071      string = string.trim();
4072      return Byte.parseByte(string);
4073    }
4074    catch (NumberFormatException JavaDoc e)
4075    {
4076      throw new SQLException JavaDoc("the value " + obj.toString()
4077          + " is not a valid byte");
4078    }
4079  }
4080
4081  /**
4082   * @see java.lang.Object#toString()
4083   */

4084  public String JavaDoc toString()
4085  {
4086    return nbOfRows + " rows - " + nbOfColumns + " columns - current row:"
4087        + currentRow + " - hasMoreData:" + hasMoreData + " - isClosed:"
4088        + isClosed;
4089  }
4090}
Popular Tags