History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/com/sun/rowset/CachedRowSetImpl.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/rowset/CachedRowSetImpl.java+10133−0
@@ -0,0 +1,10133 @@
1+/*
2+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package com.sun.rowset;
27+
28+import java.sql.*;
29+import javax.sql.*;
30+import java.io.*;
31+import java.math.*;
32+import java.util.*;
33+import java.text.*;
34+
35+import javax.sql.rowset.*;
36+import javax.sql.rowset.spi.*;
37+import javax.sql.rowset.serial.*;
38+import com.sun.rowset.internal.*;
39+import com.sun.rowset.providers.*;
40+
41+/**
42+ * The standard implementation of the <code>CachedRowSet</code> interface.
43+ *
44+ * See interface defintion for full behaviour and implementation requirements.
45+ * This reference implementation has made provision for a one-to-one write back
46+ * facility and it is curremtly be possible to change the peristence provider
47+ * during the life-time of any CachedRowSetImpl.
48+ *
49+ * @author Jonathan Bruce, Amit Handa
50+ */
51+
52+public class CachedRowSetImpl extends BaseRowSet implements RowSet, RowSetInternal, Serializable, Cloneable, CachedRowSet {
53+
54+ /**
55+ * The <code>SyncProvider</code> used by the CachedRowSet
56+ */
57+ private SyncProvider provider;
58+
59+ /**
60+ * The <code>RowSetReaderImpl</code> object that is the reader
61+ * for this rowset. The method <code>execute</code> uses this
62+ * reader as part of its implementation.
63+ * @serial
64+ */
65+ private RowSetReader rowSetReader;
66+
67+ /**
68+ * The <code>RowSetWriterImpl</code> object that is the writer
69+ * for this rowset. The method <code>acceptChanges</code> uses
70+ * this writer as part of its implementation.
71+ * @serial
72+ */
73+ private RowSetWriter rowSetWriter;
74+
75+ /**
76+ * The <code>Connection</code> object that connects with this
77+ * <code>CachedRowSetImpl</code> object's current underlying data source.
78+ */
79+ private transient Connection conn;
80+
81+ /**
82+ * The <code>ResultSetMetaData</code> object that contains information
83+ * about the columns in the <code>ResultSet</code> object that is the
84+ * current source of data for this <code>CachedRowSetImpl</code> object.
85+ */
86+ private transient ResultSetMetaData RSMD;
87+
88+ /**
89+ * The <code>RowSetMetaData</code> object that contains information about
90+ * the columns in this <code>CachedRowSetImpl</code> object.
91+ * @serial
92+ */
93+ private RowSetMetaDataImpl RowSetMD;
94+
95+ // Properties of this RowSet
96+
97+ /**
98+ * An array containing the columns in this <code>CachedRowSetImpl</code>
99+ * object that form a unique identifier for a row. This array
100+ * is used by the writer.
101+ * @serial
102+ */
103+ private int keyCols[];
104+
105+ /**
106+ * The name of the table in the underlying database to which updates
107+ * should be written. This name is needed because most drivers
108+ * do not return this information in a <code>ResultSetMetaData</code>
109+ * object.
110+ * @serial
111+ */
112+ private String tableName;
113+
114+ /**
115+ * A <code>Vector</code> object containing the <code>Row</code>
116+ * objects that comprise this <code>CachedRowSetImpl</code> object.
117+ * @serial
118+ */
119+ private Vector<Object> rvh;
120+
121+ /**
122+ * The current postion of the cursor in this <code>CachedRowSetImpl</code>
123+ * object.
124+ * @serial
125+ */
126+ private int cursorPos;
127+
128+ /**
129+ * The current postion of the cursor in this <code>CachedRowSetImpl</code>
130+ * object not counting rows that have been deleted, if any.
131+ * <P>
132+ * For example, suppose that the cursor is on the last row of a rowset
133+ * that started with five rows and subsequently had the second and third
134+ * rows deleted. The <code>absolutePos</code> would be <code>3</code>,
135+ * whereas the <code>cursorPos</code> would be <code>5</code>.
136+ * @serial
137+ */
138+ private int absolutePos;
139+
140+ /**
141+ * The number of deleted rows currently in this <code>CachedRowSetImpl</code>
142+ * object.
143+ * @serial
144+ */
145+ private int numDeleted;
146+
147+ /**
148+ * The total number of rows currently in this <code>CachedRowSetImpl</code>
149+ * object.
150+ * @serial
151+ */
152+ private int numRows;
153+
154+ /**
155+ * A special row used for constructing a new row. A new
156+ * row is constructed by using <code>ResultSet.updateXXX</code>
157+ * methods to insert column values into the insert row.
158+ * @serial
159+ */
160+ private InsertRow insertRow;
161+
162+ /**
163+ * A <code>boolean</code> indicating whether the cursor is
164+ * currently on the insert row.
165+ * @serial
166+ */
167+ private boolean onInsertRow;
168+
169+ /**
170+ * The field that temporarily holds the last position of the
171+ * cursor before it moved to the insert row, thus preserving
172+ * the number of the current row to which the cursor may return.
173+ * @serial
174+ */
175+ private int currentRow;
176+
177+ /**
178+ * A <code>boolean</code> indicating whether the last value
179+ * returned was an SQL <code>NULL</code>.
180+ * @serial
181+ */
182+ private boolean lastValueNull;
183+
184+ /**
185+ * A <code>SQLWarning</code> which logs on the warnings
186+ */
187+ private SQLWarning sqlwarn;
188+
189+ /**
190+ * Used to track match column for JoinRowSet consumption
191+ */
192+ private String strMatchColumn ="";
193+
194+ /**
195+ * Used to track match column for JoinRowSet consumption
196+ */
197+ private int iMatchColumn = -1;
198+
199+ /**
200+ * A <code>RowSetWarning</code> which logs on the warnings
201+ */
202+ private RowSetWarning rowsetWarning;
203+
204+ /**
205+ * The default SyncProvider for the RI CachedRowSetImpl
206+ */
207+ private String DEFAULT_SYNC_PROVIDER = "com.sun.rowset.providers.RIOptimisticProvider";
208+
209+ /**
210+ * The boolean variable indicating locatorsUpdateValue
211+ */
212+ private boolean dbmslocatorsUpdateCopy;
213+
214+ /**
215+ * The <code>ResultSet</code> object that is used to maintain the data when
216+ * a ResultSet and start position are passed as parameters to the populate function
217+ */
218+ private transient ResultSet resultSet;
219+
220+ /**
221+ * The integer value indicating the end position in the ResultSetwhere the picking
222+ * up of rows for populating a CachedRowSet object was left off.
223+ */
224+ private int endPos;
225+
226+ /**
227+ * The integer value indicating the end position in the ResultSetwhere the picking
228+ * up of rows for populating a CachedRowSet object was left off.
229+ */
230+ private int prevEndPos;
231+
232+ /**
233+ * The integer value indicating the position in the ResultSet, to populate the
234+ * CachedRowSet object.
235+ */
236+ private int startPos;
237+
238+ /**
239+ * The integer value indicating the positon from where the page prior to this
240+ * was populated.
241+ */
242+ private int startPrev;
243+
244+ /**
245+ * The integer value indicating size of the page.
246+ */
247+ private int pageSize;
248+
249+ /**
250+ * The integer value indicating number of rows that have been processed so far.
251+ * Used for checking whether maxRows has been reached or not.
252+ */
253+ private int maxRowsreached;
254+ /**
255+ * The boolean value when true signifies that pages are still to follow and a
256+ * false value indicates that this is the last page.
257+ */
258+ private boolean pagenotend = true;
259+
260+ /**
261+ * The boolean value indicating whether this is the first page or not.
262+ */
263+ private boolean onFirstPage;
264+
265+ /**
266+ * The boolean value indicating whether this is the last page or not.
267+ */
268+ private boolean onLastPage;
269+
270+ /**
271+ * The integer value indicating how many times the populate function has been called.
272+ */
273+ private int populatecallcount;
274+
275+ /**
276+ * The integer value indicating the total number of rows to be processed in the
277+ * ResultSet object passed to the populate function.
278+ */
279+ private int totalRows;
280+
281+ /**
282+ * The boolean value indicating how the CahedRowSet object has been populated for
283+ * paging purpose. True indicates that connection parameter is passed.
284+ */
285+ private boolean callWithCon;
286+
287+ /**
288+ * CachedRowSet reader object to read the data from the ResultSet when a connection
289+ * parameter is passed to populate the CachedRowSet object for paging.
290+ */
291+ private CachedRowSetReader crsReader;
292+
293+ /**
294+ * The Vector holding the Match Columns
295+ */
296+ private Vector<Integer> iMatchColumns;
297+
298+ /**
299+ * The Vector that will hold the Match Column names.
300+ */
301+ private Vector<String> strMatchColumns;
302+
303+ /**
304+ * Trigger that indicates whether the active SyncProvider is exposes the
305+ * additional TransactionalWriter method
306+ */
307+ private boolean tXWriter = false;
308+
309+ /**
310+ * The field object for a transactional RowSet writer
311+ */
312+ private TransactionalWriter tWriter = null;
313+
314+ protected transient JdbcRowSetResourceBundle resBundle;
315+
316+ private boolean updateOnInsert;
317+
318+
319+
320+ /**
321+ * Constructs a new default <code>CachedRowSetImpl</code> object with
322+ * the capacity to hold 100 rows. This new object has no metadata
323+ * and has the following default values:
324+ * <pre>
325+ * onInsertRow = false
326+ * insertRow = null
327+ * cursorPos = 0
328+ * numRows = 0
329+ * showDeleted = false
330+ * queryTimeout = 0
331+ * maxRows = 0
332+ * maxFieldSize = 0
333+ * rowSetType = ResultSet.TYPE_SCROLL_INSENSITIVE
334+ * concurrency = ResultSet.CONCUR_UPDATABLE
335+ * readOnly = false
336+ * isolation = Connection.TRANSACTION_READ_COMMITTED
337+ * escapeProcessing = true
338+ * onInsertRow = false
339+ * insertRow = null
340+ * cursorPos = 0
341+ * absolutePos = 0
342+ * numRows = 0
343+ * </pre>
344+ * A <code>CachedRowSetImpl</code> object is configured to use the default
345+ * <code>RIOptimisticProvider</code> implementation to provide connectivity
346+ * and synchronization capabilities to the set data source.
347+ * <P>
348+ * @throws SQLException if an error occurs
349+ */
350+ public CachedRowSetImpl() throws SQLException {
351+
352+ try {
353+ resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
354+ } catch(IOException ioe) {
355+ throw new RuntimeException(ioe);
356+ }
357+
358+ // set the Reader, this maybe overridden latter
359+ provider =
360+ (SyncProvider)SyncFactory.getInstance(DEFAULT_SYNC_PROVIDER);
361+
362+ if (!(provider instanceof RIOptimisticProvider)) {
363+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.invalidp").toString());
364+ }
365+
366+ rowSetReader = (CachedRowSetReader)provider.getRowSetReader();
367+ rowSetWriter = (CachedRowSetWriter)provider.getRowSetWriter();
368+
369+ // allocate the parameters collection
370+ initParams();
371+
372+ initContainer();
373+
374+ // set up some default values
375+ initProperties();
376+
377+ // insert row setup
378+ onInsertRow = false;
379+ insertRow = null;
380+
381+ // set the warninings
382+ sqlwarn = new SQLWarning();
383+ rowsetWarning = new RowSetWarning();
384+
385+ }
386+
387+ /**
388+ * Provides a <code>CachedRowSetImpl</code> instance with the same default properties as
389+ * as the zero parameter constructor.
390+ * <pre>
391+ * onInsertRow = false
392+ * insertRow = null
393+ * cursorPos = 0
394+ * numRows = 0
395+ * showDeleted = false
396+ * queryTimeout = 0
397+ * maxRows = 0
398+ * maxFieldSize = 0
399+ * rowSetType = ResultSet.TYPE_SCROLL_INSENSITIVE
400+ * concurrency = ResultSet.CONCUR_UPDATABLE
401+ * readOnly = false
402+ * isolation = Connection.TRANSACTION_READ_COMMITTED
403+ * escapeProcessing = true
404+ * onInsertRow = false
405+ * insertRow = null
406+ * cursorPos = 0
407+ * absolutePos = 0
408+ * numRows = 0
409+ * </pre>
410+ *
411+ * However, applications will have the means to specify at runtime the
412+ * desired <code>SyncProvider</code> object.
413+ * <p>
414+ * For example, creating a <code>CachedRowSetImpl</code> object as follows ensures
415+ * that a it is established with the <code>com.foo.provider.Impl</code> synchronization
416+ * implementation providing the synchronization mechanism for this disconnected
417+ * <code>RowSet</code> object.
418+ * <pre>
419+ * Hashtable env = new Hashtable();
420+ * env.put(javax.sql.rowset.spi.SyncFactory.ROWSET_PROVIDER_NAME,
421+ * "com.foo.provider.Impl");
422+ * CachedRowSetImpl crs = new CachedRowSet(env);
423+ * </pre>
424+ * <p>
425+ * Calling this constructor with a <code>null</code> parameter will
426+ * cause the <code>SyncFactory</code> to provide the reference
427+ * optimistic provider <code>com.sun.rowset.providers.RIOptimisticProvider</code>.
428+ * <p>
429+ * In addition, the following properties can be associated with the
430+ * provider to assist in determining the choice of the synchronizaton
431+ * provider such as:
432+ * <ul>
433+ * <li><code>ROWSET_SYNC_PROVIDER</code> - the property specifying the the
434+ * <code>SyncProvider</code> class name to be instantiated by the
435+ * <code>SyncFacttory</code>
436+ * <li><code>ROWSET_SYNC_VENDOR</code> - the property specifying the software
437+ * vendor associated with a <code>SyncProvider</code> implementation.
438+ * <li><code>ROWSET_SYNC_PROVIDER_VER</code> - the property specifying the
439+ * version of the <code>SyncProvider</code> implementation provided by the
440+ * software vendor.
441+ * </ul>
442+ * More specific detailes are available in the <code>SyncFactory</code>
443+ * and <code>SyncProvider</code> specificiations later in this document.
444+ * <p>
445+ * @param env a <code>Hashtable</code> object with a list of desired
446+ * synchronization providers
447+ * @throws SQLException if the requested provider cannot be found by the
448+ * synchonization factory
449+ * @see SyncProvider
450+ */
451+
452+ public CachedRowSetImpl(Hashtable env) throws SQLException {
453+
454+
455+ try {
456+ resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
457+ } catch(IOException ioe) {
458+ throw new RuntimeException(ioe);
459+ }
460+
461+ if (env == null) {
462+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.nullhash").toString());
463+ }
464+
465+ String providerName = (String)env.get(
466+ javax.sql.rowset.spi.SyncFactory.ROWSET_SYNC_PROVIDER);
467+
468+ // set the Reader, this maybe overridden latter
469+ provider =
470+ (SyncProvider)SyncFactory.getInstance(providerName);
471+
472+ rowSetReader = provider.getRowSetReader();
473+ rowSetWriter = provider.getRowSetWriter();
474+
475+ initParams(); // allocate the parameters collection
476+ initContainer();
477+ initProperties(); // set up some default values
478+ }
479+
480+ /**
481+ * Sets the <code>rvh</code> field to a new <code>Vector</code>
482+ * object with a capacity of 100 and sets the
483+ * <code>cursorPos</code> and <code>numRows</code> fields to zero.
484+ */
485+ private void initContainer() {
486+
487+ rvh = new Vector<Object>(100);
488+ cursorPos = 0;
489+ absolutePos = 0;
490+ numRows = 0;
491+ numDeleted = 0;
492+ }
493+
494+ /**
495+ * Sets the properties for this <code>CachedRowSetImpl</code> object to
496+ * their default values. This method is called internally by the
497+ * default constructor.
498+ */
499+
500+ private void initProperties() throws SQLException {
501+
502+ if(resBundle == null) {
503+ try {
504+ resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
505+ } catch(IOException ioe) {
506+ throw new RuntimeException(ioe);
507+ }
508+ }
509+ setShowDeleted(false);
510+ setQueryTimeout(0);
511+ setMaxRows(0);
512+ setMaxFieldSize(0);
513+ setType(ResultSet.TYPE_SCROLL_INSENSITIVE);
514+ setConcurrency(ResultSet.CONCUR_UPDATABLE);
515+ if((rvh.size() > 0) && (isReadOnly() == false))
516+ setReadOnly(false);
517+ else
518+ setReadOnly(true);
519+ setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
520+ setEscapeProcessing(true);
521+ //setTypeMap(null);
522+ checkTransactionalWriter();
523+
524+ //Instantiating the vector for MatchColumns
525+
526+ iMatchColumns = new Vector<Integer>(10);
527+ for(int i = 0; i < 10 ; i++) {
528+ iMatchColumns.add(i,Integer.valueOf(-1));
529+ }
530+
531+ strMatchColumns = new Vector<String>(10);
532+ for(int j = 0; j < 10; j++) {
533+ strMatchColumns.add(j,null);
534+ }
535+ }
536+
537+ /**
538+ * Determine whether the SyncProvider's writer implements the
539+ * <code>TransactionalWriter<code> interface
540+ */
541+ private void checkTransactionalWriter() {
542+ if (rowSetWriter != null) {
543+ Class c = rowSetWriter.getClass();
544+ if (c != null) {
545+ Class[] theInterfaces = c.getInterfaces();
546+ for (int i = 0; i < theInterfaces.length; i++) {
547+ if ((theInterfaces[i].getName()).indexOf("TransactionalWriter") > 0) {
548+ tXWriter = true;
549+ establishTransactionalWriter();
550+ }
551+ }
552+ }
553+ }
554+ }
555+
556+ /**
557+ * Sets an private field to all transaction bounddaries to be set
558+ */
559+ private void establishTransactionalWriter() {
560+ tWriter = (TransactionalWriter)provider.getRowSetWriter();
561+ }
562+
563+ //-----------------------------------------------------------------------
564+ // Properties
565+ //-----------------------------------------------------------------------
566+
567+ /**
568+ * Sets this <code>CachedRowSetImpl</code> object's command property
569+ * to the given <code>String</code> object and clears the parameters,
570+ * if any, that were set for the previous command.
571+ * <P>
572+ * The command property may not be needed
573+ * if the rowset is produced by a data source, such as a spreadsheet,
574+ * that does not support commands. Thus, this property is optional
575+ * and may be <code>null</code>.
576+ *
577+ * @param cmd a <code>String</code> object containing an SQL query
578+ * that will be set as the command; may be <code>null</code>
579+ * @throws SQLException if an error occurs
580+ */
581+ public void setCommand(String cmd) throws SQLException {
582+
583+ super.setCommand(cmd);
584+
585+ if(!buildTableName(cmd).equals("")) {
586+ this.setTableName(buildTableName(cmd));
587+ }
588+ }
589+
590+
591+ //---------------------------------------------------------------------
592+ // Reading and writing data
593+ //---------------------------------------------------------------------
594+
595+ /**
596+ * Populates this <code>CachedRowSetImpl</code> object with data from
597+ * the given <code>ResultSet</code> object. This
598+ * method is an alternative to the method <code>execute</code>
599+ * for filling the rowset with data. The method <code>populate</code>
600+ * does not require that the properties needed by the method
601+ * <code>execute</code>, such as the <code>command</code> property,
602+ * be set. This is true because the method <code>populate</code>
603+ * is given the <code>ResultSet</code> object from
604+ * which to get data and thus does not need to use the properties
605+ * required for setting up a connection and executing this
606+ * <code>CachedRowSetImpl</code> object's command.
607+ * <P>
608+ * After populating this rowset with data, the method
609+ * <code>populate</code> sets the rowset's metadata and
610+ * then sends a <code>RowSetChangedEvent</code> object
611+ * to all registered listeners prior to returning.
612+ *
613+ * @param data the <code>ResultSet</code> object containing the data
614+ * to be read into this <code>CachedRowSetImpl</code> object
615+ * @throws SQLException if an error occurs; or the max row setting is
616+ * violated while populating the RowSet
617+ * @see #execute
618+ */
619+
620+ public void populate(ResultSet data) throws SQLException {
621+ int rowsFetched;
622+ Row currentRow;
623+ int numCols;
624+ int i;
625+ Map<String, Class<?>> map = getTypeMap();
626+ Object obj;
627+ int mRows;
628+
629+ if (data == null) {
630+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.populate").toString());
631+ }
632+ this.resultSet = data;
633+
634+ // get the meta data for this ResultSet
635+ RSMD = data.getMetaData();
636+
637+ // set up the metadata
638+ RowSetMD = new RowSetMetaDataImpl();
639+ initMetaData(RowSetMD, RSMD);
640+
641+ // release the meta-data so that aren't tempted to use it.
642+ RSMD = null;
643+ numCols = RowSetMD.getColumnCount();
644+ mRows = this.getMaxRows();
645+ rowsFetched = 0;
646+ currentRow = null;
647+
648+ while ( data.next()) {
649+
650+ currentRow = new Row(numCols);
651+
652+ if ( rowsFetched > mRows && mRows > 0) {
653+ rowsetWarning.setNextWarning(new RowSetWarning("Populating rows "
654+ + "setting has exceeded max row setting"));
655+ }
656+ for ( i = 1; i <= numCols; i++) {
657+ /*
658+ * check if the user has set a map. If no map
659+ * is set then use plain getObject. This lets
660+ * us work with drivers that do not support
661+ * getObject with a map in fairly sensible way
662+ */
663+ if (map == null) {
664+ obj = data.getObject(i);
665+ } else {
666+ obj = data.getObject(i, map);
667+ }
668+ /*
669+ * the following block checks for the various
670+ * types that we have to serialize in order to
671+ * store - right now only structs have been tested
672+ */
673+ if (obj instanceof Struct) {
674+ obj = new SerialStruct((Struct)obj, map);
675+ } else if (obj instanceof SQLData) {
676+ obj = new SerialStruct((SQLData)obj, map);
677+ } else if (obj instanceof Blob) {
678+ obj = new SerialBlob((Blob)obj);
679+ } else if (obj instanceof Clob) {
680+ obj = new SerialClob((Clob)obj);
681+ } else if (obj instanceof java.sql.Array) {
682+ if(map != null)
683+ obj = new SerialArray((java.sql.Array)obj, map);
684+ else
685+ obj = new SerialArray((java.sql.Array)obj);
686+ }
687+
688+ ((Row)currentRow).initColumnObject(i, obj);
689+ }
690+ rowsFetched++;
691+ rvh.add(currentRow);
692+ }
693+
694+ numRows = rowsFetched ;
695+ // Also rowsFetched should be equal to rvh.size()
696+
697+ // notify any listeners that the rowset has changed
698+ notifyRowSetChanged();
699+
700+
701+ }
702+
703+ /**
704+ * Initializes the given <code>RowSetMetaData</code> object with the values
705+ * in the given <code>ResultSetMetaData</code> object.
706+ *
707+ * @param md the <code>RowSetMetaData</code> object for this
708+ * <code>CachedRowSetImpl</code> object, which will be set with
709+ * values from rsmd
710+ * @param rsmd the <code>ResultSetMetaData</code> object from which new
711+ * values for md will be read
712+ * @throws SQLException if an error occurs
713+ */
714+ private void initMetaData(RowSetMetaDataImpl md, ResultSetMetaData rsmd) throws SQLException {
715+ int numCols = rsmd.getColumnCount();
716+
717+ md.setColumnCount(numCols);
718+ for (int col=1; col <= numCols; col++) {
719+ md.setAutoIncrement(col, rsmd.isAutoIncrement(col));
720+ if(rsmd.isAutoIncrement(col))
721+ updateOnInsert = true;
722+ md.setCaseSensitive(col, rsmd.isCaseSensitive(col));
723+ md.setCurrency(col, rsmd.isCurrency(col));
724+ md.setNullable(col, rsmd.isNullable(col));
725+ md.setSigned(col, rsmd.isSigned(col));
726+ md.setSearchable(col, rsmd.isSearchable(col));
727+ /*
728+ * The PostgreSQL drivers sometimes return negative columnDisplaySize,
729+ * which causes an exception to be thrown. Check for it.
730+ */
731+ int size = rsmd.getColumnDisplaySize(col);
732+ if (size < 0) {
733+ size = 0;
734+ }
735+ md.setColumnDisplaySize(col, size);
736+ md.setColumnLabel(col, rsmd.getColumnLabel(col));
737+ md.setColumnName(col, rsmd.getColumnName(col));
738+ md.setSchemaName(col, rsmd.getSchemaName(col));
739+ /*
740+ * Drivers return some strange values for precision, for non-numeric data, including reports of
741+ * non-integer values; maybe we should check type, & set to 0 for non-numeric types.
742+ */
743+ int precision = rsmd.getPrecision(col);
744+ if (precision < 0) {
745+ precision = 0;
746+ }
747+ md.setPrecision(col, precision);
748+
749+ /*
750+ * It seems, from a bug report, that a driver can sometimes return a negative
751+ * value for scale. javax.sql.rowset.RowSetMetaDataImpl will throw an exception
752+ * if we attempt to set a negative value. As such, we'll check for this case.
753+ */
754+ int scale = rsmd.getScale(col);
755+ if (scale < 0) {
756+ scale = 0;
757+ }
758+ md.setScale(col, scale);
759+ md.setTableName(col, rsmd.getTableName(col));
760+ md.setCatalogName(col, rsmd.getCatalogName(col));
761+ md.setColumnType(col, rsmd.getColumnType(col));
762+ md.setColumnTypeName(col, rsmd.getColumnTypeName(col));
763+ }
764+
765+ if( conn != null){
766+ // JDBC 4.0 mandates as does the Java EE spec that all DataBaseMetaData methods
767+ // must be implemented, therefore, the previous fix for 5055528 is being backed out
768+ dbmslocatorsUpdateCopy = conn.getMetaData().locatorsUpdateCopy();
769+ }
770+ }
771+
772+ /**
773+ * Populates this <code>CachedRowSetImpl</code> object with data,
774+ * using the given connection to produce the result set from
775+ * which data will be read. A second form of this method,
776+ * which takes no arguments, uses the values from this rowset's
777+ * user, password, and either url or data source properties to
778+ * create a new database connection. The form of <code>execute</code>
779+ * that is given a connection ignores these properties.
780+ *
781+ * @param conn A standard JDBC <code>Connection</code> object that this
782+ * <code>CachedRowSet</code> object can pass to a synchronization provider
783+ * to establish a connection to the data source
784+ * @throws SQLException if an invalid <code>Connection</code> is supplied
785+ * or an error occurs in establishing the connection to the
786+ * data source
787+ * @see #populate
788+ * @see java.sql.Connection
789+ */
790+ public void execute(Connection conn) throws SQLException {
791+ // store the connection so the reader can find it.
792+ setConnection(conn);
793+
794+ if(getPageSize() != 0){
795+ crsReader = (CachedRowSetReader)provider.getRowSetReader();
796+ crsReader.setStartPosition(1);
797+ callWithCon = true;
798+ crsReader.readData((RowSetInternal)this);
799+ }
800+
801+ // Now call the current reader's readData method
802+ else {
803+ rowSetReader.readData((RowSetInternal)this);
804+ }
805+ RowSetMD = (RowSetMetaDataImpl)this.getMetaData();
806+
807+ if(conn != null){
808+ // JDBC 4.0 mandates as does the Java EE spec that all DataBaseMetaData methods
809+ // must be implemented, therefore, the previous fix for 5055528 is being backed out
810+ dbmslocatorsUpdateCopy = conn.getMetaData().locatorsUpdateCopy();
811+ }
812+
813+ }
814+
815+ /**
816+ * Sets this <code>CachedRowSetImpl</code> object's connection property
817+ * to the given <code>Connection</code> object. This method is called
818+ * internally by the version of the method <code>execute</code> that takes a
819+ * <code>Connection</code> object as an argument. The reader for this
820+ * <code>CachedRowSetImpl</code> object can retrieve the connection stored
821+ * in the rowset's connection property by calling its
822+ * <code>getConnection</code> method.
823+ *
824+ * @param connection the <code>Connection</code> object that was passed in
825+ * to the method <code>execute</code> and is to be stored
826+ * in this <code>CachedRowSetImpl</code> object's connection
827+ * property
828+ */
829+ private void setConnection (Connection connection) {
830+ conn = connection;
831+ }
832+
833+
834+ /**
835+ * Propagates all row update, insert, and delete changes to the
836+ * underlying data source backing this <code>CachedRowSetImpl</code>
837+ * object.
838+ * <P>
839+ * <b>Note</b>In the reference implementation an optimistic concurrency implementation
840+ * is provided as a sample implementation of a the <code>SyncProvider</code>
841+ * abstract class.
842+ * <P>
843+ * This method fails if any of the updates cannot be propagated back
844+ * to the data source. When it fails, the caller can assume that
845+ * none of the updates are reflected in the data source.
846+ * When an exception is thrown, the current row
847+ * is set to the first "updated" row that resulted in an exception
848+ * unless the row that caused the exception is a "deleted" row.
849+ * In that case, when deleted rows are not shown, which is usually true,
850+ * the current row is not affected.
851+ * <P>
852+ * If no <code>SyncProvider</code> is configured, the reference implementation
853+ * leverages the <code>RIOptimisticProvider</code> available which provides the
854+ * default and reference synchronization capabilities for disconnected
855+ * <code>RowSets</code>.
856+ *
857+ * @throws SQLException if the cursor is on the insert row or the underlying
858+ * reference synchronization provider fails to commit the updates
859+ * to the datasource
860+ * @throws SyncProviderException if an internal error occurs within the
861+ * <code>SyncProvider</code> instance during either during the
862+ * process or at any time when the <code>SyncProvider</code>
863+ * instance touches the data source.
864+ * @see #acceptChanges(java.sql.Connection)
865+ * @see javax.sql.RowSetWriter
866+ * @see javax.sql.rowset.spi.SyncProvider
867+ */
868+ public void acceptChanges() throws SyncProviderException {
869+ if (onInsertRow == true) {
870+ throw new SyncProviderException(resBundle.handleGetObject("cachedrowsetimpl.invalidop").toString());
871+ }
872+
873+ int saveCursorPos = cursorPos;
874+ boolean success = false;
875+ boolean conflict = false;
876+
877+ try {
878+ if (rowSetWriter != null) {
879+ saveCursorPos = cursorPos;
880+ conflict = rowSetWriter.writeData((RowSetInternal)this);
881+ cursorPos = saveCursorPos;
882+ }
883+
884+ if ((tXWriter) && this.COMMIT_ON_ACCEPT_CHANGES) {
885+ // do commit/rollback's here
886+ if (!conflict) {
887+ tWriter = (TransactionalWriter)rowSetWriter;
888+ tWriter.rollback();
889+ success = false;
890+ } else {
891+ tWriter = (TransactionalWriter)rowSetWriter;
892+ if (tWriter instanceof CachedRowSetWriter) {
893+ ((CachedRowSetWriter)tWriter).commit(this, updateOnInsert);
894+ } else {
895+ tWriter.commit();
896+ }
897+
898+ success = true;
899+ }
900+ }
901+
902+ if (success == true) {
903+ setOriginal();
904+ } else if (!(success) && !(this.COMMIT_ON_ACCEPT_CHANGES)) {
905+ throw new SyncProviderException(resBundle.handleGetObject("cachedrowsetimpl.accfailed").toString());
906+ }
907+
908+ } catch (SyncProviderException spe) {
909+ throw spe;
910+ } catch (SQLException e) {
911+ e.printStackTrace();
912+ throw new SyncProviderException(e.getMessage());
913+ } catch (SecurityException e) {
914+ throw new SyncProviderException(e.getMessage());
915+ }
916+ }
917+
918+ /**
919+ * Propagates all row update, insert, and delete changes to the
920+ * data source backing this <code>CachedRowSetImpl</code> object
921+ * using the given <code>Connection</code> object.
922+ * <P>
923+ * The reference implementation <code>RIOptimisticProvider</code>
924+ * modifies its synchronization to a write back function given
925+ * the updated connection
926+ * The reference implementation modifies its synchronization behaviour
927+ * via the <code>SyncProvider</code> to ensure the synchronization
928+ * occurs according to the updated JDBC <code>Connection</code>
929+ * properties.
930+ *
931+ * @param con a standard JDBC <code>Connection</code> object
932+ * @throws SQLException if the cursor is on the insert row or the underlying
933+ * synchronization provider fails to commit the updates
934+ * back to the data source
935+ * @see #acceptChanges
936+ * @see javax.sql.RowSetWriter
937+ * @see javax.sql.rowset.spi.SyncFactory
938+ * @see javax.sql.rowset.spi.SyncProvider
939+ */
940+ public void acceptChanges(Connection con) throws SyncProviderException{
941+
942+ setConnection(con);
943+ acceptChanges();
944+
945+ }
946+
947+ /**
948+ * Restores this <code>CachedRowSetImpl</code> object to its original state,
949+ * that is, its state before the last set of changes.
950+ * <P>
951+ * Before returning, this method moves the cursor before the first row
952+ * and sends a <code>rowSetChanged</code> event to all registered
953+ * listeners.
954+ * @throws SQLException if an error is occurs rolling back the RowSet
955+ * state to the definied original value.
956+ * @see javax.sql.RowSetListener#rowSetChanged
957+ */
958+ public void restoreOriginal() throws SQLException {
959+ Row currentRow;
960+ for (Iterator i = rvh.iterator(); i.hasNext();) {
961+ currentRow = (Row)i.next();
962+ if (currentRow.getInserted() == true) {
963+ i.remove();
964+ --numRows;
965+ } else {
966+ if (currentRow.getDeleted() == true) {
967+ currentRow.clearDeleted();
968+ }
969+ if (currentRow.getUpdated() == true) {
970+ currentRow.clearUpdated();
971+ }
972+ }
973+ }
974+ // move to before the first
975+ cursorPos = 0;
976+
977+ // notify any listeners
978+ notifyRowSetChanged();
979+ }
980+
981+ /**
982+ * Releases the current contents of this <code>CachedRowSetImpl</code>
983+ * object and sends a <code>rowSetChanged</code> event object to all
984+ * registered listeners.
985+ *
986+ * @throws SQLException if an error occurs flushing the contents of
987+ * RowSet.
988+ * @see javax.sql.RowSetListener#rowSetChanged
989+ */
990+ public void release() throws SQLException {
991+ initContainer();
992+ notifyRowSetChanged();
993+ }
994+
995+ /**
996+ * Cancels deletion of the current row and notifies listeners that
997+ * a row has changed.
998+ * <P>
999+ * Note: This method can be ignored if deleted rows are not being shown,
1000+ * which is the normal case.
1001+ *
1002+ * @throws SQLException if the cursor is not on a valid row
1003+ */
1004+ public void undoDelete() throws SQLException {
1005+ if (getShowDeleted() == false) {
1006+ return;
1007+ }
1008+ // make sure we are on a row
1009+ checkCursor();
1010+
1011+ // don't want this to happen...
1012+ if (onInsertRow == true) {
1013+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.invalidcp").toString());
1014+ }
1015+
1016+ Row currentRow = (Row)getCurrentRow();
1017+ if (currentRow.getDeleted() == true) {
1018+ currentRow.clearDeleted();
1019+ --numDeleted;
1020+ notifyRowChanged();
1021+ }
1022+ }
1023+
1024+ /**
1025+ * Immediately removes the current row from this
1026+ * <code>CachedRowSetImpl</code> object if the row has been inserted, and
1027+ * also notifies listeners the a row has changed. An exception is thrown
1028+ * if the row is not a row that has been inserted or the cursor is before
1029+ * the first row, after the last row, or on the insert row.
1030+ * <P>
1031+ * This operation cannot be undone.
1032+ *
1033+ * @throws SQLException if an error occurs,
1034+ * the cursor is not on a valid row,
1035+ * or the row has not been inserted
1036+ */
1037+ public void undoInsert() throws SQLException {
1038+ // make sure we are on a row
1039+ checkCursor();
1040+
1041+ // don't want this to happen...
1042+ if (onInsertRow == true) {
1043+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.invalidcp").toString());
1044+ }
1045+
1046+ Row currentRow = (Row)getCurrentRow();
1047+ if (currentRow.getInserted() == true) {
1048+ rvh.remove(cursorPos-1);
1049+ --numRows;
1050+ notifyRowChanged();
1051+ } else {
1052+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.illegalop").toString());
1053+ }
1054+ }
1055+
1056+ /**
1057+ * Immediately reverses the last update operation if the
1058+ * row has been modified. This method can be
1059+ * called to reverse updates on a all columns until all updates in a row have
1060+ * been rolled back to their originating state since the last synchronization
1061+ * (<code>acceptChanges</code>) or population. This method may also be called
1062+ * while performing updates to the insert row.
1063+ * <P>
1064+ * <code>undoUpdate</code may be called at any time during the life-time of a
1065+ * rowset, however after a synchronization has occurs this method has no
1066+ * affect until further modification to the RowSet data occurs.
1067+ *
1068+ * @throws SQLException if cursor is before the first row, after the last
1069+ * row in rowset.
1070+ * @see #undoDelete
1071+ * @see #undoInsert
1072+ * @see java.sql.ResultSet#cancelRowUpdates
1073+ */
1074+ public void undoUpdate() throws SQLException {
1075+ // if on insert row, cancel the insert row
1076+ // make the insert row flag,
1077+ // cursorPos back to the current row
1078+ moveToCurrentRow();
1079+
1080+ // else if not on insert row
1081+ // call undoUpdate or undoInsert
1082+ undoDelete();
1083+
1084+ undoInsert();
1085+
1086+ }
1087+
1088+ //--------------------------------------------------------------------
1089+ // Views
1090+ //--------------------------------------------------------------------
1091+
1092+ /**
1093+ * Returns a new <code>RowSet</code> object backed by the same data as
1094+ * that of this <code>CachedRowSetImpl</code> object and sharing a set of cursors
1095+ * with it. This allows cursors to interate over a shared set of rows, providing
1096+ * multiple views of the underlying data.
1097+ *
1098+ * @return a <code>RowSet</code> object that is a copy of this <code>CachedRowSetImpl</code>
1099+ * object and shares a set of cursors with it
1100+ * @throws SQLException if an error occurs or cloning is
1101+ * not supported
1102+ * @see javax.sql.RowSetEvent
1103+ * @see javax.sql.RowSetListener
1104+ */
1105+ public RowSet createShared() throws SQLException {
1106+ RowSet clone;
1107+ try {
1108+ clone = (RowSet)clone();
1109+ } catch (CloneNotSupportedException ex) {
1110+ throw new SQLException(ex.getMessage());
1111+ }
1112+ return clone;
1113+ }
1114+
1115+ /**
1116+ * Returns a new <code>RowSet</code> object containing by the same data
1117+ * as this <code>CachedRowSetImpl</code> object. This method
1118+ * differs from the method <code>createCopy</code> in that it throws a
1119+ * <code>CloneNotSupportedException</code> object instead of an
1120+ * <code>SQLException</code> object, as the method <code>createShared</code>
1121+ * does. This <code>clone</code>
1122+ * method is called internally by the method <code>createShared</code>,
1123+ * which catches the <code>CloneNotSupportedException</code> object
1124+ * and in turn throws a new <code>SQLException</code> object.
1125+ *
1126+ * @return a copy of this <code>CachedRowSetImpl</code> object
1127+ * @throws CloneNotSupportedException if an error occurs when
1128+ * attempting to clone this <code>CachedRowSetImpl</code> object
1129+ * @see #createShared
1130+ */
1131+ protected Object clone() throws CloneNotSupportedException {
1132+ return (super.clone());
1133+ }
1134+
1135+ /**
1136+ * Creates a <code>RowSet</code> object that is a deep copy of
1137+ * this <code>CachedRowSetImpl</code> object's data, including
1138+ * constraints. Updates made
1139+ * on a copy are not visible to the original rowset;
1140+ * a copy of a rowset is completely independent from the original.
1141+ * <P>
1142+ * Making a copy saves the cost of creating an identical rowset
1143+ * from first principles, which can be quite expensive.
1144+ * For example, it can eliminate the need to query a
1145+ * remote database server.
1146+ * @return a new <code>CachedRowSet</code> object that is a deep copy
1147+ * of this <code>CachedRowSet</code> object and is
1148+ * completely independent from this <code>CachedRowSetImpl</code>
1149+ * object.
1150+ * @throws SQLException if an error occurs in generating the copy of this
1151+ * of the <code>CachedRowSetImpl</code>
1152+ * @see #createShared
1153+ * @see javax.sql.RowSetEvent
1154+ * @see javax.sql.RowSetListener
1155+ */
1156+ public CachedRowSet createCopy() throws SQLException {
1157+ ObjectOutputStream out;
1158+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
1159+ try {
1160+ out = new ObjectOutputStream(bOut);
1161+ out.writeObject(this);
1162+ } catch (IOException ex) {
1163+ throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.clonefail").toString() , ex.getMessage()));
1164+ }
1165+
1166+ ObjectInputStream in;
1167+
1168+ try {
1169+ ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray());
1170+ in = new ObjectInputStream(bIn);
1171+ } catch (StreamCorruptedException ex) {
1172+ throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.clonefail").toString() , ex.getMessage()));
1173+ } catch (IOException ex) {
1174+ throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.clonefail").toString() , ex.getMessage()));
1175+ }
1176+
1177+ try {
1178+ //return ((CachedRowSet)(in.readObject()));
1179+ CachedRowSetImpl crsTemp = (CachedRowSetImpl)in.readObject();
1180+ crsTemp.resBundle = this.resBundle;
1181+ return ((CachedRowSet)crsTemp);
1182+
1183+ } catch (ClassNotFoundException ex) {
1184+ throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.clonefail").toString() , ex.getMessage()));
1185+ } catch (OptionalDataException ex) {
1186+ throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.clonefail").toString() , ex.getMessage()));
1187+ } catch (IOException ex) {
1188+ throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.clonefail").toString() , ex.getMessage()));
1189+ }
1190+ }
1191+
1192+ /**
1193+ * Creates a <code>RowSet</code> object that is a copy of
1194+ * this <code>CachedRowSetImpl</code> object's table structure
1195+ * and the constraints only.
1196+ * There will be no data in the object being returned.
1197+ * Updates made on a copy are not visible to the original rowset.
1198+ * <P>
1199+ * This helps in getting the underlying XML schema which can
1200+ * be used as the basis for populating a <code>WebRowSet</code>.
1201+ *
1202+ * @return a new <code>CachedRowSet</code> object that is a copy
1203+ * of this <code>CachedRowSetImpl</code> object's schema and
1204+ * retains all the constraints on the original rowset but contains
1205+ * no data
1206+ * @throws SQLException if an error occurs in generating the copy
1207+ * of the <code>CachedRowSet</code> object
1208+ * @see #createShared
1209+ * @see #createCopy
1210+ * @see #createCopyNoConstraints
1211+ * @see javax.sql.RowSetEvent
1212+ * @see javax.sql.RowSetListener
1213+ */
1214+ public CachedRowSet createCopySchema() throws SQLException {
1215+ // Copy everything except data i.e all constraints
1216+
1217+ // Store the number of rows of "this"
1218+ // and make numRows equals zero.
1219+ // and make data also zero.
1220+ int nRows = numRows;
1221+ numRows = 0;
1222+
1223+ CachedRowSet crs = this.createCopy();
1224+
1225+ // reset this object back to number of rows.
1226+ numRows = nRows;
1227+
1228+ return crs;
1229+ }
1230+
1231+ /**
1232+ * Creates a <code>CachedRowSet</code> object that is a copy of
1233+ * this <code>CachedRowSetImpl</code> object's data only.
1234+ * All constraints set in this object will not be there
1235+ * in the returning object. Updates made
1236+ * on a copy are not visible to the original rowset.
1237+ *
1238+ * @return a new <code>CachedRowSet</code> object that is a deep copy
1239+ * of this <code>CachedRowSetImpl</code> object and is
1240+ * completely independent from this <code>CachedRowSetImpl</code> object
1241+ * @throws SQLException if an error occurs in generating the copy of the
1242+ * of the <code>CachedRowSet</code>
1243+ * @see #createShared
1244+ * @see #createCopy
1245+ * @see #createCopySchema
1246+ * @see javax.sql.RowSetEvent
1247+ * @see javax.sql.RowSetListener
1248+ */
1249+ public CachedRowSet createCopyNoConstraints() throws SQLException {
1250+ // Copy the whole data ONLY without any constraints.
1251+ CachedRowSetImpl crs;
1252+ crs = (CachedRowSetImpl)this.createCopy();
1253+
1254+ crs.initProperties();
1255+ try {
1256+ crs.unsetMatchColumn(crs.getMatchColumnIndexes());
1257+ } catch(SQLException sqle) {
1258+ //do nothing, if the setMatchColumn is not set.
1259+ }
1260+
1261+ try {
1262+ crs.unsetMatchColumn(crs.getMatchColumnNames());
1263+ } catch(SQLException sqle) {
1264+ //do nothing, if the setMatchColumn is not set.
1265+ }
1266+
1267+ return crs;
1268+ }
1269+
1270+ /**
1271+ * Converts this <code>CachedRowSetImpl</code> object to a collection
1272+ * of tables. The sample implementation utilitizes the <code>TreeMap</code>
1273+ * collection type.
1274+ * This class guarantees that the map will be in ascending key order,
1275+ * sorted according to the natural order for the key's class.
1276+ *
1277+ * @return a <code>Collection</code> object consisting of tables,
1278+ * each of which is a copy of a row in this
1279+ * <code>CachedRowSetImpl</code> object
1280+ * @throws SQLException if an error occurs in generating the collection
1281+ * @see #toCollection(int)
1282+ * @see #toCollection(String)
1283+ * @see java.util.TreeMap
1284+ */
1285+ public Collection<?> toCollection() throws SQLException {
1286+
1287+ TreeMap<Integer, Object> tMap = new TreeMap<>();
1288+
1289+ for (int i = 0; i<numRows; i++) {
1290+ tMap.put(Integer.valueOf(i), rvh.get(i));
1291+ }
1292+
1293+ return (tMap.values());
1294+ }
1295+
1296+ /**
1297+ * Returns the specified column of this <code>CachedRowSetImpl</code> object
1298+ * as a <code>Collection</code> object. This method makes a copy of the
1299+ * column's data and utilitizes the <code>Vector</code> to establish the
1300+ * collection. The <code>Vector</code> class implements a growable array
1301+ * objects allowing the individual components to be accessed using an
1302+ * an integer index similar to that of an array.
1303+ *
1304+ * @return a <code>Collection</code> object that contains the value(s)
1305+ * stored in the specified column of this
1306+ * <code>CachedRowSetImpl</code>
1307+ * object
1308+ * @throws SQLException if an error occurs generated the collection; or
1309+ * an invalid column is provided.
1310+ * @see #toCollection()
1311+ * @see #toCollection(String)
1312+ * @see java.util.Vector
1313+ */
1314+ public Collection<?> toCollection(int column) throws SQLException {
1315+
1316+ int nRows = numRows;
1317+ Vector<Object> vec = new Vector<>(nRows);
1318+
1319+ // create a copy
1320+ CachedRowSetImpl crsTemp;
1321+ crsTemp = (CachedRowSetImpl) this.createCopy();
1322+
1323+ while(nRows!=0) {
1324+ crsTemp.next();
1325+ vec.add(crsTemp.getObject(column));
1326+ nRows--;
1327+ }
1328+
1329+ return (Collection)vec;
1330+ }
1331+
1332+ /**
1333+ * Returns the specified column of this <code>CachedRowSetImpl</code> object
1334+ * as a <code>Collection</code> object. This method makes a copy of the
1335+ * column's data and utilitizes the <code>Vector</code> to establish the
1336+ * collection. The <code>Vector</code> class implements a growable array
1337+ * objects allowing the individual components to be accessed using an
1338+ * an integer index similar to that of an array.
1339+ *
1340+ * @return a <code>Collection</code> object that contains the value(s)
1341+ * stored in the specified column of this
1342+ * <code>CachedRowSetImpl</code>
1343+ * object
1344+ * @throws SQLException if an error occurs generated the collection; or
1345+ * an invalid column is provided.
1346+ * @see #toCollection()
1347+ * @see #toCollection(int)
1348+ * @see java.util.Vector
1349+ */
1350+ public Collection<?> toCollection(String column) throws SQLException {
1351+ return toCollection(getColIdxByName(column));
1352+ }
1353+
1354+ //--------------------------------------------------------------------
1355+ // Advanced features
1356+ //--------------------------------------------------------------------
1357+
1358+
1359+ /**
1360+ * Returns the <code>SyncProvider</code> implementation being used
1361+ * with this <code>CachedRowSetImpl</code> implementation rowset.
1362+ *
1363+ * @return the SyncProvider used by the rowset. If not provider was
1364+ * set when the rowset was instantiated, the reference
1365+ * implementation (default) provider is returned.
1366+ * @throws SQLException if error occurs while return the
1367+ * <code>SyncProvider</code> instance.
1368+ */
1369+ public SyncProvider getSyncProvider() throws SQLException {
1370+ return provider;
1371+ }
1372+
1373+ /**
1374+ * Sets the active <code>SyncProvider</code> and attempts to load
1375+ * load the new provider using the <code>SyncFactory</code> SPI.
1376+ *
1377+ * @throws SQLException if an error occurs while resetting the
1378+ * <code>SyncProvider</code>.
1379+ */
1380+ public void setSyncProvider(String providerStr) throws SQLException {
1381+ provider =
1382+ (SyncProvider)SyncFactory.getInstance(providerStr);
1383+
1384+ rowSetReader = provider.getRowSetReader();
1385+ rowSetWriter = provider.getRowSetWriter();
1386+ }
1387+
1388+
1389+ //-----------------
1390+ // methods inherited from RowSet
1391+ //-----------------
1392+
1393+
1394+
1395+
1396+
1397+
1398+ //---------------------------------------------------------------------
1399+ // Reading and writing data
1400+ //---------------------------------------------------------------------
1401+
1402+ /**
1403+ * Populates this <code>CachedRowSetImpl</code> object with data.
1404+ * This form of the method uses the rowset's user, password, and url or
1405+ * data source name properties to create a database
1406+ * connection. If properties that are needed
1407+ * have not been set, this method will throw an exception.
1408+ * <P>
1409+ * Another form of this method uses an existing JDBC <code>Connection</code>
1410+ * object instead of creating a new one; therefore, it ignores the
1411+ * properties used for establishing a new connection.
1412+ * <P>
1413+ * The query specified by the command property is executed to create a
1414+ * <code>ResultSet</code> object from which to retrieve data.
1415+ * The current contents of the rowset are discarded, and the
1416+ * rowset's metadata is also (re)set. If there are outstanding updates,
1417+ * they are also ignored.
1418+ * <P>
1419+ * The method <code>execute</code> closes any database connections that it
1420+ * creates.
1421+ *
1422+ * @throws SQLException if an error occurs or the
1423+ * necessary properties have not been set
1424+ */
1425+ public void execute() throws SQLException {
1426+ execute(null);
1427+ }
1428+
1429+
1430+
1431+ //-----------------------------------
1432+ // Methods inherited from ResultSet
1433+ //-----------------------------------
1434+
1435+ /**
1436+ * Moves the cursor down one row from its current position and
1437+ * returns <code>true</code> if the new cursor position is a
1438+ * valid row.
1439+ * The cursor for a new <code>ResultSet</code> object is initially
1440+ * positioned before the first row. The first call to the method
1441+ * <code>next</code> moves the cursor to the first row, making it
1442+ * the current row; the second call makes the second row the
1443+ * current row, and so on.
1444+ *
1445+ * <P>If an input stream from the previous row is open, it is
1446+ * implicitly closed. The <code>ResultSet</code> object's warning
1447+ * chain is cleared when a new row is read.
1448+ *
1449+ * @return <code>true</code> if the new current row is valid;
1450+ * <code>false</code> if there are no more rows
1451+ * @throws SQLException if an error occurs or
1452+ * the cursor is not positioned in the rowset, before
1453+ * the first row, or after the last row
1454+ */
1455+ public boolean next() throws SQLException {
1456+ /*
1457+ * make sure things look sane. The cursor must be
1458+ * positioned in the rowset or before first (0) or
1459+ * after last (numRows + 1)
1460+ */
1461+ if (cursorPos < 0 || cursorPos >= numRows + 1) {
1462+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.invalidcp").toString());
1463+ }
1464+ // now move and notify
1465+ boolean ret = this.internalNext();
1466+ notifyCursorMoved();
1467+
1468+ return ret;
1469+ }
1470+
1471+ /**
1472+ * Moves this <code>CachedRowSetImpl</code> object's cursor to the next
1473+ * row and returns <code>true</code> if the cursor is still in the rowset;
1474+ * returns <code>false</code> if the cursor has moved to the position after
1475+ * the last row.
1476+ * <P>
1477+ * This method handles the cases where the cursor moves to a row that
1478+ * has been deleted.
1479+ * If this rowset shows deleted rows and the cursor moves to a row
1480+ * that has been deleted, this method moves the cursor to the next
1481+ * row until the cursor is on a row that has not been deleted.
1482+ * <P>
1483+ * The method <code>internalNext</code> is called by methods such as
1484+ * <code>next</code>, <code>absolute</code>, and <code>relative</code>,
1485+ * and, as its name implies, is only called internally.
1486+ * <p>
1487+ * This is a implementation only method and is not required as a standard
1488+ * implementation of the <code>CachedRowSet</code> interface.
1489+ *
1490+ * @return <code>true</code> if the cursor is on a valid row in this
1491+ * rowset; <code>false</code> if it is after the last row
1492+ * @throws SQLException if an error occurs
1493+ */
1494+ protected boolean internalNext() throws SQLException {
1495+ boolean ret = false;
1496+
1497+ do {
1498+ if (cursorPos < numRows) {
1499+ ++cursorPos;
1500+ ret = true;
1501+ } else if (cursorPos == numRows) {
1502+ // increment to after last
1503+ ++cursorPos;
1504+ ret = false;
1505+ break;
1506+ }
1507+ } while ((getShowDeleted() == false) && (rowDeleted() == true));
1508+
1509+ /* each call to internalNext may increment cursorPos multiple
1510+ * times however, the absolutePos only increments once per call.
1511+ */
1512+ if (ret == true)
1513+ absolutePos++;
1514+ else
1515+ absolutePos = 0;
1516+
1517+ return ret;
1518+ }
1519+
1520+ /**
1521+ * Closes this <code>CachedRowSetImpl</code> objecy and releases any resources
1522+ * it was using.
1523+ *
1524+ * @throws SQLException if an error occurs when releasing any resources in use
1525+ * by this <code>CachedRowSetImpl</code> object
1526+ */
1527+ public void close() throws SQLException {
1528+
1529+ // close all data structures holding
1530+ // the disconnected rowset
1531+
1532+ cursorPos = 0;
1533+ absolutePos = 0;
1534+ numRows = 0;
1535+ numDeleted = 0;
1536+
1537+ // set all insert(s), update(s) & delete(s),
1538+ // if at all, to their initial values.
1539+ initProperties();
1540+
1541+ // clear the vector of it's present contents
1542+ rvh.clear();
1543+
1544+ // this will make it eligible for gc
1545+ // rvh = null;
1546+ }
1547+
1548+ /**
1549+ * Reports whether the last column read was SQL <code>NULL</code>.
1550+ * Note that you must first call the method <code>getXXX</code>
1551+ * on a column to try to read its value and then call the method
1552+ * <code>wasNull</code> to determine whether the value was
1553+ * SQL <code>NULL</code>.
1554+ *
1555+ * @return <code>true</code> if the value in the last column read
1556+ * was SQL <code>NULL</code>; <code>false</code> otherwise
1557+ * @throws SQLException if an error occurs
1558+ */
1559+ public boolean wasNull() throws SQLException {
1560+ return lastValueNull;
1561+ }
1562+
1563+ /**
1564+ * Sets the field <code>lastValueNull</code> to the given
1565+ * <code>boolean</code> value.
1566+ *
1567+ * @param value <code>true</code> to indicate that the value of
1568+ * the last column read was SQL <code>NULL</code>;
1569+ * <code>false</code> to indicate that it was not
1570+ */
1571+ private void setLastValueNull(boolean value) {
1572+ lastValueNull = value;
1573+ }
1574+
1575+ // Methods for accessing results by column index
1576+
1577+ /**
1578+ * Checks to see whether the given index is a valid column number
1579+ * in this <code>CachedRowSetImpl</code> object and throws
1580+ * an <code>SQLException</code> if it is not. The index is out of bounds
1581+ * if it is less than <code>1</code> or greater than the number of
1582+ * columns in this rowset.
1583+ * <P>
1584+ * This method is called internally by the <code>getXXX</code> and
1585+ * <code>updateXXX</code> methods.
1586+ *
1587+ * @param idx the number of a column in this <code>CachedRowSetImpl</code>
1588+ * object; must be between <code>1</code> and the number of
1589+ * rows in this rowset
1590+ * @throws SQLException if the given index is out of bounds
1591+ */
1592+ private void checkIndex(int idx) throws SQLException {
1593+ if (idx < 1 || idx > RowSetMD.getColumnCount()) {
1594+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.invalidcol").toString());
1595+ }
1596+ }
1597+
1598+ /**
1599+ * Checks to see whether the cursor for this <code>CachedRowSetImpl</code>
1600+ * object is on a row in the rowset and throws an
1601+ * <code>SQLException</code> if it is not.
1602+ * <P>
1603+ * This method is called internally by <code>getXXX</code> methods, by
1604+ * <code>updateXXX</code> methods, and by methods that update, insert,
1605+ * or delete a row or that cancel a row update, insert, or delete.
1606+ *
1607+ * @throws SQLException if the cursor for this <code>CachedRowSetImpl</code>
1608+ * object is not on a valid row
1609+ */
1610+ private void checkCursor() throws SQLException {
1611+ if (isAfterLast() == true || isBeforeFirst() == true) {
1612+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.invalidcp").toString());
1613+ }
1614+ }
1615+
1616+ /**
1617+ * Returns the column number of the column with the given name in this
1618+ * <code>CachedRowSetImpl</code> object. This method throws an
1619+ * <code>SQLException</code> if the given name is not the name of
1620+ * one of the columns in this rowset.
1621+ *
1622+ * @param name a <code>String</code> object that is the name of a column in
1623+ * this <code>CachedRowSetImpl</code> object
1624+ * @throws SQLException if the given name does not match the name of one of
1625+ * the columns in this rowset
1626+ */
1627+ private int getColIdxByName(String name) throws SQLException {
1628+ RowSetMD = (RowSetMetaDataImpl)this.getMetaData();
1629+ int cols = RowSetMD.getColumnCount();
1630+
1631+ for (int i=1; i <= cols; ++i) {
1632+ String colName = RowSetMD.getColumnName(i);
1633+ if (colName != null)
1634+ if (name.equalsIgnoreCase(colName))
1635+ return (i);
1636+ else
1637+ continue;
1638+ }
1639+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.invalcolnm").toString());
1640+
1641+ }
1642+
1643+ /**
1644+ * Returns the insert row or the current row of this
1645+ * <code>CachedRowSetImpl</code>object.
1646+ *
1647+ * @return the <code>Row</code> object on which this <code>CachedRowSetImpl</code>
1648+ * objects's cursor is positioned
1649+ */
1650+ protected BaseRow getCurrentRow() {
1651+ if (onInsertRow == true) {
1652+ return (BaseRow)insertRow;
1653+ } else {
1654+ return (BaseRow)(rvh.get(cursorPos - 1));
1655+ }
1656+ }
1657+
1658+ /**
1659+ * Removes the row on which the cursor is positioned.
1660+ * <p>
1661+ * This is a implementation only method and is not required as a standard
1662+ * implementation of the <code>CachedRowSet</code> interface.
1663+ *
1664+ * @throws SQLException if the cursor is positioned on the insert
1665+ * row
1666+ */
1667+ protected void removeCurrentRow() {
1668+ ((Row)getCurrentRow()).setDeleted();
1669+ rvh.remove(cursorPos - 1);
1670+ --numRows;
1671+ }
1672+
1673+
1674+ /**
1675+ * Retrieves the value of the designated column in the current row
1676+ * of this <code>CachedRowSetImpl</code> object as a
1677+ * <code>String</code> object.
1678+ *
1679+ * @param columnIndex the first column is <code>1</code>, the second
1680+ * is <code>2</code>, and so on; must be <code>1</code> or larger
1681+ * and equal to or less than the number of columns in the rowset
1682+ * @return the column value; if the value is SQL <code>NULL</code>, the
1683+ * result is <code>null</code>
1684+ * @throws SQLException if (1) the given column index is out of bounds,
1685+ * (2) the cursor is not on one of this rowset's rows or its
1686+ * insert row, or (3) the designated column does not store an
1687+ * SQL <code>TINYINT, SMALLINT, INTEGER, BIGINT, REAL,
1688+ * FLOAT, DOUBLE, DECIMAL, NUMERIC, BIT, <b>CHAR</b>, <b>VARCHAR</b></code>
1689+ * or <code>LONGVARCHAR</code> value. The bold SQL type designates the
1690+ * recommended return type.
1691+ */
1692+ public String getString(int columnIndex) throws SQLException {
1693+ Object value;
1694+
1695+ // sanity check.
1696+ checkIndex(columnIndex);
1697+ // make sure the cursor is on a valid row
1698+ checkCursor();
1699+
1700+ setLastValueNull(false);
1701+ value = getCurrentRow().getColumnObject(columnIndex);
1702+
1703+ // check for SQL NULL
1704+ if (value == null) {
1705+ setLastValueNull(true);
1706+ return null;
1707+ }
1708+
1709+ return value.toString();
1710+ }
1711+
1712+ /**
1713+ * Retrieves the value of the designated column in the current row
1714+ * of this <code>CachedRowSetImpl</code> object as a
1715+ * <code>boolean</code> value.
1716+ *
1717+ * @param columnIndex the first column is <code>1</code>, the second
1718+ * is <code>2</code>, and so on; must be <code>1</code> or larger
1719+ * and equal to or less than the number of columns in the rowset
1720+ * @return the column value as a <code>boolean</code> in the Java progamming language;
1721+ * if the value is SQL <code>NULL</code>, the result is <code>false</code>
1722+ * @throws SQLException if (1) the given column index is out of bounds,
1723+ * (2) the cursor is not on one of this rowset's rows or its
1724+ * insert row, or (3) the designated column does not store an
1725+ * SQL <code>BOOLEAN</code> value
1726+ * @see #getBoolean(String)
1727+ */
1728+ public boolean getBoolean(int columnIndex) throws SQLException {
1729+ Object value;
1730+
1731+ // sanity check.
1732+ checkIndex(columnIndex);
1733+ // make sure the cursor is on a valid row
1734+ checkCursor();
1735+
1736+ setLastValueNull(false);
1737+ value = getCurrentRow().getColumnObject(columnIndex);
1738+
1739+ // check for SQL NULL
1740+ if (value == null) {
1741+ setLastValueNull(true);
1742+ return false;
1743+ }
1744+
1745+ // check for Boolean...
1746+ if (value instanceof Boolean) {
1747+ return ((Boolean)value).booleanValue();
1748+ }
1749+
1750+ // convert to a Double and compare to zero
1751+ try {
1752+ Double d = new Double(value.toString());
1753+ if (d.compareTo(new Double((double)0)) == 0) {
1754+ return false;
1755+ } else {
1756+ return true;
1757+ }
1758+ } catch (NumberFormatException ex) {
1759+ throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.boolfail").toString(),
1760+ new Object[] {value.toString().trim(), columnIndex}));
1761+ }
1762+ }
1763+
1764+ /**
1765+ * Retrieves the value of the designated column in the current row
1766+ * of this <code>CachedRowSetImpl</code> object as a
1767+ * <code>byte</code> value.
1768+ *
1769+ * @param columnIndex the first column is <code>1</code>, the second
1770+ * is <code>2</code>, and so on; must be <code>1</code> or larger
1771+ * and equal to or less than the number of columns in the rowset
1772+ * @return the column value as a <code>byte</code> in the Java programming
1773+ * language; if the value is SQL <code>NULL</code>, the result is <code>0</code>
1774+ * @throws SQLException if (1) the given column index is out of bounds,
1775+ * (2) the cursor is not on one of this rowset's rows or its
1776+ * insert row, or (3) the designated column does not store an
1777+ * SQL <code><b>TINYINT</b>, SMALLINT, INTEGER, BIGINT, REAL,
1778+ * FLOAT, DOUBLE, DECIMAL, NUMERIC, BIT, CHAR, VARCHAR</code>
1779+ * or <code>LONGVARCHAR</code> value. The bold SQL type
1780+ * designates the recommended return type.
1781+ * @see #getByte(String)
1782+ */
1783+ public byte getByte(int columnIndex) throws SQLException {
1784+ Object value;
1785+
1786+ // sanity check.
1787+ checkIndex(columnIndex);
1788+ // make sure the cursor is on a valid row
1789+ checkCursor();
1790+
1791+ setLastValueNull(false);
1792+ value = getCurrentRow().getColumnObject(columnIndex);
1793+
1794+ // check for SQL NULL
1795+ if (value == null) {
1796+ setLastValueNull(true);
1797+ return (byte)0;
1798+ }
1799+ try {
1800+ return ((Byte.valueOf(value.toString())).byteValue());
1801+ } catch (NumberFormatException ex) {
1802+ throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.bytefail").toString(),
1803+ new Object[] {value.toString().trim(), columnIndex}));
1804+ }
1805+ }
1806+
1807+ /**
1808+ * Retrieves the value of the designated column in the current row
1809+ * of this <code>CachedRowSetImpl</code> object as a
1810+ * <code>short</code> value.
1811+ *
1812+ * @param columnIndex the first column is <code>1</code>, the second
1813+ * is <code>2</code>, and so on; must be <code>1</code> or larger
1814+ * and equal to or less than the number of columns in the rowset
1815+ * @return the column value; if the value is SQL <code>NULL</code>, the
1816+ * result is <code>0</code>
1817+ * @throws SQLException if (1) the given column index is out of bounds,
1818+ * (2) the cursor is not on one of this rowset's rows or its
1819+ * insert row, or (3) the designated column does not store an
1820+ * SQL <code>TINYINT, <b>SMALLINT</b>, INTEGER, BIGINT, REAL
1821+ * FLOAT, DOUBLE, DECIMAL, NUMERIC, BIT, CHAR, VARCHAR</code>
1822+ * or <code>LONGVARCHAR</code> value. The bold SQL type designates the
1823+ * recommended return type.
1824+ * @see #getShort(String)
1825+ */
1826+ public short getShort(int columnIndex) throws SQLException {
1827+ Object value;
1828+
1829+ // sanity check.
1830+ checkIndex(columnIndex);
1831+ // make sure the cursor is on a valid row
1832+ checkCursor();
1833+
1834+ setLastValueNull(false);
1835+ value = getCurrentRow().getColumnObject(columnIndex);
1836+
1837+ // check for SQL NULL
1838+ if (value == null) {
1839+ setLastValueNull(true);
1840+ return (short)0;
1841+ }
1842+
1843+ try {
1844+ return ((Short.valueOf(value.toString().trim())).shortValue());
1845+ } catch (NumberFormatException ex) {
1846+ throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.shortfail").toString(),
1847+ new Object[] {value.toString().trim(), columnIndex}));
1848+ }
1849+ }
1850+
1851+ /**
1852+ * Retrieves the value of the designated column in the current row
1853+ * of this <code>CachedRowSetImpl</code> object as an
1854+ * <code>int</code> value.
1855+ *
1856+ * @param columnIndex the first column is <code>1</code>, the second
1857+ * is <code>2</code>, and so on; must be <code>1</code> or larger
1858+ * and equal to or less than the number of columns in the rowset
1859+ * @return the column value; if the value is SQL <code>NULL</code>, the
1860+ * result is <code>0</code>
1861+ * @throws SQLException if (1) the given column index is out of bounds,
1862+ * (2) the cursor is not on one of this rowset's rows or its
1863+ * insert row, or (3) the designated column does not store an
1864+ * SQL <code>TINYINT, SMALLINT, <b>INTEGER</b>, BIGINT, REAL
1865+ * FLOAT, DOUBLE, DECIMAL, NUMERIC, BIT, CHAR, VARCHAR</code>
1866+ * or <code>LONGVARCHAR</code> value. The bold SQL type designates the
1867+ * recommended return type.
1868+ */
1869+ public int getInt(int columnIndex) throws SQLException {
1870+ Object value;
1871+
1872+ // sanity check.
1873+ checkIndex(columnIndex);
1874+ // make sure the cursor is on a valid row
1875+ checkCursor();
1876+
1877+ setLastValueNull(false);
1878+ value = getCurrentRow().getColumnObject(columnIndex);
1879+
1880+ // check for SQL NULL
1881+ if (value == null) {
1882+ setLastValueNull(true);
1883+ return (int)0;
1884+ }
1885+
1886+ try {
1887+ return ((Integer.valueOf(value.toString().trim())).intValue());
1888+ } catch (NumberFormatException ex) {
1889+ throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.intfail").toString(),
1890+ new Object[] {value.toString().trim(), columnIndex}));
1891+ }
1892+ }
1893+
1894+ /**
1895+ * Retrieves the value of the designated column in the current row
1896+ * of this <code>CachedRowSetImpl</code> object as a
1897+ * <code>long</code> value.
1898+ *
1899+ * @param columnIndex the first column is <code>1</code>, the second
1900+ * is <code>2</code>, and so on; must be <code>1</code> or larger
1901+ * and equal to or less than the number of columns in the rowset
1902+ * @return the column value; if the value is SQL <code>NULL</code>, the
1903+ * result is <code>0</code>
1904+ * @throws SQLException if (1) the given column index is out of bounds,
1905+ * (2) the cursor is not on one of this rowset's rows or its
1906+ * insert row, or (3) the designated column does not store an
1907+ * SQL <code>TINYINT, SMALLINT, INTEGER, <b>BIGINT</b>, REAL
1908+ * FLOAT, DOUBLE, DECIMAL, NUMERIC, BIT, CHAR, VARCHAR</code>
1909+ * or <code>LONGVARCHAR</code> value. The bold SQL type designates the
1910+ * recommended return type.
1911+ * @see #getLong(String)
1912+ */
1913+ public long getLong(int columnIndex) throws SQLException {
1914+ Object value;
1915+
1916+ // sanity check.
1917+ checkIndex(columnIndex);
1918+ // make sure the cursor is on a valid row
1919+ checkCursor();
1920+
1921+ setLastValueNull(false);
1922+ value = getCurrentRow().getColumnObject(columnIndex);
1923+
1924+ // check for SQL NULL
1925+ if (value == null) {
1926+ setLastValueNull(true);
1927+ return (long)0;
1928+ }
1929+ try {
1930+ return ((Long.valueOf(value.toString().trim())).longValue());
1931+ } catch (NumberFormatException ex) {
1932+ throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.longfail").toString(),
1933+ new Object[] {value.toString().trim(), columnIndex}));
1934+ }
1935+ }
1936+
1937+ /**
1938+ * Retrieves the value of the designated column in the current row
1939+ * of this <code>CachedRowSetImpl</code> object as a
1940+ * <code>float</code> value.
1941+ *
1942+ * @param columnIndex the first column is <code>1</code>, the second
1943+ * is <code>2</code>, and so on; must be <code>1</code> or larger
1944+ * and equal to or less than the number of columns in the rowset
1945+ * @return the column value; if the value is SQL <code>NULL</code>, the
1946+ * result is <code>0</code>
1947+ * @throws SQLException if (1) the given column index is out of bounds,
1948+ * (2) the cursor is not on one of this rowset's rows or its
1949+ * insert row, or (3) the designated column does not store an
1950+ * SQL <code>TINYINT, SMALLINT, INTEGER, BIGINT, <b>REAL</b>,
1951+ * FLOAT, DOUBLE, DECIMAL, NUMERIC, BIT, CHAR, VARCHAR</code>
1952+ * or <code>LONGVARCHAR</code> value. The bold SQL type designates the
1953+ * recommended return type.
1954+ * @see #getFloat(String)
1955+ */
1956+ public float getFloat(int columnIndex) throws SQLException {
1957+ Object value;
1958+
1959+ // sanity check.
1960+ checkIndex(columnIndex);
1961+ // make sure the cursor is on a valid row
1962+ checkCursor();
1963+
1964+ setLastValueNull(false);
1965+ value = getCurrentRow().getColumnObject(columnIndex);
1966+
1967+ // check for SQL NULL
1968+ if (value == null) {
1969+ setLastValueNull(true);
1970+ return (float)0;
1971+ }
1972+ try {
1973+ return ((new Float(value.toString())).floatValue());
1974+ } catch (NumberFormatException ex) {
1975+ throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.floatfail").toString(),
1976+ new Object[] {value.toString().trim(), columnIndex}));
1977+ }
1978+ }
1979+
1980+ /**
1981+ * Retrieves the value of the designated column in the current row
1982+ * of this <code>CachedRowSetImpl</code> object as a
1983+ * <code>double</code> value.
1984+ *
1985+ * @param columnIndex the first column is <code>1</code>, the second
1986+ * is <code>2</code>, and so on; must be <code>1</code> or larger
1987+ * and equal to or less than the number of columns in the rowset
1988+ * @return the column value; if the value is SQL <code>NULL</code>, the
1989+ * result is <code>0</code>
1990+ * @throws SQLException if (1) the given column index is out of bounds,
1991+ * (2) the cursor is not on one of this rowset's rows or its
1992+ * insert row, or (3) the designated column does not store an
1993+ * SQL <code>TINYINT, SMALLINT, INTEGER, BIGINT, REAL,
1994+ * <b>FLOAT</b>, <b>DOUBLE</b>, DECIMAL, NUMERIC, BIT, CHAR, VARCHAR</code>
1995+ * or <code>LONGVARCHAR</code> value. The bold SQL type designates the
1996+ * recommended return type.
1997+ * @see #getDouble(String)
1998+ *
1999+ */
2000+ public double getDouble(int columnIndex) throws SQLException {
2001+ Object value;
2002+
2003+ // sanity check.
2004+ checkIndex(columnIndex);
2005+ // make sure the cursor is on a valid row
2006+ checkCursor();
2007+
2008+ setLastValueNull(false);
2009+ value = getCurrentRow().getColumnObject(columnIndex);
2010+
2011+ // check for SQL NULL
2012+ if (value == null) {
2013+ setLastValueNull(true);
2014+ return (double)0;
2015+ }
2016+ try {
2017+ return ((new Double(value.toString().trim())).doubleValue());
2018+ } catch (NumberFormatException ex) {
2019+ throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.doublefail").toString(),
2020+ new Object[] {value.toString().trim(), columnIndex}));
2021+ }
2022+ }
2023+
2024+ /**
2025+ * Retrieves the value of the designated column in the current row
2026+ * of this <code>CachedRowSetImpl</code> object as a
2027+ * <code>java.math.BigDecimal</code> object.
2028+ * <P>
2029+ * This method is deprecated; use the version of <code>getBigDecimal</code>
2030+ * that does not take a scale parameter and returns a value with full
2031+ * precision.
2032+ *
2033+ * @param columnIndex the first column is <code>1</code>, the second
2034+ * is <code>2</code>, and so on; must be <code>1</code> or larger
2035+ * and equal to or less than the number of columns in the rowset
2036+ * @param scale the number of digits to the right of the decimal point in the
2037+ * value returned
2038+ * @return the column value with the specified number of digits to the right
2039+ * of the decimal point; if the value is SQL <code>NULL</code>, the
2040+ * result is <code>null</code>
2041+ * @throws SQLException if the given column index is out of bounds,
2042+ * the cursor is not on a valid row, or this method fails
2043+ * @deprecated
2044+ */
2045+ public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException {
2046+ Object value;
2047+ BigDecimal bDecimal, retVal;
2048+
2049+ // sanity check.
2050+ checkIndex(columnIndex);
2051+ // make sure the cursor is on a valid row
2052+ checkCursor();
2053+
2054+ setLastValueNull(false);
2055+ value = getCurrentRow().getColumnObject(columnIndex);
2056+
2057+ // check for SQL NULL
2058+ if (value == null) {
2059+ setLastValueNull(true);
2060+ return (new BigDecimal(0));
2061+ }
2062+
2063+ bDecimal = this.getBigDecimal(columnIndex);
2064+
2065+ retVal = bDecimal.setScale(scale);
2066+
2067+ return retVal;
2068+ }
2069+
2070+ /**
2071+ * Retrieves the value of the designated column in the current row
2072+ * of this <code>CachedRowSetImpl</code> object as a
2073+ * <code>byte</code> array value.
2074+ *
2075+ * @param columnIndex the first column is <code>1</code>, the second
2076+ * is <code>2</code>, and so on; must be <code>1</code> or larger
2077+ * and equal to or less than the number of columns in the rowset
2078+ * @return the column value as a <code>byte</code> array in the Java programming
2079+ * language; if the value is SQL <code>NULL</code>, the
2080+ * result is <code>null</code>
2081+ *
2082+ * @throws SQLException if (1) the given column index is out of bounds,
2083+ * (2) the cursor is not on one of this rowset's rows or its
2084+ * insert row, or (3) the designated column does not store an
2085+ * SQL <code><b>BINARY</b>, <b>VARBINARY</b> or
2086+ * LONGVARBINARY</code> value.
2087+ * The bold SQL type designates the recommended return type.
2088+ * @see #getBytes(String)
2089+ */
2090+ public byte[] getBytes(int columnIndex) throws SQLException {
2091+ // sanity check.
2092+ checkIndex(columnIndex);
2093+ // make sure the cursor is on a valid row
2094+ checkCursor();
2095+
2096+ if (isBinary(RowSetMD.getColumnType(columnIndex)) == false) {
2097+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.dtypemismt").toString());
2098+ }
2099+
2100+ return (byte[])(getCurrentRow().getColumnObject(columnIndex));
2101+ }
2102+
2103+ /**
2104+ * Retrieves the value of the designated column in the current row
2105+ * of this <code>CachedRowSetImpl</code> object as a
2106+ * <code>java.sql.Date</code> object.
2107+ *
2108+ * @param columnIndex the first column is <code>1</code>, the second
2109+ * is <code>2</code>, and so on; must be <code>1</code> or larger
2110+ * and equal to or less than the number of columns in the rowset
2111+ * @return the column value as a <code>java.sql.Data</code> object; if
2112+ * the value is SQL <code>NULL</code>, the
2113+ * result is <code>null</code>
2114+ * @throws SQLException if the given column index is out of bounds,
2115+ * the cursor is not on a valid row, or this method fails
2116+ */
2117+ public java.sql.Date getDate(int columnIndex) throws SQLException {
2118+ Object value;
2119+
2120+ // sanity check.
2121+ checkIndex(columnIndex);
2122+ // make sure the cursor is on a valid row
2123+ checkCursor();
2124+
2125+ setLastValueNull(false);
2126+ value = getCurrentRow().getColumnObject(columnIndex);
2127+
2128+ // check for SQL NULL
2129+ if (value == null) {
2130+ setLastValueNull(true);
2131+ return null;
2132+ }
2133+
2134+ /*
2135+ * The object coming back from the db could be
2136+ * a date, a timestamp, or a char field variety.
2137+ * If it's a date type return it, a timestamp
2138+ * we turn into a long and then into a date,
2139+ * char strings we try to parse. Yuck.
2140+ */
2141+ switch (RowSetMD.getColumnType(columnIndex)) {
2142+ case java.sql.Types.DATE: {
2143+ long sec = ((java.sql.Date)value).getTime();
2144+ return new java.sql.Date(sec);
2145+ }
2146+ case java.sql.Types.TIMESTAMP: {
2147+ long sec = ((java.sql.Timestamp)value).getTime();
2148+ return new java.sql.Date(sec);
2149+ }
2150+ case java.sql.Types.CHAR:
2151+ case java.sql.Types.VARCHAR:
2152+ case java.sql.Types.LONGVARCHAR: {
2153+ try {
2154+ DateFormat df = DateFormat.getDateInstance();
2155+ return ((java.sql.Date)(df.parse(value.toString())));
2156+ } catch (ParseException ex) {
2157+ throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.datefail").toString(),
2158+ new Object[] {value.toString().trim(), columnIndex}));
2159+ }
2160+ }
2161+ default: {
2162+ throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.datefail").toString(),
2163+ new Object[] {value.toString().trim(), columnIndex}));
2164+ }
2165+ }
2166+ }
2167+
2168+ /**
2169+ * Retrieves the value of the designated column in the current row
2170+ * of this <code>CachedRowSetImpl</code> object as a
2171+ * <code>java.sql.Time</code> object.
2172+ *
2173+ * @param columnIndex the first column is <code>1</code>, the second
2174+ * is <code>2</code>, and so on; must be <code>1</code> or larger
2175+ * and equal to or less than the number of columns in the rowset
2176+ * @return the column value; if the value is SQL <code>NULL</code>, the
2177+ * result is <code>null</code>
2178+ * @throws SQLException if the given column index is out of bounds,
2179+ * the cursor is not on a valid row, or this method fails
2180+ */
2181+ public java.sql.Time getTime(int columnIndex) throws SQLException {
2182+ Object value;
2183+
2184+ // sanity check.
2185+ checkIndex(columnIndex);
2186+ // make sure the cursor is on a valid row
2187+ checkCursor();
2188+
2189+ setLastValueNull(false);
2190+ value = getCurrentRow().getColumnObject(columnIndex);
2191+
2192+ // check for SQL NULL
2193+ if (value == null) {
2194+ setLastValueNull(true);
2195+ return null;
2196+ }
2197+
2198+ /*
2199+ * The object coming back from the db could be
2200+ * a date, a timestamp, or a char field variety.
2201+ * If it's a date type return it, a timestamp
2202+ * we turn into a long and then into a date,
2203+ * char strings we try to parse. Yuck.
2204+ */
2205+ switch (RowSetMD.getColumnType(columnIndex)) {
2206+ case java.sql.Types.TIME: {
2207+ return (java.sql.Time)value;
2208+ }
2209+ case java.sql.Types.TIMESTAMP: {
2210+ long sec = ((java.sql.Timestamp)value).getTime();
2211+ return new java.sql.Time(sec);
2212+ }
2213+ case java.sql.Types.CHAR:
2214+ case java.sql.Types.VARCHAR:
2215+ case java.sql.Types.LONGVARCHAR: {
2216+ try {
2217+ DateFormat tf = DateFormat.getTimeInstance();
2218+ return ((java.sql.Time)(tf.parse(value.toString())));
2219+ } catch (ParseException ex) {
2220+ throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.timefail").toString(),
2221+ new Object[] {value.toString().trim(), columnIndex}));
2222+ }
2223+ }
2224+ default: {
2225+ throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.timefail").toString(),
2226+ new Object[] {value.toString().trim(), columnIndex}));
2227+ }
2228+ }
2229+ }
2230+
2231+ /**
2232+ * Retrieves the value of the designated column in the current row
2233+ * of this <code>CachedRowSetImpl</code> object as a
2234+ * <code>java.sql.Timestamp</code> object.
2235+ *
2236+ * @param columnIndex the first column is <code>1</code>, the second
2237+ * is <code>2</code>, and so on; must be <code>1</code> or larger
2238+ * and equal to or less than the number of columns in the rowset
2239+ * @return the column value; if the value is SQL <code>NULL</code>, the
2240+ * result is <code>null</code>
2241+ * @throws SQLException if the given column index is out of bounds,
2242+ * the cursor is not on a valid row, or this method fails
2243+ */
2244+ public java.sql.Timestamp getTimestamp(int columnIndex) throws SQLException {
2245+ Object value;
2246+
2247+ // sanity check.
2248+ checkIndex(columnIndex);
2249+ // make sure the cursor is on a valid row
2250+ checkCursor();
2251+
2252+ setLastValueNull(false);
2253+ value = getCurrentRow().getColumnObject(columnIndex);
2254+
2255+ // check for SQL NULL
2256+ if (value == null) {
2257+ setLastValueNull(true);
2258+ return null;
2259+ }
2260+
2261+ /*
2262+ * The object coming back from the db could be
2263+ * a date, a timestamp, or a char field variety.
2264+ * If it's a date type return it; a timestamp
2265+ * we turn into a long and then into a date;
2266+ * char strings we try to parse. Yuck.
2267+ */
2268+ switch (RowSetMD.getColumnType(columnIndex)) {
2269+ case java.sql.Types.TIMESTAMP: {
2270+ return (java.sql.Timestamp)value;
2271+ }
2272+ case java.sql.Types.TIME: {
2273+ long sec = ((java.sql.Time)value).getTime();
2274+ return new java.sql.Timestamp(sec);
2275+ }
2276+ case java.sql.Types.DATE: {
2277+ long sec = ((java.sql.Date)value).getTime();
2278+ return new java.sql.Timestamp(sec);
2279+ }
2280+ case java.sql.Types.CHAR:
2281+ case java.sql.Types.VARCHAR:
2282+ case java.sql.Types.LONGVARCHAR: {
2283+ try {
2284+ DateFormat tf = DateFormat.getTimeInstance();
2285+ return ((java.sql.Timestamp)(tf.parse(value.toString())));
2286+ } catch (ParseException ex) {
2287+ throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.timefail").toString(),
2288+ new Object[] {value.toString().trim(), columnIndex}));
2289+ }
2290+ }
2291+ default: {
2292+ throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.timefail").toString(),
2293+ new Object[] {value.toString().trim(), columnIndex}));
2294+ }
2295+ }
2296+ }
2297+
2298+ /**
2299+ * Retrieves the value of the designated column in the current row of this
2300+ * <code>CachedRowSetImpl</code> object as a <code>java.io.InputStream</code>
2301+ * object.
2302+ *
2303+ * A column value can be retrieved as a stream of ASCII characters
2304+ * and then read in chunks from the stream. This method is particularly
2305+ * suitable for retrieving large <code>LONGVARCHAR</code> values. The JDBC
2306+ * driver will do any necessary conversion from the database format into ASCII.
2307+ *
2308+ * <P><B>Note:</B> All the data in the returned stream must be
2309+ * read prior to getting the value of any other column. The next
2310+ * call to a get method implicitly closes the stream. . Also, a
2311+ * stream may return <code>0</code> for <code>CachedRowSetImpl.available()</code>
2312+ * whether there is data available or not.
2313+ *
2314+ * @param columnIndex the first column is <code>1</code>, the second
2315+ * is <code>2</code>, and so on; must be <code>1</code> or larger
2316+ * and equal to or less than the number of columns in this rowset
2317+ * @return a Java input stream that delivers the database column value
2318+ * as a stream of one-byte ASCII characters. If the value is SQL
2319+ * <code>NULL</code>, the result is <code>null</code>.
2320+ * @throws SQLException if (1) the given column index is out of bounds,
2321+ * (2) the cursor is not on one of this rowset's rows or its
2322+ * insert row, or (3) the designated column does not store an
2323+ * SQL <code>CHAR, VARCHAR</code>, <code><b>LONGVARCHAR</b></code>
2324+ * <code>BINARY, VARBINARY</code> or <code>LONGVARBINARY</code> value. The
2325+ * bold SQL type designates the recommended return types that this method is
2326+ * used to retrieve.
2327+ * @see #getAsciiStream(String)
2328+ */
2329+ public java.io.InputStream getAsciiStream(int columnIndex) throws SQLException {
2330+ Object value;
2331+
2332+ // always free an old stream
2333+ asciiStream = null;
2334+
2335+ // sanity check
2336+ checkIndex(columnIndex);
2337+ //make sure the cursor is on a vlid row
2338+ checkCursor();
2339+
2340+ value = getCurrentRow().getColumnObject(columnIndex);
2341+ if (value == null) {
2342+ lastValueNull = true;
2343+ return null;
2344+ }
2345+
2346+ try {
2347+ if (isString(RowSetMD.getColumnType(columnIndex))) {
2348+ asciiStream = new ByteArrayInputStream(((String)value).getBytes("ASCII"));
2349+ } else {
2350+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.dtypemismt").toString());
2351+ }
2352+ } catch (java.io.UnsupportedEncodingException ex) {
2353+ throw new SQLException(ex.getMessage());
2354+ }
2355+
2356+ return (java.io.InputStream)asciiStream;
2357+ }
2358+
2359+ /**
2360+ * A column value can be retrieved as a stream of Unicode characters
2361+ * and then read in chunks from the stream. This method is particularly
2362+ * suitable for retrieving large LONGVARCHAR values. The JDBC driver will
2363+ * do any necessary conversion from the database format into Unicode.
2364+ *
2365+ * <P><B>Note:</B> All the data in the returned stream must be
2366+ * read prior to getting the value of any other column. The next
2367+ * call to a get method implicitly closes the stream. . Also, a
2368+ * stream may return 0 for available() whether there is data
2369+ * available or not.
2370+ *
2371+ * @param columnIndex the first column is <code>1</code>, the second
2372+ * is <code>2</code>, and so on; must be <code>1</code> or larger
2373+ * and equal to or less than the number of columns in this rowset
2374+ * @return a Java input stream that delivers the database column value
2375+ * as a stream of two byte Unicode characters. If the value is SQL NULL
2376+ * then the result is null.
2377+ * @throws SQLException if an error occurs
2378+ * @deprecated
2379+ */
2380+ public java.io.InputStream getUnicodeStream(int columnIndex) throws SQLException {
2381+ // always free an old stream
2382+ unicodeStream = null;
2383+
2384+ // sanity check.
2385+ checkIndex(columnIndex);
2386+ // make sure the cursor is on a valid row
2387+ checkCursor();
2388+
2389+ if (isBinary(RowSetMD.getColumnType(columnIndex)) == false &&
2390+ isString(RowSetMD.getColumnType(columnIndex)) == false) {
2391+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.dtypemismt").toString());
2392+ }
2393+
2394+ Object value = getCurrentRow().getColumnObject(columnIndex);
2395+ if (value == null) {
2396+ lastValueNull = true;
2397+ return null;
2398+ }
2399+
2400+ unicodeStream = new StringBufferInputStream(value.toString());
2401+
2402+ return (java.io.InputStream)unicodeStream;
2403+ }
2404+
2405+ /**
2406+ * Retrieves the value of the designated column in the current row of this
2407+ * <code>CachedRowSetImpl</code> object as a <code>java.io.InputStream</code>
2408+ * object.
2409+ * <P>
2410+ * A column value can be retrieved as a stream of uninterpreted bytes
2411+ * and then read in chunks from the stream. This method is particularly
2412+ * suitable for retrieving large <code>LONGVARBINARY</code> values.
2413+ *
2414+ * <P><B>Note:</B> All the data in the returned stream must be
2415+ * read prior to getting the value of any other column. The next
2416+ * call to a get method implicitly closes the stream. Also, a
2417+ * stream may return <code>0</code> for
2418+ * <code>CachedRowSetImpl.available()</code> whether there is data
2419+ * available or not.
2420+ *
2421+ * @param columnIndex the first column is <code>1</code>, the second
2422+ * is <code>2</code>, and so on; must be <code>1</code> or larger
2423+ * and equal to or less than the number of columns in the rowset
2424+ * @return a Java input stream that delivers the database column value
2425+ * as a stream of uninterpreted bytes. If the value is SQL <code>NULL</code>
2426+ * then the result is <code>null</code>.
2427+ * @throws SQLException if (1) the given column index is out of bounds,
2428+ * (2) the cursor is not on one of this rowset's rows or its
2429+ * insert row, or (3) the designated column does not store an
2430+ * SQL <code>BINARY, VARBINARY</code> or <code><b>LONGVARBINARY</b></code>
2431+ * The bold type indicates the SQL type that this method is recommened
2432+ * to retrieve.
2433+ * @see #getBinaryStream(String)
2434+ */
2435+ public java.io.InputStream getBinaryStream(int columnIndex) throws SQLException {
2436+
2437+ // always free an old stream
2438+ binaryStream = null;
2439+
2440+ // sanity check.
2441+ checkIndex(columnIndex);
2442+ // make sure the cursor is on a valid row
2443+ checkCursor();
2444+
2445+ if (isBinary(RowSetMD.getColumnType(columnIndex)) == false) {
2446+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.dtypemismt").toString());
2447+ }
2448+
2449+ Object value = getCurrentRow().getColumnObject(columnIndex);
2450+ if (value == null) {
2451+ lastValueNull = true;
2452+ return null;
2453+ }
2454+
2455+ binaryStream = new ByteArrayInputStream((byte[])value);
2456+
2457+ return (java.io.InputStream)binaryStream;
2458+
2459+ }
2460+
2461+
2462+ // Methods for accessing results by column name
2463+
2464+ /**
2465+ * Retrieves the value stored in the designated column
2466+ * of the current row as a <code>String</code> object.
2467+ *
2468+ * @param columnName a <code>String</code> object giving the SQL name of
2469+ * a column in this <code>CachedRowSetImpl</code> object
2470+ * @return the column value; if the value is SQL <code>NULL</code>,
2471+ * the result is <code>null</code>
2472+ * @throws SQLException if (1) the given column name is not the name of
2473+ * a column in this rowset, (2) the cursor is not on one of
2474+ * this rowset's rows or its insert row, or (3) the designated
2475+ * column does not store an SQL <code>TINYINT, SMALLINT, INTEGER
2476+ * BIGINT, REAL, FLOAT, DOUBLE, DECIMAL, NUMERIC, BIT, <b>CHAR</b>,
2477+ * <b>VARCHAR</b></code> or <code>LONGVARCHAR<</code> value. The bold SQL type
2478+ * designates the recommended return type.
2479+ */
2480+ public String getString(String columnName) throws SQLException {
2481+ return getString(getColIdxByName(columnName));
2482+ }
2483+
2484+ /**
2485+ * Retrieves the value stored in the designated column
2486+ * of the current row as a <code>boolean</code> value.
2487+ *
2488+ * @param columnName a <code>String</code> object giving the SQL name of
2489+ * a column in this <code>CachedRowSetImpl</code> object
2490+ * @return the column value as a <code>boolean</code> in the Java programming
2491+ * language; if the value is SQL <code>NULL</code>,
2492+ * the result is <code>false</code>
2493+ * @throws SQLException if (1) the given column name is not the name of
2494+ * a column in this rowset, (2) the cursor is not on one of
2495+ * this rowset's rows or its insert row, or (3) the designated
2496+ * column does not store an SQL <code>BOOLEAN</code> value
2497+ * @see #getBoolean(int)
2498+ */
2499+ public boolean getBoolean(String columnName) throws SQLException {
2500+ return getBoolean(getColIdxByName(columnName));
2501+ }
2502+
2503+ /**
2504+ * Retrieves the value stored in the designated column
2505+ * of the current row as a <code>byte</code> value.
2506+ *
2507+ * @param columnName a <code>String</code> object giving the SQL name of
2508+ * a column in this <code>CachedRowSetImpl</code> object
2509+ * @return the column value as a <code>byte</code> in the Java programming
2510+ * language; if the value is SQL <code>NULL</code>, the result is <code>0</code>
2511+ * @throws SQLException if (1) the given column name is not the name of
2512+ * a column in this rowset, (2) the cursor is not on one of
2513+ * this rowset's rows or its insert row, or (3) the designated
2514+ * column does not store an SQL <code><B>TINYINT</B>, SMALLINT, INTEGER,
2515+ * BIGINT, REAL, FLOAT, DOUBLE, DECIMAL, NUMERIC, BIT, CHAR,
2516+ * VARCHAR</code> or <code>LONGVARCHAR</code> value. The
2517+ * bold type designates the recommended return type
2518+ */
2519+ public byte getByte(String columnName) throws SQLException {
2520+ return getByte(getColIdxByName(columnName));
2521+ }
2522+
2523+ /**
2524+ * Retrieves the value stored in the designated column
2525+ * of the current row as a <code>short</code> value.
2526+ *
2527+ * @param columnName a <code>String</code> object giving the SQL name of
2528+ * a column in this <code>CachedRowSetImpl</code> object
2529+ * @return the column value; if the value is SQL <code>NULL</code>,
2530+ * the result is <code>0</code>
2531+ * @throws SQLException if (1) the given column name is not the name of
2532+ * a column in this rowset, (2) the cursor is not on one of
2533+ * this rowset's rows or its insert row, or (3) the designated
2534+ * column does not store an SQL <code>TINYINT, <b>SMALLINT</b>, INTEGER
2535+ * BIGINT, REAL, FLOAT, DOUBLE, DECIMAL, NUMERIC, BIT, CHAR,
2536+ * VARCHAR</code> or <code>LONGVARCHAR</code> value. The bold SQL type
2537+ * designates the recommended return type.
2538+ * @see #getShort(int)
2539+ */
2540+ public short getShort(String columnName) throws SQLException {
2541+ return getShort(getColIdxByName(columnName));
2542+ }
2543+
2544+ /**
2545+ * Retrieves the value stored in the designated column
2546+ * of the current row as an <code>int</code> value.
2547+ *
2548+ * @param columnName a <code>String</code> object giving the SQL name of
2549+ * a column in this <code>CachedRowSetImpl</code> object
2550+ * @return the column value; if the value is SQL <code>NULL</code>,
2551+ * the result is <code>0</code>
2552+ * @throws SQLException if (1) the given column name is not the name
2553+ * of a column in this rowset,
2554+ * (2) the cursor is not on one of this rowset's rows or its
2555+ * insert row, or (3) the designated column does not store an
2556+ * SQL <code>TINYINT, SMALLINT, <b>INTEGER</b>, BIGINT, REAL
2557+ * FLOAT, DOUBLE, DECIMAL, NUMERIC, BIT, CHAR, VARCHAR</code>
2558+ * or <code>LONGVARCHAR</code> value. The bold SQL type designates the
2559+ * recommended return type.
2560+ */
2561+ public int getInt(String columnName) throws SQLException {
2562+ return getInt(getColIdxByName(columnName));
2563+ }
2564+
2565+ /**
2566+ * Retrieves the value stored in the designated column
2567+ * of the current row as a <code>long</code> value.
2568+ *
2569+ * @param columnName a <code>String</code> object giving the SQL name of
2570+ * a column in this <code>CachedRowSetImpl</code> object
2571+ * @return the column value; if the value is SQL <code>NULL</code>,
2572+ * the result is <code>0</code>
2573+ * @throws SQLException if (1) the given column name is not the name of
2574+ * a column in this rowset, (2) the cursor is not on one of
2575+ * this rowset's rows or its insert row, or (3) the designated
2576+ * column does not store an SQL <code>TINYINT, SMALLINT, INTEGER
2577+ * <b>BIGINT</b>, REAL, FLOAT, DOUBLE, DECIMAL, NUMERIC, BIT, CHAR,
2578+ * VARCHAR</code> or <code>LONGVARCHAR</code> value. The bold SQL type
2579+ * designates the recommended return type.
2580+ * @see #getLong(int)
2581+ */
2582+ public long getLong(String columnName) throws SQLException {
2583+ return getLong(getColIdxByName(columnName));
2584+ }
2585+
2586+ /**
2587+ * Retrieves the value stored in the designated column
2588+ * of the current row as a <code>float</code> value.
2589+ *
2590+ * @param columnName a <code>String</code> object giving the SQL name of
2591+ * a column in this <code>CachedRowSetImpl</code> object
2592+ * @return the column value; if the value is SQL <code>NULL</code>,
2593+ * the result is <code>0</code>
2594+ * @throws SQLException if (1) the given column name is not the name of
2595+ * a column in this rowset, (2) the cursor is not on one of
2596+ * this rowset's rows or its insert row, or (3) the designated
2597+ * column does not store an SQL <code>TINYINT, SMALLINT, INTEGER
2598+ * BIGINT, <b>REAL</b>, FLOAT, DOUBLE, DECIMAL, NUMERIC, BIT, CHAR,
2599+ * VARCHAR</code> or <code>LONGVARCHAR</code> value. The bold SQL type
2600+ * designates the recommended return type.
2601+ * @see #getFloat(String)
2602+ */
2603+ public float getFloat(String columnName) throws SQLException {
2604+ return getFloat(getColIdxByName(columnName));
2605+ }
2606+
2607+ /**
2608+ * Retrieves the value stored in the designated column
2609+ * of the current row of this <code>CachedRowSetImpl</code> object
2610+ * as a <code>double</code> value.
2611+ *
2612+ * @param columnName a <code>String</code> object giving the SQL name of
2613+ * a column in this <code>CachedRowSetImpl</code> object
2614+ * @return the column value; if the value is SQL <code>NULL</code>,
2615+ * the result is <code>0</code>
2616+ * @throws SQLException if (1) the given column name is not the name of
2617+ * a column in this rowset, (2) the cursor is not on one of
2618+ * this rowset's rows or its insert row, or (3) the designated
2619+ * column does not store an SQL <code>TINYINT, SMALLINT, INTEGER
2620+ * BIGINT, REAL, <b>FLOAT</b>, <b>DOUBLE</b>, DECIMAL, NUMERIC, BIT, CHAR,
2621+ * VARCHAR</code> or <code>LONGVARCHAR</code> value. The bold SQL type
2622+ * designates the recommended return types.
2623+ * @see #getDouble(int)
2624+ */
2625+ public double getDouble(String columnName) throws SQLException {
2626+ return getDouble(getColIdxByName(columnName));
2627+ }
2628+
2629+ /**
2630+ * Retrieves the value stored in the designated column
2631+ * of the current row as a <code>java.math.BigDecimal</code> object.
2632+ *
2633+ * @param columnName a <code>String</code> object giving the SQL name of
2634+ * a column in this <code>CachedRowSetImpl</code> object
2635+ * @param scale the number of digits to the right of the decimal point
2636+ * @return a java.math.BugDecimal object with <code><i>scale</i></code>
2637+ * number of digits to the right of the decimal point.
2638+ * @throws SQLException if (1) the given column name is not the name of
2639+ * a column in this rowset, (2) the cursor is not on one of
2640+ * this rowset's rows or its insert row, or (3) the designated
2641+ * column does not store an SQL <code>TINYINT, SMALLINT, INTEGER
2642+ * BIGINT, REAL, FLOAT, DOUBLE, <b>DECIMAL</b>, <b>NUMERIC</b>, BIT CHAR,
2643+ * VARCHAR</code> or <code>LONGVARCHAR</code> value. The bold SQL type
2644+ * designates the recommended return type that this method is used to
2645+ * retrieve.
2646+ * @deprecated Use the <code>getBigDecimal(String columnName)</code>
2647+ * method instead
2648+ */
2649+ public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException {
2650+ return getBigDecimal(getColIdxByName(columnName), scale);
2651+ }
2652+
2653+ /**
2654+ * Retrieves the value stored in the designated column
2655+ * of the current row as a <code>byte</code> array.
2656+ * The bytes represent the raw values returned by the driver.
2657+ *
2658+ * @param columnName a <code>String</code> object giving the SQL name of
2659+ * a column in this <code>CachedRowSetImpl</code> object
2660+ * @return the column value as a <code>byte</code> array in the Java programming
2661+ * language; if the value is SQL <code>NULL</code>, the result is <code>null</code>
2662+ * @throws SQLException if (1) the given column name is not the name of
2663+ * a column in this rowset, (2) the cursor is not on one of
2664+ * this rowset's rows or its insert row, or (3) the designated
2665+ * column does not store an SQL <code><b>BINARY</b>, <b>VARBINARY</b>
2666+ * </code> or <code>LONGVARBINARY</code> values
2667+ * The bold SQL type designates the recommended return type.
2668+ * @see #getBytes(int)
2669+ */
2670+ public byte[] getBytes(String columnName) throws SQLException {
2671+ return getBytes(getColIdxByName(columnName));
2672+ }
2673+
2674+ /**
2675+ * Retrieves the value stored in the designated column
2676+ * of the current row as a <code>java.sql.Date</code> object.
2677+ *
2678+ * @param columnName a <code>String</code> object giving the SQL name of
2679+ * a column in this <code>CachedRowSetImpl</code> object
2680+ * @return the column value; if the value is SQL <code>NULL</code>,
2681+ * the result is <code>null</code>
2682+ * @throws SQLException if (1) the given column name is not the name of
2683+ * a column in this rowset, (2) the cursor is not on one of
2684+ * this rowset's rows or its insert row, or (3) the designated
2685+ * column does not store an SQL <code>DATE</code> or
2686+ * <code>TIMESTAMP</code> value
2687+ */
2688+ public java.sql.Date getDate(String columnName) throws SQLException {
2689+ return getDate(getColIdxByName(columnName));
2690+ }
2691+
2692+ /**
2693+ * Retrieves the value stored in the designated column
2694+ * of the current row as a <code>java.sql.Time</code> object.
2695+ *
2696+ * @param columnName a <code>String</code> object giving the SQL name of
2697+ * a column in this <code>CachedRowSetImpl</code> object
2698+ * @return the column value; if the value is SQL <code>NULL</code>,
2699+ * the result is <code>null</code>
2700+ * @throws SQLException if the given column name does not match one of
2701+ * this rowset's column names or the cursor is not on one of
2702+ * this rowset's rows or its insert row
2703+ */
2704+ public java.sql.Time getTime(String columnName) throws SQLException {
2705+ return getTime(getColIdxByName(columnName));
2706+ }
2707+
2708+ /**
2709+ * Retrieves the value stored in the designated column
2710+ * of the current row as a <code>java.sql.Timestamp</code> object.
2711+ *
2712+ * @param columnName a <code>String</code> object giving the SQL name of
2713+ * a column in this <code>CachedRowSetImpl</code> object
2714+ * @return the column value; if the value is SQL <code>NULL</code>,
2715+ * the result is <code>null</code>
2716+ * @throws SQLException if the given column name does not match one of
2717+ * this rowset's column names or the cursor is not on one of
2718+ * this rowset's rows or its insert row
2719+ */
2720+ public java.sql.Timestamp getTimestamp(String columnName) throws SQLException {
2721+ return getTimestamp(getColIdxByName(columnName));
2722+ }
2723+
2724+ /**
2725+ * Retrieves the value of the designated column in the current row of this
2726+ * <code>CachedRowSetImpl</code> object as a <code>java.io.InputStream</code>
2727+ * object.
2728+ *
2729+ * A column value can be retrieved as a stream of ASCII characters
2730+ * and then read in chunks from the stream. This method is particularly
2731+ * suitable for retrieving large <code>LONGVARCHAR</code> values. The
2732+ * <code>SyncProvider</code> will rely on the JDBC driver to do any necessary
2733+ * conversion from the database format into ASCII format.
2734+ *
2735+ * <P><B>Note:</B> All the data in the returned stream must
2736+ * be read prior to getting the value of any other column. The
2737+ * next call to a <code>getXXX</code> method implicitly closes the stream.
2738+ *
2739+ * @param columnName a <code>String</code> object giving the SQL name of
2740+ * a column in this <code>CachedRowSetImpl</code> object
2741+ * @return a Java input stream that delivers the database column value
2742+ * as a stream of one-byte ASCII characters. If the value is SQL
2743+ * <code>NULL</code>, the result is <code>null</code>.
2744+ * @throws SQLException if (1) the given column name is not the name of
2745+ * a column in this rowset
2746+ * (2) the cursor is not on one of this rowset's rows or its
2747+ * insert row, or (3) the designated column does not store an
2748+ * SQL <code>CHAR, VARCHAR</code>, <code><b>LONGVARCHAR</b></code>
2749+ * <code>BINARY, VARBINARY</code> or <code>LONGVARBINARY</code> value. The
2750+ * bold SQL type designates the recommended return types that this method is
2751+ * used to retrieve.
2752+ * @see #getAsciiStream(int)
2753+ */
2754+ public java.io.InputStream getAsciiStream(String columnName) throws SQLException {
2755+ return getAsciiStream(getColIdxByName(columnName));
2756+
2757+ }
2758+
2759+ /**
2760+ * A column value can be retrieved as a stream of Unicode characters
2761+ * and then read in chunks from the stream. This method is particularly
2762+ * suitable for retrieving large <code>LONGVARCHAR</code> values.
2763+ * The JDBC driver will do any necessary conversion from the database
2764+ * format into Unicode.
2765+ *
2766+ * <P><B>Note:</B> All the data in the returned stream must
2767+ * be read prior to getting the value of any other column. The
2768+ * next call to a <code>getXXX</code> method implicitly closes the stream.
2769+ *
2770+ * @param columnName a <code>String</code> object giving the SQL name of
2771+ * a column in this <code>CachedRowSetImpl</code> object
2772+ * @return a Java input stream that delivers the database column value
2773+ * as a stream of two-byte Unicode characters. If the value is
2774+ * SQL <code>NULL</code>, the result is <code>null</code>.
2775+ * @throws SQLException if the given column name does not match one of
2776+ * this rowset's column names or the cursor is not on one of
2777+ * this rowset's rows or its insert row
2778+ * @deprecated use the method <code>getCharacterStream</code> instead
2779+ */
2780+ public java.io.InputStream getUnicodeStream(String columnName) throws SQLException {
2781+ return getUnicodeStream(getColIdxByName(columnName));
2782+ }
2783+
2784+ /**
2785+ * Retrieves the value of the designated column in the current row of this
2786+ * <code>CachedRowSetImpl</code> object as a <code>java.io.InputStream</code>
2787+ * object.
2788+ * <P>
2789+ * A column value can be retrieved as a stream of uninterpreted bytes
2790+ * and then read in chunks from the stream. This method is particularly
2791+ * suitable for retrieving large <code>LONGVARBINARY</code> values.
2792+ *
2793+ * <P><B>Note:</B> All the data in the returned stream must be
2794+ * read prior to getting the value of any other column. The next
2795+ * call to a get method implicitly closes the stream. Also, a
2796+ * stream may return <code>0</code> for <code>CachedRowSetImpl.available()</code>
2797+ * whether there is data available or not.
2798+ *
2799+ * @param columnName a <code>String</code> object giving the SQL name of
2800+ * a column in this <code>CachedRowSetImpl</code> object
2801+ * @return a Java input stream that delivers the database column value
2802+ * as a stream of uninterpreted bytes. If the value is SQL
2803+ * <code>NULL</code>, the result is <code>null</code>.
2804+ * @throws SQLException if (1) the given column name is unknown,
2805+ * (2) the cursor is not on one of this rowset's rows or its
2806+ * insert row, or (3) the designated column does not store an
2807+ * SQL <code>BINARY, VARBINARY</code> or <code><b>LONGVARBINARY</b></code>
2808+ * The bold type indicates the SQL type that this method is recommened
2809+ * to retrieve.
2810+ * @see #getBinaryStream(int)
2811+ *
2812+ */
2813+ public java.io.InputStream getBinaryStream(String columnName) throws SQLException {
2814+ return getBinaryStream(getColIdxByName(columnName));
2815+ }
2816+
2817+
2818+ // Advanced features:
2819+
2820+ /**
2821+ * The first warning reported by calls on this <code>CachedRowSetImpl</code>
2822+ * object is returned. Subsequent <code>CachedRowSetImpl</code> warnings will
2823+ * be chained to this <code>SQLWarning</code>.
2824+ *
2825+ * <P>The warning chain is automatically cleared each time a new
2826+ * row is read.
2827+ *
2828+ * <P><B>Note:</B> This warning chain only covers warnings caused
2829+ * by <code>ResultSet</code> methods. Any warning caused by statement
2830+ * methods (such as reading OUT parameters) will be chained on the
2831+ * <code>Statement</code> object.
2832+ *
2833+ * @return the first SQLWarning or null
2834+ */
2835+ public SQLWarning getWarnings() {
2836+ return sqlwarn;
2837+ }
2838+
2839+ /**
2840+ * Clears all the warnings reporeted for the <code>CachedRowSetImpl</code>
2841+ * object. After a call to this method, the <code>getWarnings</code> method
2842+ * returns <code>null</code> until a new warning is reported for this
2843+ * <code>CachedRowSetImpl</code> object.
2844+ */
2845+ public void clearWarnings() {
2846+ sqlwarn = null;
2847+ }
2848+
2849+ /**
2850+ * Retrieves the name of the SQL cursor used by this
2851+ * <code>CachedRowSetImpl</code> object.
2852+ *
2853+ * <P>In SQL, a result table is retrieved through a cursor that is
2854+ * named. The current row of a <code>ResultSet</code> can be updated or deleted
2855+ * using a positioned update/delete statement that references the
2856+ * cursor name. To ensure that the cursor has the proper isolation
2857+ * level to support an update operation, the cursor's <code>SELECT</code>
2858+ * statement should be of the form <code>select for update</code>.
2859+ * If the <code>for update</code> clause
2860+ * is omitted, positioned updates may fail.
2861+ *
2862+ * <P>JDBC supports this SQL feature by providing the name of the
2863+ * SQL cursor used by a <code>ResultSet</code> object. The current row
2864+ * of a result set is also the current row of this SQL cursor.
2865+ *
2866+ * <P><B>Note:</B> If positioned updates are not supported, an
2867+ * <code>SQLException</code> is thrown.
2868+ *
2869+ * @return the SQL cursor name for this <code>CachedRowSetImpl</code> object's
2870+ * cursor
2871+ * @throws SQLException if an error occurs
2872+ */
2873+ public String getCursorName() throws SQLException {
2874+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.posupdate").toString());
2875+ }
2876+
2877+ /**
2878+ * Retrieves a <code>ResultSetMetaData</code> object instance that
2879+ * contains information about the <code>CachedRowSet</code> object.
2880+ * However, applications should cast the returned object to a
2881+ * <code>RowSetMetaData</code> interface implementation. In the
2882+ * reference implementation, this cast can be done on the
2883+ * <code>RowSetMetaDataImpl</code> class.
2884+ * <P>
2885+ * For example:
2886+ * <pre>
2887+ * CachedRowSet crs = new CachedRowSetImpl();
2888+ * RowSetMetaDataImpl metaData =
2889+ * (RowSetMetaDataImpl)crs.getMetaData();
2890+ * // Set the number of columns in the RowSet object for
2891+ * // which this RowSetMetaDataImpl object was created to the
2892+ * // given number.
2893+ * metaData.setColumnCount(3);
2894+ * crs.setMetaData(metaData);
2895+ * </pre>
2896+ *
2897+ * @return the <code>ResultSetMetaData</code> object that describes this
2898+ * <code>CachedRowSetImpl</code> object's columns
2899+ * @throws SQLException if an error occurs in generating the RowSet
2900+ * meta data; or if the <code>CachedRowSetImpl</code> is empty.
2901+ * @see javax.sql.RowSetMetaData
2902+ */
2903+ public ResultSetMetaData getMetaData() throws SQLException {
2904+ return (ResultSetMetaData)RowSetMD;
2905+ }
2906+
2907+
2908+ /**
2909+ * Retrieves the value of the designated column in the current row
2910+ * of this <code>CachedRowSetImpl</code> object as an
2911+ * <code>Object</code> value.
2912+ * <P>
2913+ * The type of the <code>Object</code> will be the default
2914+ * Java object type corresponding to the column's SQL type,
2915+ * following the mapping for built-in types specified in the JDBC 3.0
2916+ * specification.
2917+ * <P>
2918+ * This method may also be used to read datatabase-specific
2919+ * abstract data types.
2920+ * <P>
2921+ * This implementation of the method <code>getObject</code> extends its
2922+ * behavior so that it gets the attributes of an SQL structured type
2923+ * as an array of <code>Object</code> values. This method also custom
2924+ * maps SQL user-defined types to classes in the Java programming language.
2925+ * When the specified column contains
2926+ * a structured or distinct value, the behavior of this method is as
2927+ * if it were a call to the method <code>getObject(columnIndex,
2928+ * this.getStatement().getConnection().getTypeMap())</code>.
2929+ *
2930+ * @param columnIndex the first column is <code>1</code>, the second
2931+ * is <code>2</code>, and so on; must be <code>1</code> or larger
2932+ * and equal to or less than the number of columns in the rowset
2933+ * @return a <code>java.lang.Object</code> holding the column value;
2934+ * if the value is SQL <code>NULL</code>, the result is <code>null</code>
2935+ * @throws SQLException if the given column index is out of bounds,
2936+ * the cursor is not on a valid row, or there is a problem getting
2937+ * the <code>Class</code> object for a custom mapping
2938+ * @see #getObject(String)
2939+ */
2940+ public Object getObject(int columnIndex) throws SQLException {
2941+ Object value;
2942+ Map<String, Class<?>> map;
2943+
2944+ // sanity check.
2945+ checkIndex(columnIndex);
2946+ // make sure the cursor is on a valid row
2947+ checkCursor();
2948+
2949+ setLastValueNull(false);
2950+ value = getCurrentRow().getColumnObject(columnIndex);
2951+
2952+ // check for SQL NULL
2953+ if (value == null) {
2954+ setLastValueNull(true);
2955+ return null;
2956+ }
2957+ if (value instanceof Struct) {
2958+ Struct s = (Struct)value;
2959+ map = getTypeMap();
2960+ // look up the class in the map
2961+ Class c = (Class)map.get(s.getSQLTypeName());
2962+ if (c != null) {
2963+ // create new instance of the class
2964+ SQLData obj = null;
2965+ try {
2966+ obj = (SQLData)c.newInstance();
2967+ } catch (java.lang.InstantiationException ex) {
2968+ throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.unableins").toString(),
2969+ ex.getMessage()));
2970+ } catch (java.lang.IllegalAccessException ex) {
2971+ throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.unableins").toString(),
2972+ ex.getMessage()));
2973+ }
2974+ // get the attributes from the struct
2975+ Object attribs[] = s.getAttributes(map);
2976+ // create the SQLInput "stream"
2977+ SQLInputImpl sqlInput = new SQLInputImpl(attribs, map);
2978+ // read the values...
2979+ obj.readSQL(sqlInput, s.getSQLTypeName());
2980+ return (Object)obj;
2981+ }
2982+ }
2983+ return value;
2984+ }
2985+
2986+ /**
2987+ * Retrieves the value of the designated column in the current row
2988+ * of this <code>CachedRowSetImpl</code> object as an
2989+ * <code>Object</code> value.
2990+ * <P>
2991+ * The type of the <code>Object</code> will be the default
2992+ * Java object type corresponding to the column's SQL type,
2993+ * following the mapping for built-in types specified in the JDBC 3.0
2994+ * specification.
2995+ * <P>
2996+ * This method may also be used to read datatabase-specific
2997+ * abstract data types.
2998+ * <P>
2999+ * This implementation of the method <code>getObject</code> extends its
3000+ * behavior so that it gets the attributes of an SQL structured type
3001+ * as an array of <code>Object</code> values. This method also custom
3002+ * maps SQL user-defined types to classes
3003+ * in the Java programming language. When the specified column contains
3004+ * a structured or distinct value, the behavior of this method is as
3005+ * if it were a call to the method <code>getObject(columnIndex,
3006+ * this.getStatement().getConnection().getTypeMap())</code>.
3007+ *
3008+ * @param columnName a <code>String</code> object that must match the
3009+ * SQL name of a column in this rowset, ignoring case
3010+ * @return a <code>java.lang.Object</code> holding the column value;
3011+ * if the value is SQL <code>NULL</code>, the result is <code>null</code>
3012+ * @throws SQLException if (1) the given column name does not match one of
3013+ * this rowset's column names, (2) the cursor is not
3014+ * on a valid row, or (3) there is a problem getting
3015+ * the <code>Class</code> object for a custom mapping
3016+ * @see #getObject(int)
3017+ */
3018+ public Object getObject(String columnName) throws SQLException {
3019+ return getObject(getColIdxByName(columnName));
3020+ }
3021+
3022+ //----------------------------------------------------------------
3023+
3024+ /**
3025+ * Maps the given column name for one of this <code>CachedRowSetImpl</code>
3026+ * object's columns to its column number.
3027+ *
3028+ * @param columnName a <code>String</code> object that must match the
3029+ * SQL name of a column in this rowset, ignoring case
3030+ * @return the column index of the given column name
3031+ * @throws SQLException if the given column name does not match one
3032+ * of this rowset's column names
3033+ */
3034+ public int findColumn(String columnName) throws SQLException {
3035+ return getColIdxByName(columnName);
3036+ }
3037+
3038+
3039+ //--------------------------JDBC 2.0-----------------------------------
3040+
3041+ //---------------------------------------------------------------------
3042+ // Getter's and Setter's
3043+ //---------------------------------------------------------------------
3044+
3045+ /**
3046+ * Retrieves the value stored in the designated column
3047+ * of the current row as a <code>java.io.Reader</code> object.
3048+ *
3049+ * <P><B>Note:</B> All the data in the returned stream must
3050+ * be read prior to getting the value of any other column. The
3051+ * next call to a <code>getXXX</code> method implicitly closes the stream.
3052+ *
3053+ * @param columnIndex the first column is <code>1</code>, the second
3054+ * is <code>2</code>, and so on; must be <code>1</code> or larger
3055+ * and equal to or less than the number of columns in the rowset
3056+ * @return a Java character stream that delivers the database column value
3057+ * as a stream of two-byte unicode characters in a
3058+ * <code>java.io.Reader</code> object. If the value is
3059+ * SQL <code>NULL</code>, the result is <code>null</code>.
3060+ * @throws SQLException if (1) the given column index is out of bounds,
3061+ * (2) the cursor is not on one of this rowset's rows or its
3062+ * insert row, or (3) the designated column does not store an
3063+ * SQL <code>CHAR, VARCHAR, <b>LONGVARCHAR</b>, BINARY, VARBINARY</code> or
3064+ * <code>LONGVARBINARY</code> value.
3065+ * The bold SQL type designates the recommended return type.
3066+ * @see #getCharacterStream(String)
3067+ */
3068+ public java.io.Reader getCharacterStream(int columnIndex) throws SQLException{
3069+
3070+ // sanity check.
3071+ checkIndex(columnIndex);
3072+ // make sure the cursor is on a valid row
3073+ checkCursor();
3074+
3075+ if (isBinary(RowSetMD.getColumnType(columnIndex))) {
3076+ Object value = getCurrentRow().getColumnObject(columnIndex);
3077+ if (value == null) {
3078+ lastValueNull = true;
3079+ return null;
3080+ }
3081+ charStream = new InputStreamReader
3082+ (new ByteArrayInputStream((byte[])value));
3083+ } else if (isString(RowSetMD.getColumnType(columnIndex))) {
3084+ Object value = getCurrentRow().getColumnObject(columnIndex);
3085+ if (value == null) {
3086+ lastValueNull = true;
3087+ return null;
3088+ }
3089+ charStream = new StringReader(value.toString());
3090+ } else {
3091+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.dtypemismt").toString());
3092+ }
3093+
3094+ return (java.io.Reader)charStream;
3095+ }
3096+
3097+ /**
3098+ * Retrieves the value stored in the designated column
3099+ * of the current row as a <code>java.io.Reader</code> object.
3100+ *
3101+ * <P><B>Note:</B> All the data in the returned stream must
3102+ * be read prior to getting the value of any other column. The
3103+ * next call to a <code>getXXX</code> method implicitly closes the stream.
3104+ *
3105+ * @param columnName a <code>String</code> object giving the SQL name of
3106+ * a column in this <code>CachedRowSetImpl</code> object
3107+ * @return a Java input stream that delivers the database column value
3108+ * as a stream of two-byte Unicode characters. If the value is
3109+ * SQL <code>NULL</code>, the result is <code>null</code>.
3110+ * @throws SQLException if (1) the given column name is not the name of
3111+ * a column in this rowset, (2) the cursor is not on one of
3112+ * this rowset's rows or its insert row, or (3) the designated
3113+ * column does not store an SQL <code>CHAR, VARCHAR, <b>LONGVARCHAR</b>,
3114+ * BINARY, VARYBINARY</code> or <code>LONGVARBINARY</code> value.
3115+ * The bold SQL type designates the recommended return type.
3116+ */
3117+ public java.io.Reader getCharacterStream(String columnName) throws SQLException {
3118+ return getCharacterStream(getColIdxByName(columnName));
3119+ }
3120+
3121+ /**
3122+ * Retrieves the value of the designated column in the current row
3123+ * of this <code>CachedRowSetImpl</code> object as a
3124+ * <code>java.math.BigDecimal</code> object.
3125+ *
3126+ * @param columnIndex the first column is <code>1</code>, the second
3127+ * is <code>2</code>, and so on; must be <code>1</code> or larger
3128+ * and equal to or less than the number of columns in the rowset
3129+ * @return a <code>java.math.BigDecimal</code> value with full precision;
3130+ * if the value is SQL <code>NULL</code>, the result is <code>null</code>
3131+ * @throws SQLException if (1) the given column index is out of bounds,
3132+ * (2) the cursor is not on one of this rowset's rows or its
3133+ * insert row, or (3) the designated column does not store an
3134+ * SQL <code>TINYINT, SMALLINT, INTEGER, BIGINT, REAL,
3135+ * FLOAT, DOUBLE, <b>DECIMAL</b>, <b>NUMERIC</b>, BIT, CHAR, VARCHAR</code>
3136+ * or <code>LONGVARCHAR</code> value. The bold SQL type designates the
3137+ * recommended return types that this method is used to retrieve.
3138+ * @see #getBigDecimal(String)
3139+ */
3140+ public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
3141+ Object value;
3142+
3143+ // sanity check.
3144+ checkIndex(columnIndex);
3145+ // make sure the cursor is on a valid row
3146+ checkCursor();
3147+
3148+ setLastValueNull(false);
3149+ value = getCurrentRow().getColumnObject(columnIndex);
3150+
3151+ // check for SQL NULL
3152+ if (value == null) {
3153+ setLastValueNull(true);
3154+ return null;
3155+ }
3156+ try {
3157+ return (new BigDecimal(value.toString().trim()));
3158+ } catch (NumberFormatException ex) {
3159+ throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.doublefail").toString(),
3160+ new Object[] {value.toString().trim(), columnIndex}));
3161+ }
3162+ }
3163+
3164+ /**
3165+ * Retrieves the value of the designated column in the current row
3166+ * of this <code>CachedRowSetImpl</code> object as a
3167+ * <code>java.math.BigDecimal</code> object.
3168+ *
3169+ * @param columnName a <code>String</code> object that must match the
3170+ * SQL name of a column in this rowset, ignoring case
3171+ * @return a <code>java.math.BigDecimal</code> value with full precision;
3172+ * if the value is SQL <code>NULL</code>, the result is <code>null</code>
3173+ * @throws SQLException if (1) the given column name is not the name of
3174+ * a column in this rowset, (2) the cursor is not on one of
3175+ * this rowset's rows or its insert row, or (3) the designated
3176+ * column does not store an SQL <code>TINYINT, SMALLINT, INTEGER
3177+ * BIGINT, REAL, FLOAT, DOUBLE, <b>DECIMAL</b>, <b>NUMERIC</b>, BIT CHAR,
3178+ * VARCHAR</code> or <code>LONGVARCHAR</code> value. The bold SQL type
3179+ * designates the recommended return type that this method is used to
3180+ * retrieve
3181+ * @see #getBigDecimal(int)
3182+ */
3183+ public BigDecimal getBigDecimal(String columnName) throws SQLException {
3184+ return getBigDecimal(getColIdxByName(columnName));
3185+ }
3186+
3187+ //---------------------------------------------------------------------
3188+ // Traversal/Positioning
3189+ //---------------------------------------------------------------------
3190+
3191+ /**
3192+ * Returns the number of rows in this <code>CachedRowSetImpl</code> object.
3193+ *
3194+ * @return number of rows in the rowset
3195+ */
3196+ public int size() {
3197+ return numRows;
3198+ }
3199+
3200+ /**
3201+ * Indicates whether the cursor is before the first row in this
3202+ * <code>CachedRowSetImpl</code> object.
3203+ *
3204+ * @return <code>true</code> if the cursor is before the first row;
3205+ * <code>false</code> otherwise or if the rowset contains no rows
3206+ * @throws SQLException if an error occurs
3207+ */
3208+ public boolean isBeforeFirst() throws SQLException {
3209+ if (cursorPos == 0 && numRows > 0) {
3210+ return true;
3211+ } else {
3212+ return false;
3213+ }
3214+ }
3215+
3216+ /**
3217+ * Indicates whether the cursor is after the last row in this
3218+ * <code>CachedRowSetImpl</code> object.
3219+ *
3220+ * @return <code>true</code> if the cursor is after the last row;
3221+ * <code>false</code> otherwise or if the rowset contains no rows
3222+ * @throws SQLException if an error occurs
3223+ */
3224+ public boolean isAfterLast() throws SQLException {
3225+ if (cursorPos == numRows+1 && numRows > 0) {
3226+ return true;
3227+ } else {
3228+ return false;
3229+ }
3230+ }
3231+
3232+ /**
3233+ * Indicates whether the cursor is on the first row in this
3234+ * <code>CachedRowSetImpl</code> object.
3235+ *
3236+ * @return <code>true</code> if the cursor is on the first row;
3237+ * <code>false</code> otherwise or if the rowset contains no rows
3238+ * @throws SQLException if an error occurs
3239+ */
3240+ public boolean isFirst() throws SQLException {
3241+ // this becomes nasty because of deletes.
3242+ int saveCursorPos = cursorPos;
3243+ int saveAbsoluteCursorPos = absolutePos;
3244+ internalFirst();
3245+ if (cursorPos == saveCursorPos) {
3246+ return true;
3247+ } else {
3248+ cursorPos = saveCursorPos;
3249+ absolutePos = saveAbsoluteCursorPos;
3250+ return false;
3251+ }
3252+ }
3253+
3254+ /**
3255+ * Indicates whether the cursor is on the last row in this
3256+ * <code>CachedRowSetImpl</code> object.
3257+ * <P>
3258+ * Note: Calling the method <code>isLast</code> may be expensive
3259+ * because the JDBC driver might need to fetch ahead one row in order
3260+ * to determine whether the current row is the last row in this rowset.
3261+ *
3262+ * @return <code>true</code> if the cursor is on the last row;
3263+ * <code>false</code> otherwise or if this rowset contains no rows
3264+ * @throws SQLException if an error occurs
3265+ */
3266+ public boolean isLast() throws SQLException {
3267+ int saveCursorPos = cursorPos;
3268+ int saveAbsoluteCursorPos = absolutePos;
3269+ boolean saveShowDeleted = getShowDeleted();
3270+ setShowDeleted(true);
3271+ internalLast();
3272+ if (cursorPos == saveCursorPos) {
3273+ setShowDeleted(saveShowDeleted);
3274+ return true;
3275+ } else {
3276+ setShowDeleted(saveShowDeleted);
3277+ cursorPos = saveCursorPos;
3278+ absolutePos = saveAbsoluteCursorPos;
3279+ return false;
3280+ }
3281+ }
3282+
3283+ /**
3284+ * Moves this <code>CachedRowSetImpl</code> object's cursor to the front of
3285+ * the rowset, just before the first row. This method has no effect if
3286+ * this rowset contains no rows.
3287+ *
3288+ * @throws SQLException if an error occurs or the type of this rowset
3289+ * is <code>ResultSet.TYPE_FORWARD_ONLY</code>
3290+ */
3291+ public void beforeFirst() throws SQLException {
3292+ if (getType() == ResultSet.TYPE_FORWARD_ONLY) {
3293+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.beforefirst").toString());
3294+ }
3295+ cursorPos = 0;
3296+ absolutePos = 0;
3297+ notifyCursorMoved();
3298+ }
3299+
3300+ /**
3301+ * Moves this <code>CachedRowSetImpl</code> object's cursor to the end of
3302+ * the rowset, just after the last row. This method has no effect if
3303+ * this rowset contains no rows.
3304+ *
3305+ * @throws SQLException if an error occurs
3306+ */
3307+ public void afterLast() throws SQLException {
3308+ if (numRows > 0) {
3309+ cursorPos = numRows + 1;
3310+ absolutePos = 0;
3311+ notifyCursorMoved();
3312+ }
3313+ }
3314+
3315+ /**
3316+ * Moves this <code>CachedRowSetImpl</code> object's cursor to the first row
3317+ * and returns <code>true</code> if the operation was successful. This
3318+ * method also notifies registered listeners that the cursor has moved.
3319+ *
3320+ * @return <code>true</code> if the cursor is on a valid row;
3321+ * <code>false</code> otherwise or if there are no rows in this
3322+ * <code>CachedRowSetImpl</code> object
3323+ * @throws SQLException if the type of this rowset
3324+ * is <code>ResultSet.TYPE_FORWARD_ONLY</code>
3325+ */
3326+ public boolean first() throws SQLException {
3327+ if(getType() == ResultSet.TYPE_FORWARD_ONLY) {
3328+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.first").toString());
3329+ }
3330+
3331+ // move and notify
3332+ boolean ret = this.internalFirst();
3333+ notifyCursorMoved();
3334+
3335+ return ret;
3336+ }
3337+
3338+ /**
3339+ * Moves this <code>CachedRowSetImpl</code> object's cursor to the first
3340+ * row and returns <code>true</code> if the operation is successful.
3341+ * <P>
3342+ * This method is called internally by the methods <code>first</code>,
3343+ * <code>isFirst</code>, and <code>absolute</code>.
3344+ * It in turn calls the method <code>internalNext</code> in order to
3345+ * handle the case where the first row is a deleted row that is not visible.
3346+ * <p>
3347+ * This is a implementation only method and is not required as a standard
3348+ * implementation of the <code>CachedRowSet</code> interface.
3349+ *
3350+ * @return <code>true</code> if the cursor moved to the first row;
3351+ * <code>false</code> otherwise
3352+ * @throws SQLException if an error occurs
3353+ */
3354+ protected boolean internalFirst() throws SQLException {
3355+ boolean ret = false;
3356+
3357+ if (numRows > 0) {
3358+ cursorPos = 1;
3359+ if ((getShowDeleted() == false) && (rowDeleted() == true)) {
3360+ ret = internalNext();
3361+ } else {
3362+ ret = true;
3363+ }
3364+ }
3365+
3366+ if (ret == true)
3367+ absolutePos = 1;
3368+ else
3369+ absolutePos = 0;
3370+
3371+ return ret;
3372+ }
3373+
3374+ /**
3375+ * Moves this <code>CachedRowSetImpl</code> object's cursor to the last row
3376+ * and returns <code>true</code> if the operation was successful. This
3377+ * method also notifies registered listeners that the cursor has moved.
3378+ *
3379+ * @return <code>true</code> if the cursor is on a valid row;
3380+ * <code>false</code> otherwise or if there are no rows in this
3381+ * <code>CachedRowSetImpl</code> object
3382+ * @throws SQLException if the type of this rowset
3383+ * is <code>ResultSet.TYPE_FORWARD_ONLY</code>
3384+ */
3385+ public boolean last() throws SQLException {
3386+ if (getType() == ResultSet.TYPE_FORWARD_ONLY) {
3387+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.last").toString());
3388+ }
3389+
3390+ // move and notify
3391+ boolean ret = this.internalLast();
3392+ notifyCursorMoved();
3393+
3394+ return ret;
3395+ }
3396+
3397+ /**
3398+ * Moves this <code>CachedRowSetImpl</code> object's cursor to the last
3399+ * row and returns <code>true</code> if the operation is successful.
3400+ * <P>
3401+ * This method is called internally by the method <code>last</code>
3402+ * when rows have been deleted and the deletions are not visible.
3403+ * The method <code>internalLast</code> handles the case where the
3404+ * last row is a deleted row that is not visible by in turn calling
3405+ * the method <code>internalPrevious</code>.
3406+ * <p>
3407+ * This is a implementation only method and is not required as a standard
3408+ * implementation of the <code>CachedRowSet</code> interface.
3409+ *
3410+ * @return <code>true</code> if the cursor moved to the last row;
3411+ * <code>false</code> otherwise
3412+ * @throws SQLException if an error occurs
3413+ */
3414+ protected boolean internalLast() throws SQLException {
3415+ boolean ret = false;
3416+
3417+ if (numRows > 0) {
3418+ cursorPos = numRows;
3419+ if ((getShowDeleted() == false) && (rowDeleted() == true)) {
3420+ ret = internalPrevious();
3421+ } else {
3422+ ret = true;
3423+ }
3424+ }
3425+ if (ret == true)
3426+ absolutePos = numRows - numDeleted;
3427+ else
3428+ absolutePos = 0;
3429+ return ret;
3430+ }
3431+
3432+ /**
3433+ * Returns the number of the current row in this <code>CachedRowSetImpl</code>
3434+ * object. The first row is number 1, the second number 2, and so on.
3435+ *
3436+ * @return the number of the current row; <code>0</code> if there is no
3437+ * current row
3438+ * @throws SQLException if an error occurs; or if the <code>CacheRowSetImpl</code>
3439+ * is empty
3440+ */
3441+ public int getRow() throws SQLException {
3442+ // are we on a valid row? Valid rows are between first and last
3443+ if (numRows > 0 &&
3444+ cursorPos > 0 &&
3445+ cursorPos < (numRows + 1) &&
3446+ (getShowDeleted() == false && rowDeleted() == false)) {
3447+ return absolutePos;
3448+ } else if (getShowDeleted() == true) {
3449+ return cursorPos;
3450+ } else {
3451+ return 0;
3452+ }
3453+ }
3454+
3455+ /**
3456+ * Moves this <code>CachedRowSetImpl</code> object's cursor to the row number
3457+ * specified.
3458+ *
3459+ * <p>If the number is positive, the cursor moves to an absolute row with
3460+ * respect to the beginning of the rowset. The first row is row 1, the second
3461+ * is row 2, and so on. For example, the following command, in which
3462+ * <code>crs</code> is a <code>CachedRowSetImpl</code> object, moves the cursor
3463+ * to the fourth row, starting from the beginning of the rowset.
3464+ * <PRE><code>
3465+ *
3466+ * crs.absolute(4);
3467+ *
3468+ * </code> </PRE>
3469+ * <P>
3470+ * If the number is negative, the cursor moves to an absolute row position
3471+ * with respect to the end of the rowset. For example, calling
3472+ * <code>absolute(-1)</code> positions the cursor on the last row,
3473+ * <code>absolute(-2)</code> moves it on the next-to-last row, and so on.
3474+ * If the <code>CachedRowSetImpl</code> object <code>crs</code> has five rows,
3475+ * the following command moves the cursor to the fourth-to-last row, which
3476+ * in the case of a rowset with five rows, is also the second row, counting
3477+ * from the beginning.
3478+ * <PRE><code>
3479+ *
3480+ * crs.absolute(-4);
3481+ *
3482+ * </code> </PRE>
3483+ *
3484+ * If the number specified is larger than the number of rows, the cursor
3485+ * will move to the position after the last row. If the number specified
3486+ * would move the cursor one or more rows before the first row, the cursor
3487+ * moves to the position before the first row.
3488+ * <P>
3489+ * Note: Calling <code>absolute(1)</code> is the same as calling the
3490+ * method <code>first()</code>. Calling <code>absolute(-1)</code> is the
3491+ * same as calling <code>last()</code>.
3492+ *
3493+ * @param row a positive number to indicate the row, starting row numbering from
3494+ * the first row, which is <code>1</code>; a negative number to indicate
3495+ * the row, starting row numbering from the last row, which is
3496+ * <code>-1</code>; it must not be <code>0</code>
3497+ * @return <code>true</code> if the cursor is on the rowset; <code>false</code>
3498+ * otherwise
3499+ * @throws SQLException if the given cursor position is <code>0</code> or the
3500+ * type of this rowset is <code>ResultSet.TYPE_FORWARD_ONLY</code>
3501+ */
3502+ public boolean absolute( int row ) throws SQLException {
3503+ if (row == 0 || getType() == ResultSet.TYPE_FORWARD_ONLY) {
3504+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.absolute").toString());
3505+ }
3506+
3507+ if (row > 0) { // we are moving foward
3508+ if (row > numRows) {
3509+ // fell off the end
3510+ afterLast();
3511+ return false;
3512+ } else {
3513+ if (absolutePos <= 0)
3514+ internalFirst();
3515+ }
3516+ } else { // we are moving backward
3517+ if (cursorPos + row < 0) {
3518+ // fell off the front
3519+ beforeFirst();
3520+ return false;
3521+ } else {
3522+ if (absolutePos >= 0)
3523+ internalLast();
3524+ }
3525+ }
3526+
3527+ // Now move towards the absolute row that we're looking for
3528+ while (absolutePos != row) {
3529+ if (absolutePos < row) {
3530+ if (!internalNext())
3531+ break;
3532+ }
3533+ else {
3534+ if (!internalPrevious())
3535+ break;
3536+ }
3537+ }
3538+
3539+ notifyCursorMoved();
3540+
3541+ if (isAfterLast() || isBeforeFirst()) {
3542+ return false;
3543+ } else {
3544+ return true;
3545+ }
3546+ }
3547+
3548+ /**
3549+ * Moves the cursor the specified number of rows from the current
3550+ * position, with a positive number moving it forward and a
3551+ * negative number moving it backward.
3552+ * <P>
3553+ * If the number is positive, the cursor moves the specified number of
3554+ * rows toward the end of the rowset, starting at the current row.
3555+ * For example, the following command, in which
3556+ * <code>crs</code> is a <code>CachedRowSetImpl</code> object with 100 rows,
3557+ * moves the cursor forward four rows from the current row. If the
3558+ * current row is 50, the cursor would move to row 54.
3559+ * <PRE><code>
3560+ *
3561+ * crs.relative(4);
3562+ *
3563+ * </code> </PRE>
3564+ * <P>
3565+ * If the number is negative, the cursor moves back toward the beginning
3566+ * the specified number of rows, starting at the current row.
3567+ * For example, calling the method
3568+ * <code>absolute(-1)</code> positions the cursor on the last row,
3569+ * <code>absolute(-2)</code> moves it on the next-to-last row, and so on.
3570+ * If the <code>CachedRowSetImpl</code> object <code>crs</code> has five rows,
3571+ * the following command moves the cursor to the fourth-to-last row, which
3572+ * in the case of a rowset with five rows, is also the second row
3573+ * from the beginning.
3574+ * <PRE><code>
3575+ *
3576+ * crs.absolute(-4);
3577+ *
3578+ * </code> </PRE>
3579+ *
3580+ * If the number specified is larger than the number of rows, the cursor
3581+ * will move to the position after the last row. If the number specified
3582+ * would move the cursor one or more rows before the first row, the cursor
3583+ * moves to the position before the first row. In both cases, this method
3584+ * throws an <code>SQLException</code>.
3585+ * <P>
3586+ * Note: Calling <code>absolute(1)</code> is the same as calling the
3587+ * method <code>first()</code>. Calling <code>absolute(-1)</code> is the
3588+ * same as calling <code>last()</code>. Calling <code>relative(0)</code>
3589+ * is valid, but it does not change the cursor position.
3590+ *
3591+ * @param rows an <code>int</code> indicating the number of rows to move
3592+ * the cursor, starting at the current row; a positive number
3593+ * moves the cursor forward; a negative number moves the cursor
3594+ * backward; must not move the cursor past the valid
3595+ * rows
3596+ * @return <code>true</code> if the cursor is on a row in this
3597+ * <code>CachedRowSetImpl</code> object; <code>false</code>
3598+ * otherwise
3599+ * @throws SQLException if there are no rows in this rowset, the cursor is
3600+ * positioned either before the first row or after the last row, or
3601+ * the rowset is type <code>ResultSet.TYPE_FORWARD_ONLY</code>
3602+ */
3603+ public boolean relative(int rows) throws SQLException {
3604+ if (numRows == 0 || isBeforeFirst() ||
3605+ isAfterLast() || getType() == ResultSet.TYPE_FORWARD_ONLY) {
3606+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.relative").toString());
3607+ }
3608+
3609+ if (rows == 0) {
3610+ return true;
3611+ }
3612+
3613+ if (rows > 0) { // we are moving forward
3614+ if (cursorPos + rows > numRows) {
3615+ // fell off the end
3616+ afterLast();
3617+ } else {
3618+ for (int i=0; i < rows; i++) {
3619+ if (!internalNext())
3620+ break;
3621+ }
3622+ }
3623+ } else { // we are moving backward
3624+ if (cursorPos + rows < 0) {
3625+ // fell off the front
3626+ beforeFirst();
3627+ } else {
3628+ for (int i=rows; i < 0; i++) {
3629+ if (!internalPrevious())
3630+ break;
3631+ }
3632+ }
3633+ }
3634+ notifyCursorMoved();
3635+
3636+ if (isAfterLast() || isBeforeFirst()) {
3637+ return false;
3638+ } else {
3639+ return true;
3640+ }
3641+ }
3642+
3643+ /**
3644+ * Moves this <code>CachedRowSetImpl</code> object's cursor to the
3645+ * previous row and returns <code>true</code> if the cursor is on
3646+ * a valid row or <code>false</code> if it is not.
3647+ * This method also notifies all listeners registered with this
3648+ * <code>CachedRowSetImpl</code> object that its cursor has moved.
3649+ * <P>
3650+ * Note: calling the method <code>previous()</code> is not the same
3651+ * as calling the method <code>relative(-1)</code>. This is true
3652+ * because it is possible to call <code>previous()</code> from the insert
3653+ * row, from after the last row, or from the current row, whereas
3654+ * <code>relative</code> may only be called from the current row.
3655+ * <P>
3656+ * The method <code>previous</code> may used in a <code>while</code>
3657+ * loop to iterate through a rowset starting after the last row
3658+ * and moving toward the beginning. The loop ends when <code>previous</code>
3659+ * returns <code>false</code>, meaning that there are no more rows.
3660+ * For example, the following code fragment retrieves all the data in
3661+ * the <code>CachedRowSetImpl</code> object <code>crs</code>, which has
3662+ * three columns. Note that the cursor must initially be positioned
3663+ * after the last row so that the first call to the method
3664+ * <code>previous</code> places the cursor on the last line.
3665+ * <PRE> <code>
3666+ *
3667+ * crs.afterLast();
3668+ * while (previous()) {
3669+ * String name = crs.getString(1);
3670+ * int age = crs.getInt(2);
3671+ * short ssn = crs.getShort(3);
3672+ * System.out.println(name + " " + age + " " + ssn);
3673+ * }
3674+ *
3675+ * </code> </PRE>
3676+ * This method throws an <code>SQLException</code> if the cursor is not
3677+ * on a row in the rowset, before the first row, or after the last row.
3678+ *
3679+ * @return <code>true</code> if the cursor is on a valid row;
3680+ * <code>false</code> if it is before the first row or after the
3681+ * last row
3682+ * @throws SQLException if the cursor is not on a valid position or the
3683+ * type of this rowset is <code>ResultSet.TYPE_FORWARD_ONLY</code>
3684+ */
3685+ public boolean previous() throws SQLException {
3686+ if (getType() == ResultSet.TYPE_FORWARD_ONLY) {
3687+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.last").toString());
3688+ }
3689+ /*
3690+ * make sure things look sane. The cursor must be
3691+ * positioned in the rowset or before first (0) or
3692+ * after last (numRows + 1)
3693+ */
3694+ if (cursorPos < 0 || cursorPos > numRows + 1) {
3695+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.invalidcp").toString());
3696+ }
3697+ // move and notify
3698+ boolean ret = this.internalPrevious();
3699+ notifyCursorMoved();
3700+
3701+ return ret;
3702+ }
3703+
3704+ /**
3705+ * Moves the cursor to the previous row in this <code>CachedRowSetImpl</code>
3706+ * object, skipping past deleted rows that are not visible; returns
3707+ * <code>true</code> if the cursor is on a row in this rowset and
3708+ * <code>false</code> when the cursor goes before the first row.
3709+ * <P>
3710+ * This method is called internally by the method <code>previous</code>.
3711+ * <P>
3712+ * This is a implementation only method and is not required as a standard
3713+ * implementation of the <code>CachedRowSet</code> interface.
3714+ *
3715+ * @return <code>true</code> if the cursor is on a row in this rowset;
3716+ * <code>false</code> when the cursor reaches the position before
3717+ * the first row
3718+ * @throws SQLException if an error occurs
3719+ */
3720+ protected boolean internalPrevious() throws SQLException {
3721+ boolean ret = false;
3722+
3723+ do {
3724+ if (cursorPos > 1) {
3725+ --cursorPos;
3726+ ret = true;
3727+ } else if (cursorPos == 1) {
3728+ // decrement to before first
3729+ --cursorPos;
3730+ ret = false;
3731+ break;
3732+ }
3733+ } while ((getShowDeleted() == false) && (rowDeleted() == true));
3734+
3735+ /*
3736+ * Each call to internalPrevious may move the cursor
3737+ * over multiple rows, the absolute postion moves one one row
3738+ */
3739+ if (ret == true)
3740+ --absolutePos;
3741+ else
3742+ absolutePos = 0;
3743+
3744+ return ret;
3745+ }
3746+
3747+
3748+ //---------------------------------------------------------------------
3749+ // Updates
3750+ //---------------------------------------------------------------------
3751+
3752+ /**
3753+ * Indicates whether the current row of this <code>CachedRowSetImpl</code>
3754+ * object has been updated. The value returned
3755+ * depends on whether this rowset can detect updates: <code>false</code>
3756+ * will always be returned if it does not detect updates.
3757+ *
3758+ * @return <code>true</code> if the row has been visibly updated
3759+ * by the owner or another and updates are detected;
3760+ * <code>false</code> otherwise
3761+ * @throws SQLException if the cursor is on the insert row or not
3762+ * not on a valid row
3763+ *
3764+ * @see DatabaseMetaData#updatesAreDetected
3765+ */
3766+ public boolean rowUpdated() throws SQLException {
3767+ // make sure the cursor is on a valid row
3768+ checkCursor();
3769+ if (onInsertRow == true) {
3770+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.invalidop").toString());
3771+ }
3772+ return(((Row)getCurrentRow()).getUpdated());
3773+ }
3774+
3775+ /**
3776+ * Indicates whether the designated column of the current row of
3777+ * this <code>CachedRowSetImpl</code> object has been updated. The
3778+ * value returned depends on whether this rowset can detcted updates:
3779+ * <code>false</code> will always be returned if it does not detect updates.
3780+ *
3781+ * @param idx the index identifier of the column that may be have been updated.
3782+ * @return <code>true</code> is the designated column has been updated
3783+ * and the rowset detects updates; <code>false</code> if the rowset has not
3784+ * been updated or the rowset does not detect updates
3785+ * @throws SQLException if the cursor is on the insert row or not
3786+ * on a valid row
3787+ * @see DatabaseMetaData#updatesAreDetected
3788+ */
3789+ public boolean columnUpdated(int idx) throws SQLException {
3790+ // make sure the cursor is on a valid row
3791+ checkCursor();
3792+ if (onInsertRow == true) {
3793+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.invalidop").toString());
3794+ }
3795+ return (((Row)getCurrentRow()).getColUpdated(idx - 1));
3796+ }
3797+
3798+ /**
3799+ * Indicates whether the designated column of the current row of
3800+ * this <code>CachedRowSetImpl</code> object has been updated. The
3801+ * value returned depends on whether this rowset can detcted updates:
3802+ * <code>false</code> will always be returned if it does not detect updates.
3803+ *
3804+ * @param columnName the <code>String</code> column name column that may be have
3805+ * been updated.
3806+ * @return <code>true</code> is the designated column has been updated
3807+ * and the rowset detects updates; <code>false</code> if the rowset has not
3808+ * been updated or the rowset does not detect updates
3809+ * @throws SQLException if the cursor is on the insert row or not
3810+ * on a valid row
3811+ * @see DatabaseMetaData#updatesAreDetected
3812+ */
3813+ public boolean columnUpdated(String columnName) throws SQLException {
3814+ return columnUpdated(getColIdxByName(columnName));
3815+ }
3816+
3817+ /**
3818+ * Indicates whether the current row has been inserted. The value returned
3819+ * depends on whether or not the rowset can detect visible inserts.
3820+ *
3821+ * @return <code>true</code> if a row has been inserted and inserts are detected;
3822+ * <code>false</code> otherwise
3823+ * @throws SQLException if the cursor is on the insert row or not
3824+ * not on a valid row
3825+ *
3826+ * @see DatabaseMetaData#insertsAreDetected
3827+ */
3828+ public boolean rowInserted() throws SQLException {
3829+ // make sure the cursor is on a valid row
3830+ checkCursor();
3831+ if (onInsertRow == true) {
3832+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.invalidop").toString());
3833+ }
3834+ return(((Row)getCurrentRow()).getInserted());
3835+ }
3836+
3837+ /**
3838+ * Indicates whether the current row has been deleted. A deleted row
3839+ * may leave a visible "hole" in a rowset. This method can be used to
3840+ * detect such holes if the rowset can detect deletions. This method
3841+ * will always return <code>false</code> if this rowset cannot detect
3842+ * deletions.
3843+ *
3844+ * @return <code>true</code> if (1)the current row is blank, indicating that
3845+ * the row has been deleted, and (2)deletions are detected;
3846+ * <code>false</code> otherwise
3847+ * @throws SQLException if the cursor is on a valid row in this rowset
3848+ * @see DatabaseMetaData#deletesAreDetected
3849+ */
3850+ public boolean rowDeleted() throws SQLException {
3851+ // make sure the cursor is on a valid row
3852+
3853+ if (isAfterLast() == true ||
3854+ isBeforeFirst() == true ||
3855+ onInsertRow == true) {
3856+
3857+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.invalidcp").toString());
3858+ }
3859+ return(((Row)getCurrentRow()).getDeleted());
3860+ }
3861+
3862+ /**
3863+ * Indicates whether the given SQL data type is a numberic type.
3864+ *
3865+ * @param type one of the constants from <code>java.sql.Types</code>
3866+ * @return <code>true</code> if the given type is <code>NUMERIC</code>,'
3867+ * <code>DECIMAL</code>, <code>BIT</code>, <code>TINYINT</code>,
3868+ * <code>SMALLINT</code>, <code>INTEGER</code>, <code>BIGINT</code>,
3869+ * <code>REAL</code>, <code>DOUBLE</code>, or <code>FLOAT</code>;
3870+ * <code>false</code> otherwise
3871+ */
3872+ private boolean isNumeric(int type) {
3873+ switch (type) {
3874+ case java.sql.Types.NUMERIC:
3875+ case java.sql.Types.DECIMAL:
3876+ case java.sql.Types.BIT:
3877+ case java.sql.Types.TINYINT:
3878+ case java.sql.Types.SMALLINT:
3879+ case java.sql.Types.INTEGER:
3880+ case java.sql.Types.BIGINT:
3881+ case java.sql.Types.REAL:
3882+ case java.sql.Types.DOUBLE:
3883+ case java.sql.Types.FLOAT:
3884+ return true;
3885+ default:
3886+ return false;
3887+ }
3888+ }
3889+
3890+ /**
3891+ * Indicates whether the given SQL data type is a string type.
3892+ *
3893+ * @param type one of the constants from <code>java.sql.Types</code>
3894+ * @return <code>true</code> if the given type is <code>CHAR</code>,'
3895+ * <code>VARCHAR</code>, or <code>LONGVARCHAR</code>;
3896+ * <code>false</code> otherwise
3897+ */
3898+ private boolean isString(int type) {
3899+ switch (type) {
3900+ case java.sql.Types.CHAR:
3901+ case java.sql.Types.VARCHAR:
3902+ case java.sql.Types.LONGVARCHAR:
3903+ return true;
3904+ default:
3905+ return false;
3906+ }
3907+ }
3908+
3909+ /**
3910+ * Indicates whether the given SQL data type is a binary type.
3911+ *
3912+ * @param type one of the constants from <code>java.sql.Types</code>
3913+ * @return <code>true</code> if the given type is <code>BINARY</code>,'
3914+ * <code>VARBINARY</code>, or <code>LONGVARBINARY</code>;
3915+ * <code>false</code> otherwise
3916+ */
3917+ private boolean isBinary(int type) {
3918+ switch (type) {
3919+ case java.sql.Types.BINARY:
3920+ case java.sql.Types.VARBINARY:
3921+ case java.sql.Types.LONGVARBINARY:
3922+ return true;
3923+ default:
3924+ return false;
3925+ }
3926+ }
3927+
3928+ /**
3929+ * Indicates whether the given SQL data type is a temporal type.
3930+ * This method is called internally by the conversion methods
3931+ * <code>convertNumeric</code> and <code>convertTemporal</code>.
3932+ *
3933+ * @param type one of the constants from <code>java.sql.Types</code>
3934+ * @return <code>true</code> if the given type is <code>DATE</code>,
3935+ * <code>TIME</code>, or <code>TIMESTAMP</code>;
3936+ * <code>false</code> otherwise
3937+ */
3938+ private boolean isTemporal(int type) {
3939+ switch (type) {
3940+ case java.sql.Types.DATE:
3941+ case java.sql.Types.TIME:
3942+ case java.sql.Types.TIMESTAMP:
3943+ return true;
3944+ default:
3945+ return false;
3946+ }
3947+ }
3948+
3949+ /**
3950+ * Indicates whether the given SQL data type is a boolean type.
3951+ * This method is called internally by the conversion methods
3952+ * <code>convertNumeric</code> and <code>convertBoolean</code>.
3953+ *
3954+ * @param type one of the constants from <code>java.sql.Types</code>
3955+ * @return <code>true</code> if the given type is <code>BIT</code>,
3956+ * , or <code>BOOLEAN</code>;
3957+ * <code>false</code> otherwise
3958+ */
3959+ private boolean isBoolean(int type) {
3960+ switch (type) {
3961+ case java.sql.Types.BIT:
3962+ case java.sql.Types.BOOLEAN:
3963+ return true;
3964+ default:
3965+ return false;
3966+ }
3967+ }
3968+
3969+
3970+ /**
3971+ * Converts the given <code>Object</code> in the Java programming language
3972+ * to the standard mapping for the specified SQL target data type.
3973+ * The conversion must be to a string or numeric type, but there are no
3974+ * restrictions on the type to be converted. If the source type and target
3975+ * type are the same, the given object is simply returned.
3976+ *
3977+ * @param srcObj the <code>Object</code> in the Java programming language
3978+ * that is to be converted to the target type
3979+ * @param srcType the data type that is the standard mapping in SQL of the
3980+ * object to be converted; must be one of the constants in
3981+ * <code>java.sql.Types</code>
3982+ * @param trgType the SQL data type to which to convert the given object;
3983+ * must be one of the following constants in
3984+ * <code>java.sql.Types</code>: <code>NUMERIC</code>,
3985+ * <code>DECIMAL</code>, <code>BIT</code>, <code>TINYINT</code>,
3986+ * <code>SMALLINT</code>, <code>INTEGER</code>, <code>BIGINT</code>,
3987+ * <code>REAL</code>, <code>DOUBLE</code>, <code>FLOAT</code>,
3988+ * <code>VARCHAR</code>, <code>LONGVARCHAR</code>, or <code>CHAR</code>
3989+ * @return an <code>Object</code> value.that is
3990+ * the standard object mapping for the target SQL type
3991+ * @throws SQLException if the given target type is not one of the string or
3992+ * numeric types in <code>java.sql.Types</code>
3993+ */
3994+ private Object convertNumeric(Object srcObj, int srcType,
3995+ int trgType) throws SQLException {
3996+
3997+ if (srcType == trgType) {
3998+ return srcObj;
3999+ }
4000+
4001+ if (isNumeric(trgType) == false && isString(trgType) == false) {
4002+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.dtypemismt").toString() + trgType);
4003+ }
4004+
4005+ try {
4006+ switch (trgType) {
4007+ case java.sql.Types.BIT:
4008+ Integer i = Integer.valueOf(srcObj.toString().trim());
4009+ return i.equals(Integer.valueOf((int)0)) ?
4010+ Boolean.valueOf(false) :
4011+ Boolean.valueOf(true);
4012+ case java.sql.Types.TINYINT:
4013+ return Byte.valueOf(srcObj.toString().trim());
4014+ case java.sql.Types.SMALLINT:
4015+ return Short.valueOf(srcObj.toString().trim());
4016+ case java.sql.Types.INTEGER:
4017+ return Integer.valueOf(srcObj.toString().trim());
4018+ case java.sql.Types.BIGINT:
4019+ return Long.valueOf(srcObj.toString().trim());
4020+ case java.sql.Types.NUMERIC:
4021+ case java.sql.Types.DECIMAL:
4022+ return new BigDecimal(srcObj.toString().trim());
4023+ case java.sql.Types.REAL:
4024+ case java.sql.Types.FLOAT:
4025+ return new Float(srcObj.toString().trim());
4026+ case java.sql.Types.DOUBLE:
4027+ return new Double(srcObj.toString().trim());
4028+ case java.sql.Types.CHAR:
4029+ case java.sql.Types.VARCHAR:
4030+ case java.sql.Types.LONGVARCHAR:
4031+ return srcObj.toString();
4032+ default:
4033+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.dtypemismt").toString()+ trgType);
4034+ }
4035+ } catch (NumberFormatException ex) {
4036+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.dtypemismt").toString() + trgType);
4037+ }
4038+ }
4039+
4040+ /**
4041+ * Converts the given <code>Object</code> in the Java programming language
4042+ * to the standard object mapping for the specified SQL target data type.
4043+ * The conversion must be to a string or temporal type, and there are also
4044+ * restrictions on the type to be converted.
4045+ * <P>
4046+ * <TABLE ALIGN="CENTER" BORDER CELLPADDING=10 BORDERCOLOR="#0000FF"
4047+ * <CAPTION ALIGN="CENTER"><B>Parameters and Return Values</B></CAPTION>
4048+ * <TR>
4049+ * <TD><B>Source SQL Type</B>
4050+ * <TD><B>Target SQL Type</B>
4051+ * <TD><B>Object Returned</B>
4052+ * </TR>
4053+ * <TR>
4054+ * <TD><code>TIMESTAMP</code>
4055+ * <TD><code>DATE</code>
4056+ * <TD><code>java.sql.Date</code>
4057+ * </TR>
4058+ * <TR>
4059+ * <TD><code>TIMESTAMP</code>
4060+ * <TD><code>TIME</code>
4061+ * <TD><code>java.sql.Time</code>
4062+ * </TR>
4063+ * <TR>
4064+ * <TD><code>TIME</code>
4065+ * <TD><code>TIMESTAMP</code>
4066+ * <TD><code>java.sql.Timestamp</code>
4067+ * </TR>
4068+ * <TR>
4069+ * <TD><code>DATE</code>, <code>TIME</code>, or <code>TIMESTAMP</code>
4070+ * <TD><code>CHAR</code>, <code>VARCHAR</code>, or <code>LONGVARCHAR</code>
4071+ * <TD><code>java.lang.String</code>
4072+ * </TR>
4073+ * </TABLE>
4074+ * <P>
4075+ * If the source type and target type are the same,
4076+ * the given object is simply returned.
4077+ *
4078+ * @param srcObj the <code>Object</code> in the Java programming language
4079+ * that is to be converted to the target type
4080+ * @param srcType the data type that is the standard mapping in SQL of the
4081+ * object to be converted; must be one of the constants in
4082+ * <code>java.sql.Types</code>
4083+ * @param trgType the SQL data type to which to convert the given object;
4084+ * must be one of the following constants in
4085+ * <code>java.sql.Types</code>: <code>DATE</code>,
4086+ * <code>TIME</code>, <code>TIMESTAMP</code>, <code>CHAR</code>,
4087+ * <code>VARCHAR</code>, or <code>LONGVARCHAR</code>
4088+ * @return an <code>Object</code> value.that is
4089+ * the standard object mapping for the target SQL type
4090+ * @throws SQLException if the given target type is not one of the string or
4091+ * temporal types in <code>java.sql.Types</code>
4092+ */
4093+ private Object convertTemporal(Object srcObj,
4094+ int srcType, int trgType) throws SQLException {
4095+
4096+ if (srcType == trgType) {
4097+ return srcObj;
4098+ }
4099+
4100+ if (isNumeric(trgType) == true ||
4101+ (isString(trgType) == false && isTemporal(trgType) == false)) {
4102+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.dtypemismt").toString());
4103+ }
4104+
4105+ try {
4106+ switch (trgType) {
4107+ case java.sql.Types.DATE:
4108+ if (srcType == java.sql.Types.TIMESTAMP) {
4109+ return new java.sql.Date(((java.sql.Timestamp)srcObj).getTime());
4110+ } else {
4111+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.dtypemismt").toString());
4112+ }
4113+ case java.sql.Types.TIMESTAMP:
4114+ if (srcType == java.sql.Types.TIME) {
4115+ return new Timestamp(((java.sql.Time)srcObj).getTime());
4116+ } else {
4117+ return new Timestamp(((java.sql.Date)srcObj).getTime());
4118+ }
4119+ case java.sql.Types.TIME:
4120+ if (srcType == java.sql.Types.TIMESTAMP) {
4121+ return new Time(((java.sql.Timestamp)srcObj).getTime());
4122+ } else {
4123+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.dtypemismt").toString());
4124+ }
4125+ case java.sql.Types.CHAR:
4126+ case java.sql.Types.VARCHAR:
4127+ case java.sql.Types.LONGVARCHAR:
4128+ return srcObj.toString();
4129+ default:
4130+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.dtypemismt").toString());
4131+ }
4132+ } catch (NumberFormatException ex) {
4133+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.dtypemismt").toString());
4134+ }
4135+
4136+ }
4137+
4138+ /**
4139+ * Converts the given <code>Object</code> in the Java programming language
4140+ * to the standard mapping for the specified SQL target data type.
4141+ * The conversion must be to a string or numeric type, but there are no
4142+ * restrictions on the type to be converted. If the source type and target
4143+ * type are the same, the given object is simply returned.
4144+ *
4145+ * @param srcObj the <code>Object</code> in the Java programming language
4146+ * that is to be converted to the target type
4147+ * @param srcType the data type that is the standard mapping in SQL of the
4148+ * object to be converted; must be one of the constants in
4149+ * <code>java.sql.Types</code>
4150+ * @param trgType the SQL data type to which to convert the given object;
4151+ * must be one of the following constants in
4152+ * <code>java.sql.Types</code>: <code>BIT</code>,
4153+ * or <code>BOOLEAN</code>
4154+ * @return an <code>Object</code> value.that is
4155+ * the standard object mapping for the target SQL type
4156+ * @throws SQLException if the given target type is not one of the Boolean
4157+ * types in <code>java.sql.Types</code>
4158+ */
4159+ private Object convertBoolean(Object srcObj, int srcType,
4160+ int trgType) throws SQLException {
4161+
4162+ if (srcType == trgType) {
4163+ return srcObj;
4164+ }
4165+
4166+ if (isNumeric(trgType) == true ||
4167+ (isString(trgType) == false && isBoolean(trgType) == false)) {
4168+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.dtypemismt").toString());
4169+ }
4170+
4171+
4172+ try {
4173+ switch (trgType) {
4174+ case java.sql.Types.BIT:
4175+ Integer i = Integer.valueOf(srcObj.toString().trim());
4176+ return i.equals(Integer.valueOf((int)0)) ?
4177+ Boolean.valueOf(false) :
4178+ Boolean.valueOf(true);
4179+ case java.sql.Types.BOOLEAN:
4180+ return Boolean.valueOf(srcObj.toString().trim());
4181+ default:
4182+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.dtypemismt").toString()+ trgType);
4183+ }
4184+ } catch (NumberFormatException ex) {
4185+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.dtypemismt").toString() + trgType);
4186+ }
4187+ }
4188+
4189+ /**
4190+ * Sets the designated nullable column in the current row or the
4191+ * insert row of this <code>CachedRowSetImpl</code> object with
4192+ * <code>null</code> value.
4193+ * <P>
4194+ * This method updates a column value in the current row or the insert
4195+ * row of this rowset; however, another method must be called to complete
4196+ * the update process. If the cursor is on a row in the rowset, the
4197+ * method {@link #updateRow} must be called to mark the row as updated
4198+ * and to notify listeners that the row has changed.
4199+ * If the cursor is on the insert row, the method {@link #insertRow}
4200+ * must be called to insert the new row into this rowset and to notify
4201+ * listeners that a row has changed.
4202+ * <P>
4203+ * In order to propagate updates in this rowset to the underlying
4204+ * data source, an application must call the method {@link #acceptChanges}
4205+ * after it calls either <code>updateRow</code> or <code>insertRow</code>.
4206+ *
4207+ * @param columnIndex the first column is <code>1</code>, the second
4208+ * is <code>2</code>, and so on; must be <code>1</code> or larger
4209+ * and equal to or less than the number of columns in this rowset
4210+ * @throws SQLException if (1) the given column index is out of bounds,
4211+ * (2) the cursor is not on one of this rowset's rows or its
4212+ * insert row, or (3) this rowset is
4213+ * <code>ResultSet.CONCUR_READ_ONLY</code>
4214+ */
4215+ public void updateNull(int columnIndex) throws SQLException {
4216+ // sanity check.
4217+ checkIndex(columnIndex);
4218+ // make sure the cursor is on a valid row
4219+ checkCursor();
4220+
4221+ BaseRow row = getCurrentRow();
4222+ row.setColumnObject(columnIndex, null);
4223+
4224+ }
4225+
4226+ /**
4227+ * Sets the designated column in either the current row or the insert
4228+ * row of this <code>CachedRowSetImpl</code> object with the given
4229+ * <code>boolean</code> value.
4230+ * <P>
4231+ * This method updates a column value in the current row or the insert
4232+ * row of this rowset, but it does not update the database.
4233+ * If the cursor is on a row in the rowset, the
4234+ * method {@link #updateRow} must be called to update the database.
4235+ * If the cursor is on the insert row, the method {@link #insertRow}
4236+ * must be called, which will insert the new row into both this rowset
4237+ * and the database. Both of these methods must be called before the
4238+ * cursor moves to another row.
4239+ *
4240+ * @param columnIndex the first column is <code>1</code>, the second
4241+ * is <code>2</code>, and so on; must be <code>1</code> or larger
4242+ * and equal to or less than the number of columns in this rowset
4243+ * @param x the new column value
4244+ * @throws SQLException if (1) the given column index is out of bounds,
4245+ * (2) the cursor is not on one of this rowset's rows or its
4246+ * insert row, or (3) this rowset is
4247+ * <code>ResultSet.CONCUR_READ_ONLY</code>
4248+ */
4249+ public void updateBoolean(int columnIndex, boolean x) throws SQLException {
4250+ // sanity check.
4251+ checkIndex(columnIndex);
4252+ // make sure the cursor is on a valid row
4253+ checkCursor();
4254+ Object obj = convertBoolean(Boolean.valueOf(x),
4255+ java.sql.Types.BIT,
4256+ RowSetMD.getColumnType(columnIndex));
4257+
4258+ getCurrentRow().setColumnObject(columnIndex, obj);
4259+ }
4260+
4261+ /**
4262+ * Sets the designated column in either the current row or the insert
4263+ * row of this <code>CachedRowSetImpl</code> object with the given
4264+ * <code>byte</code> value.
4265+ * <P>
4266+ * This method updates a column value in the current row or the insert
4267+ * row of this rowset, but it does not update the database.
4268+ * If the cursor is on a row in the rowset, the
4269+ * method {@link #updateRow} must be called to update the database.
4270+ * If the cursor is on the insert row, the method {@link #insertRow}
4271+ * must be called, which will insert the new row into both this rowset
4272+ * and the database. Both of these methods must be called before the
4273+ * cursor moves to another row.
4274+ *
4275+ * @param columnIndex the first column is <code>1</code>, the second
4276+ * is <code>2</code>, and so on; must be <code>1</code> or larger
4277+ * and equal to or less than the number of columns in this rowset
4278+ * @param x the new column value
4279+ * @throws SQLException if (1) the given column index is out of bounds,
4280+ * (2) the cursor is not on one of this rowset's rows or its
4281+ * insert row, or (3) this rowset is
4282+ * <code>ResultSet.CONCUR_READ_ONLY</code>
4283+ */
4284+ public void updateByte(int columnIndex, byte x) throws SQLException {
4285+ // sanity check.
4286+ checkIndex(columnIndex);
4287+ // make sure the cursor is on a valid row
4288+ checkCursor();
4289+
4290+ Object obj = convertNumeric(Byte.valueOf(x),
4291+ java.sql.Types.TINYINT,
4292+ RowSetMD.getColumnType(columnIndex));
4293+
4294+ getCurrentRow().setColumnObject(columnIndex, obj);
4295+ }
4296+
4297+ /**
4298+ * Sets the designated column in either the current row or the insert
4299+ * row of this <code>CachedRowSetImpl</code> object with the given
4300+ * <code>short</code> value.
4301+ * <P>
4302+ * This method updates a column value in the current row or the insert
4303+ * row of this rowset, but it does not update the database.
4304+ * If the cursor is on a row in the rowset, the
4305+ * method {@link #updateRow} must be called to update the database.
4306+ * If the cursor is on the insert row, the method {@link #insertRow}
4307+ * must be called, which will insert the new row into both this rowset
4308+ * and the database. Both of these methods must be called before the
4309+ * cursor moves to another row.
4310+ *
4311+ * @param columnIndex the first column is <code>1</code>, the second
4312+ * is <code>2</code>, and so on; must be <code>1</code> or larger
4313+ * and equal to or less than the number of columns in this rowset
4314+ * @param x the new column value
4315+ * @throws SQLException if (1) the given column index is out of bounds,
4316+ * (2) the cursor is not on one of this rowset's rows or its
4317+ * insert row, or (3) this rowset is
4318+ * <code>ResultSet.CONCUR_READ_ONLY</code>
4319+ */
4320+ public void updateShort(int columnIndex, short x) throws SQLException {
4321+ // sanity check.
4322+ checkIndex(columnIndex);
4323+ // make sure the cursor is on a valid row
4324+ checkCursor();
4325+
4326+ Object obj = convertNumeric(Short.valueOf(x),
4327+ java.sql.Types.SMALLINT,
4328+ RowSetMD.getColumnType(columnIndex));
4329+
4330+ getCurrentRow().setColumnObject(columnIndex, obj);
4331+ }
4332+
4333+ /**
4334+ * Sets the designated column in either the current row or the insert
4335+ * row of this <code>CachedRowSetImpl</code> object with the given
4336+ * <code>int</code> value.
4337+ * <P>
4338+ * This method updates a column value in the current row or the insert
4339+ * row of this rowset, but it does not update the database.
4340+ * If the cursor is on a row in the rowset, the
4341+ * method {@link #updateRow} must be called to update the database.
4342+ * If the cursor is on the insert row, the method {@link #insertRow}
4343+ * must be called, which will insert the new row into both this rowset
4344+ * and the database. Both of these methods must be called before the
4345+ * cursor moves to another row.
4346+ *
4347+ * @param columnIndex the first column is <code>1</code>, the second
4348+ * is <code>2</code>, and so on; must be <code>1</code> or larger
4349+ * and equal to or less than the number of columns in this rowset
4350+ * @param x the new column value
4351+ * @throws SQLException if (1) the given column index is out of bounds,
4352+ * (2) the cursor is not on one of this rowset's rows or its
4353+ * insert row, or (3) this rowset is
4354+ * <code>ResultSet.CONCUR_READ_ONLY</code>
4355+ */
4356+ public void updateInt(int columnIndex, int x) throws SQLException {
4357+ // sanity check.
4358+ checkIndex(columnIndex);
4359+ // make sure the cursor is on a valid row
4360+ checkCursor();
4361+ Object obj = convertNumeric(Integer.valueOf(x),
4362+ java.sql.Types.INTEGER,
4363+ RowSetMD.getColumnType(columnIndex));
4364+
4365+ getCurrentRow().setColumnObject(columnIndex, obj);
4366+ }
4367+
4368+ /**
4369+ * Sets the designated column in either the current row or the insert
4370+ * row of this <code>CachedRowSetImpl</code> object with the given
4371+ * <code>long</code> value.
4372+ * <P>
4373+ * This method updates a column value in the current row or the insert
4374+ * row of this rowset, but it does not update the database.
4375+ * If the cursor is on a row in the rowset, the
4376+ * method {@link #updateRow} must be called to update the database.
4377+ * If the cursor is on the insert row, the method {@link #insertRow}
4378+ * must be called, which will insert the new row into both this rowset
4379+ * and the database. Both of these methods must be called before the
4380+ * cursor moves to another row.
4381+ *
4382+ * @param columnIndex the first column is <code>1</code>, the second
4383+ * is <code>2</code>, and so on; must be <code>1</code> or larger
4384+ * and equal to or less than the number of columns in this rowset
4385+ * @param x the new column value
4386+ * @throws SQLException if (1) the given column index is out of bounds,
4387+ * (2) the cursor is not on one of this rowset's rows or its
4388+ * insert row, or (3) this rowset is
4389+ * <code>ResultSet.CONCUR_READ_ONLY</code>
4390+ */
4391+ public void updateLong(int columnIndex, long x) throws SQLException {
4392+ // sanity check.
4393+ checkIndex(columnIndex);
4394+ // make sure the cursor is on a valid row
4395+ checkCursor();
4396+
4397+ Object obj = convertNumeric(Long.valueOf(x),
4398+ java.sql.Types.BIGINT,
4399+ RowSetMD.getColumnType(columnIndex));
4400+
4401+ getCurrentRow().setColumnObject(columnIndex, obj);
4402+
4403+ }
4404+
4405+ /**
4406+ * Sets the designated column in either the current row or the insert
4407+ * row of this <code>CachedRowSetImpl</code> object with the given
4408+ * <code>float</code> value.
4409+ * <P>
4410+ * This method updates a column value in the current row or the insert
4411+ * row of this rowset, but it does not update the database.
4412+ * If the cursor is on a row in the rowset, the
4413+ * method {@link #updateRow} must be called to update the database.
4414+ * If the cursor is on the insert row, the method {@link #insertRow}
4415+ * must be called, which will insert the new row into both this rowset
4416+ * and the database. Both of these methods must be called before the
4417+ * cursor moves to another row.
4418+ *
4419+ * @param columnIndex the first column is <code>1</code>, the second
4420+ * is <code>2</code>, and so on; must be <code>1</code> or larger
4421+ * and equal to or less than the number of columns in this rowset
4422+ * @param x the new column value
4423+ * @throws SQLException if (1) the given column index is out of bounds,
4424+ * (2) the cursor is not on one of this rowset's rows or its
4425+ * insert row, or (3) this rowset is
4426+ * <code>ResultSet.CONCUR_READ_ONLY</code>
4427+ */
4428+ public void updateFloat(int columnIndex, float x) throws SQLException {
4429+ // sanity check.
4430+ checkIndex(columnIndex);
4431+ // make sure the cursor is on a valid row
4432+ checkCursor();
4433+
4434+ Object obj = convertNumeric(new Float(x),
4435+ java.sql.Types.REAL,
4436+ RowSetMD.getColumnType(columnIndex));
4437+
4438+ getCurrentRow().setColumnObject(columnIndex, obj);
4439+ }
4440+
4441+ /**
4442+ * Sets the designated column in either the current row or the insert
4443+ * row of this <code>CachedRowSetImpl</code> object with the given
4444+ * <code>double</code> value.
4445+ *
4446+ * This method updates a column value in either the current row or
4447+ * the insert row of this rowset, but it does not update the
4448+ * database. If the cursor is on a row in the rowset, the
4449+ * method {@link #updateRow} must be called to update the database.
4450+ * If the cursor is on the insert row, the method {@link #insertRow}
4451+ * must be called, which will insert the new row into both this rowset
4452+ * and the database. Both of these methods must be called before the
4453+ * cursor moves to another row.
4454+ *
4455+ * @param columnIndex the first column is <code>1</code>, the second
4456+ * is <code>2</code>, and so on; must be <code>1</code> or larger
4457+ * and equal to or less than the number of columns in this rowset
4458+ * @param x the new column value
4459+ * @throws SQLException if (1) the given column index is out of bounds,
4460+ * (2) the cursor is not on one of this rowset's rows or its
4461+ * insert row, or (3) this rowset is
4462+ * <code>ResultSet.CONCUR_READ_ONLY</code>
4463+ */
4464+ public void updateDouble(int columnIndex, double x) throws SQLException {
4465+ // sanity check.
4466+ checkIndex(columnIndex);
4467+ // make sure the cursor is on a valid row
4468+ checkCursor();
4469+ Object obj = convertNumeric(new Double(x),
4470+ java.sql.Types.DOUBLE,
4471+ RowSetMD.getColumnType(columnIndex));
4472+
4473+ getCurrentRow().setColumnObject(columnIndex, obj);
4474+ }
4475+
4476+ /**
4477+ * Sets the designated column in either the current row or the insert
4478+ * row of this <code>CachedRowSetImpl</code> object with the given
4479+ * <code>java.math.BigDecimal</code> object.
4480+ * <P>
4481+ * This method updates a column value in the current row or the insert
4482+ * row of this rowset, but it does not update the database.
4483+ * If the cursor is on a row in the rowset, the
4484+ * method {@link #updateRow} must be called to update the database.
4485+ * If the cursor is on the insert row, the method {@link #insertRow}
4486+ * must be called, which will insert the new row into both this rowset
4487+ * and the database. Both of these methods must be called before the
4488+ * cursor moves to another row.
4489+ *
4490+ * @param columnIndex the first column is <code>1</code>, the second
4491+ * is <code>2</code>, and so on; must be <code>1</code> or larger
4492+ * and equal to or less than the number of columns in this rowset
4493+ * @param x the new column value
4494+ * @throws SQLException if (1) the given column index is out of bounds,
4495+ * (2) the cursor is not on one of this rowset's rows or its
4496+ * insert row, or (3) this rowset is
4497+ * <code>ResultSet.CONCUR_READ_ONLY</code>
4498+ */
4499+ public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException {
4500+ // sanity check.
4501+ checkIndex(columnIndex);
4502+ // make sure the cursor is on a valid row
4503+ checkCursor();
4504+
4505+ Object obj = convertNumeric(x,
4506+ java.sql.Types.NUMERIC,
4507+ RowSetMD.getColumnType(columnIndex));
4508+
4509+ getCurrentRow().setColumnObject(columnIndex, obj);
4510+ }
4511+
4512+ /**
4513+ * Sets the designated column in either the current row or the insert
4514+ * row of this <code>CachedRowSetImpl</code> object with the given
4515+ * <code>String</code> object.
4516+ * <P>
4517+ * This method updates a column value in either the current row or
4518+ * the insert row of this rowset, but it does not update the
4519+ * database. If the cursor is on a row in the rowset, the
4520+ * method {@link #updateRow} must be called to mark the row as updated.
4521+ * If the cursor is on the insert row, the method {@link #insertRow}
4522+ * must be called to insert the new row into this rowset and mark it
4523+ * as inserted. Both of these methods must be called before the
4524+ * cursor moves to another row.
4525+ * <P>
4526+ * The method <code>acceptChanges</code> must be called if the
4527+ * updated values are to be written back to the underlying database.
4528+ *
4529+ * @param columnIndex the first column is <code>1</code>, the second
4530+ * is <code>2</code>, and so on; must be <code>1</code> or larger
4531+ * and equal to or less than the number of columns in this rowset
4532+ * @param x the new column value
4533+ * @throws SQLException if (1) the given column index is out of bounds,
4534+ * (2) the cursor is not on one of this rowset's rows or its
4535+ * insert row, or (3) this rowset is
4536+ * <code>ResultSet.CONCUR_READ_ONLY</code>
4537+ */
4538+ public void updateString(int columnIndex, String x) throws SQLException {
4539+ // sanity check.
4540+ checkIndex(columnIndex);
4541+ // make sure the cursor is on a valid row
4542+ checkCursor();
4543+
4544+ getCurrentRow().setColumnObject(columnIndex, x);
4545+ }
4546+
4547+ /**
4548+ * Sets the designated column in either the current row or the insert
4549+ * row of this <code>CachedRowSetImpl</code> object with the given
4550+ * <code>byte</code> array.
4551+ *
4552+ * This method updates a column value in either the current row or
4553+ * the insert row of this rowset, but it does not update the
4554+ * database. If the cursor is on a row in the rowset, the
4555+ * method {@link #updateRow} must be called to update the database.
4556+ * If the cursor is on the insert row, the method {@link #insertRow}
4557+ * must be called, which will insert the new row into both this rowset
4558+ * and the database. Both of these methods must be called before the
4559+ * cursor moves to another row.
4560+ *
4561+ * @param columnIndex the first column is <code>1</code>, the second
4562+ * is <code>2</code>, and so on; must be <code>1</code> or larger
4563+ * and equal to or less than the number of columns in this rowset
4564+ * @param x the new column value
4565+ * @throws SQLException if (1) the given column index is out of bounds,
4566+ * (2) the cursor is not on one of this rowset's rows or its
4567+ * insert row, or (3) this rowset is
4568+ * <code>ResultSet.CONCUR_READ_ONLY</code>
4569+ */
4570+ public void updateBytes(int columnIndex, byte x[]) throws SQLException {
4571+ // sanity check.
4572+ checkIndex(columnIndex);
4573+ // make sure the cursor is on a valid row
4574+ checkCursor();
4575+
4576+ if (isBinary(RowSetMD.getColumnType(columnIndex)) == false) {
4577+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.dtypemismt").toString());
4578+ }
4579+
4580+ getCurrentRow().setColumnObject(columnIndex, x);
4581+ }
4582+
4583+ /**
4584+ * Sets the designated column in either the current row or the insert
4585+ * row of this <code>CachedRowSetImpl</code> object with the given
4586+ * <code>Date</code> object.
4587+ *
4588+ * This method updates a column value in either the current row or
4589+ * the insert row of this rowset, but it does not update the
4590+ * database. If the cursor is on a row in the rowset, the
4591+ * method {@link #updateRow} must be called to update the database.
4592+ * If the cursor is on the insert row, the method {@link #insertRow}
4593+ * must be called, which will insert the new row into both this rowset
4594+ * and the database. Both of these methods must be called before the
4595+ * cursor moves to another row.
4596+ *
4597+ * @param columnIndex the first column is <code>1</code>, the second
4598+ * is <code>2</code>, and so on; must be <code>1</code> or larger
4599+ * and equal to or less than the number of columns in this rowset
4600+ * @param x the new column value
4601+ * @throws SQLException if (1) the given column index is out of bounds,
4602+ * (2) the cursor is not on one of this rowset's rows or its
4603+ * insert row, (3) the type of the designated column is not
4604+ * an SQL <code>DATE</code> or <code>TIMESTAMP</code>, or
4605+ * (4) this rowset is <code>ResultSet.CONCUR_READ_ONLY</code>
4606+ */
4607+ public void updateDate(int columnIndex, java.sql.Date x) throws SQLException {
4608+ // sanity check.
4609+ checkIndex(columnIndex);
4610+ // make sure the cursor is on a valid row
4611+ checkCursor();
4612+
4613+ Object obj = convertTemporal(x,
4614+ java.sql.Types.DATE,
4615+ RowSetMD.getColumnType(columnIndex));
4616+
4617+ getCurrentRow().setColumnObject(columnIndex, obj);
4618+ }
4619+
4620+ /**
4621+ * Sets the designated column in either the current row or the insert
4622+ * row of this <code>CachedRowSetImpl</code> object with the given
4623+ * <code>Time</code> object.
4624+ *
4625+ * This method updates a column value in either the current row or
4626+ * the insert row of this rowset, but it does not update the
4627+ * database. If the cursor is on a row in the rowset, the
4628+ * method {@link #updateRow} must be called to update the database.
4629+ * If the cursor is on the insert row, the method {@link #insertRow}
4630+ * must be called, which will insert the new row into both this rowset
4631+ * and the database. Both of these methods must be called before the
4632+ * cursor moves to another row.
4633+ *
4634+ * @param columnIndex the first column is <code>1</code>, the second
4635+ * is <code>2</code>, and so on; must be <code>1</code> or larger
4636+ * and equal to or less than the number of columns in this rowset
4637+ * @param x the new column value
4638+ * @throws SQLException if (1) the given column index is out of bounds,
4639+ * (2) the cursor is not on one of this rowset's rows or its
4640+ * insert row, (3) the type of the designated column is not
4641+ * an SQL <code>TIME</code> or <code>TIMESTAMP</code>, or
4642+ * (4) this rowset is <code>ResultSet.CONCUR_READ_ONLY</code>
4643+ */
4644+ public void updateTime(int columnIndex, java.sql.Time x) throws SQLException {
4645+ // sanity check.
4646+ checkIndex(columnIndex);
4647+ // make sure the cursor is on a valid row
4648+ checkCursor();
4649+
4650+ Object obj = convertTemporal(x,
4651+ java.sql.Types.TIME,
4652+ RowSetMD.getColumnType(columnIndex));
4653+
4654+ getCurrentRow().setColumnObject(columnIndex, obj);
4655+ }
4656+
4657+ /**
4658+ * Sets the designated column in either the current row or the insert
4659+ * row of this <code>CachedRowSetImpl</code> object with the given
4660+ * <code>Timestamp</code> object.
4661+ *
4662+ * This method updates a column value in either the current row or
4663+ * the insert row of this rowset, but it does not update the
4664+ * database. If the cursor is on a row in the rowset, the
4665+ * method {@link #updateRow} must be called to update the database.
4666+ * If the cursor is on the insert row, the method {@link #insertRow}
4667+ * must be called, which will insert the new row into both this rowset
4668+ * and the database. Both of these methods must be called before the
4669+ * cursor moves to another row.
4670+ *
4671+ * @param columnIndex the first column is <code>1</code>, the second
4672+ * is <code>2</code>, and so on; must be <code>1</code> or larger
4673+ * and equal to or less than the number of columns in this rowset
4674+ * @param x the new column value
4675+ * @throws SQLException if (1) the given column index is out of bounds,
4676+ * (2) the cursor is not on one of this rowset's rows or its
4677+ * insert row, (3) the type of the designated column is not
4678+ * an SQL <code>DATE</code>, <code>TIME</code>, or
4679+ * <code>TIMESTAMP</code>, or (4) this rowset is
4680+ * <code>ResultSet.CONCUR_READ_ONLY</code>
4681+ */
4682+ public void updateTimestamp(int columnIndex, java.sql.Timestamp x) throws SQLException {
4683+ // sanity check.
4684+ checkIndex(columnIndex);
4685+ // make sure the cursor is on a valid row
4686+ checkCursor();
4687+
4688+ Object obj = convertTemporal(x,
4689+ java.sql.Types.TIMESTAMP,
4690+ RowSetMD.getColumnType(columnIndex));
4691+
4692+ getCurrentRow().setColumnObject(columnIndex, obj);
4693+ }
4694+
4695+ /**
4696+ * Sets the designated column in either the current row or the insert
4697+ * row of this <code>CachedRowSetImpl</code> object with the given
4698+ * ASCII stream value.
4699+ * <P>
4700+ * This method updates a column value in either the current row or
4701+ * the insert row of this rowset, but it does not update the
4702+ * database. If the cursor is on a row in the rowset, the
4703+ * method {@link #updateRow} must be called to update the database.
4704+ * If the cursor is on the insert row, the method {@link #insertRow}
4705+ * must be called, which will insert the new row into both this rowset
4706+ * and the database. Both of these methods must be called before the
4707+ * cursor moves to another row.
4708+ *
4709+ * @param columnIndex the first column is <code>1</code>, the second
4710+ * is <code>2</code>, and so on; must be <code>1</code> or larger
4711+ * and equal to or less than the number of columns in this rowset
4712+ * @param x the new column value
4713+ * @param length the number of one-byte ASCII characters in the stream
4714+ * @throws SQLException if this method is invoked
4715+ */
4716+ public void updateAsciiStream(int columnIndex, java.io.InputStream x, int length) throws SQLException {
4717+ // sanity Check
4718+ checkIndex(columnIndex);
4719+ // make sure the cursor is on a valid row
4720+ checkCursor();
4721+
4722+
4723+ if (isString(RowSetMD.getColumnType(columnIndex)) == false &&
4724+ isBinary(RowSetMD.getColumnType(columnIndex)) == false) {
4725+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.dtypemismt").toString());
4726+ }
4727+
4728+ byte buf[] = new byte[length];
4729+ try {
4730+ int charsRead = 0;
4731+ do {
4732+ charsRead += x.read(buf, charsRead, length - charsRead);
4733+ } while (charsRead != length);
4734+ //Changed the condition check to check for length instead of -1
4735+ } catch (java.io.IOException ex) {
4736+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.asciistream").toString());
4737+ }
4738+ String str = new String(buf);
4739+
4740+ getCurrentRow().setColumnObject(columnIndex, str);
4741+
4742+ }
4743+
4744+ /**
4745+ * Sets the designated column in either the current row or the insert
4746+ * row of this <code>CachedRowSetImpl</code> object with the given
4747+ * <code>java.io.InputStream</code> object.
4748+ * <P>
4749+ * This method updates a column value in either the current row or
4750+ * the insert row of this rowset, but it does not update the
4751+ * database. If the cursor is on a row in the rowset, the
4752+ * method {@link #updateRow} must be called to update the database.
4753+ * If the cursor is on the insert row, the method {@link #insertRow}
4754+ * must be called, which will insert the new row into both this rowset
4755+ * and the database. Both of these methods must be called before the
4756+ * cursor moves to another row.
4757+ *
4758+ * @param columnIndex the first column is <code>1</code>, the second
4759+ * is <code>2</code>, and so on; must be <code>1</code> or larger
4760+ * and equal to or less than the number of columns in this rowset
4761+ * @param x the new column value; must be a <code>java.io.InputStream</code>
4762+ * containing <code>BINARY</code>, <code>VARBINARY</code>, or
4763+ * <code>LONGVARBINARY</code> data
4764+ * @param length the length of the stream in bytes
4765+ * @throws SQLException if (1) the given column index is out of bounds,
4766+ * (2) the cursor is not on one of this rowset's rows or its
4767+ * insert row, (3) the data in the stream is not binary, or
4768+ * (4) this rowset is <code>ResultSet.CONCUR_READ_ONLY</code>
4769+ */
4770+ public void updateBinaryStream(int columnIndex, java.io.InputStream x,int length) throws SQLException {
4771+ // sanity Check
4772+ checkIndex(columnIndex);
4773+ // make sure the cursor is on a valid row
4774+ checkCursor();
4775+
4776+ if (isBinary(RowSetMD.getColumnType(columnIndex)) == false) {
4777+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.dtypemismt").toString());
4778+ }
4779+
4780+ byte buf[] = new byte[length];
4781+ try {
4782+ int bytesRead = 0;
4783+ do {
4784+ bytesRead += x.read(buf, bytesRead, length - bytesRead);
4785+ } while (bytesRead != -1);
4786+ } catch (java.io.IOException ex) {
4787+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.binstream").toString());
4788+ }
4789+
4790+ getCurrentRow().setColumnObject(columnIndex, buf);
4791+ }
4792+
4793+ /**
4794+ * Sets the designated column in either the current row or the insert
4795+ * row of this <code>CachedRowSetImpl</code> object with the given
4796+ * <code>java.io.Reader</code> object.
4797+ * <P>
4798+ * This method updates a column value in either the current row or
4799+ * the insert row of this rowset, but it does not update the
4800+ * database. If the cursor is on a row in the rowset, the
4801+ * method {@link #updateRow} must be called to update the database.
4802+ * If the cursor is on the insert row, the method {@link #insertRow}
4803+ * must be called, which will insert the new row into both this rowset
4804+ * and the database. Both of these methods must be called before the
4805+ * cursor moves to another row.
4806+ *
4807+ * @param columnIndex the first column is <code>1</code>, the second
4808+ * is <code>2</code>, and so on; must be <code>1</code> or larger
4809+ * and equal to or less than the number of columns in this rowset
4810+ * @param x the new column value; must be a <code>java.io.Reader</code>
4811+ * containing <code>BINARY</code>, <code>VARBINARY</code>,
4812+ * <code>LONGVARBINARY</code>, <code>CHAR</code>, <code>VARCHAR</code>,
4813+ * or <code>LONGVARCHAR</code> data
4814+ * @param length the length of the stream in characters
4815+ * @throws SQLException if (1) the given column index is out of bounds,
4816+ * (2) the cursor is not on one of this rowset's rows or its
4817+ * insert row, (3) the data in the stream is not a binary or
4818+ * character type, or (4) this rowset is
4819+ * <code>ResultSet.CONCUR_READ_ONLY</code>
4820+ */
4821+ public void updateCharacterStream(int columnIndex, java.io.Reader x, int length) throws SQLException {
4822+ // sanity Check
4823+ checkIndex(columnIndex);
4824+ // make sure the cursor is on a valid row
4825+ checkCursor();
4826+
4827+ if (isString(RowSetMD.getColumnType(columnIndex)) == false &&
4828+ isBinary(RowSetMD.getColumnType(columnIndex)) == false) {
4829+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.dtypemismt").toString());
4830+ }
4831+
4832+ char buf[] = new char[length];
4833+ try {
4834+ int charsRead = 0;
4835+ do {
4836+ charsRead += x.read(buf, charsRead, length - charsRead);
4837+ } while (charsRead != length);
4838+ //Changed the condition checking to check for length instead of -1
4839+ } catch (java.io.IOException ex) {
4840+ throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.binstream").toString());
4841+ }
4842+ String str = new String(buf);
4843+
4844+ getCurrentRow().setColumnObject(columnIndex, str);
4845+ }
4846+
4847+ /**
4848+ * Sets the designated column in either the current row or the insert
4849+ * row of this <code>CachedRowSetImpl</code> object with the given
4850+ * <code>Object</code> value. The <code>scale</code> parameter indicates
4851+ * the number of digits to the right of the decimal point and is ignored
4852+ * if the new column value is not a type that will be mapped to an SQL
4853+ * <code>DECIMAL</code> or <code>NUMERIC</code> value.
4854+ * <P>
4855+ * This method updates a column value in either the current row or
4856+ * the insert row of this rowset, but it does not update the
4857+ * database. If the cursor is on a row in the rowset, the
4858+ * method {@link #updateRow} must be called to update the database.
4859+ * If the cursor is on the insert row, the method {@link #insertRow}
4860+ * must be called, which will insert the new row into both this rowset
4861+ * and the database. Both of these methods must be called before the
4862+ * cursor moves to another row.
4863+ *
4864+ * @param columnIndex the first column is <code>1</code>, the second
4865+ * is <code>2</code>, and so on; must be <code>1</code> or larger
4866+ * and equal to or less than the number of columns in this rowset
4867+ * @param x the new column value
4868+ * @param scale the number of digits to the right of the decimal point (for
4869+ * <code>DECIMAL</code> and <code>NUMERIC</code> types only)
4870+ * @throws SQLException if (1) the given column index is out of bounds,
4871+ * (2) the cursor is not on one of this rowset's rows or its
4872+ * insert row, or (3) this rowset is
4873+ * <code>ResultSet.CONCUR_READ_ONLY</code>
4874+ */
4875+ public void updateObject(int columnIndex, Object x, int scale) throws SQLException {
4876+ // sanity check.
4877+ checkIndex(columnIndex);
4878+ // make sure the cursor is on a valid row
4879+ checkCursor();
4880+
4881+ int type = RowSetMD.getColumnType(columnIndex);
4882+ if (type == Types.DECIMAL || type == Types.NUMERIC) {
4883+ ((java.math.BigDecimal)x).setScale(scale);
4884+ }
4885+ getCurrentRow().setColumnObject(columnIndex, x);
4886+ }
4887+
4888+ /**
4889+ * Sets the designated column in either the current row or the insert
4890+ * row of this <code>CachedRowSetImpl</code> object with the given
4891+ * <code>Object</code> value.
4892+ * <P>
4893+ * This method updates a column value in either the current row or
4894+ * the insert row of this rowset, but it does not update the
4895+ * database. If the cursor is on a row in the rowset, the
4896+ * method {@link #updateRow} must be called to update the database.
4897+ * If the cursor is on the insert row, the method {@link #insertRow}
4898+ * must be called, which will insert the new row into both this rowset
4899+ * and the database. Both of these methods must be called before the
4900+ * cursor moves to another row.
4901+ *
4902+ * @param columnIndex the first column is <code>1</code>, the second
4903+ * is <code>2</code>, and so on; must be <code>1</code> or larger
4904+ * and equal to or less than the number of columns in this rowset
4905+ * @param x the new column value
4906+ * @throws SQLException if (1) the given column index is out of bounds,
4907+ * (2) the cursor is not on one of this rowset's rows or its
4908+ * insert row, or (3) this rowset is
4909+ * <code>ResultSet.CONCUR_READ_ONLY</code>
4910+ */
4911+ public void updateObject(int columnIndex, Object x) throws SQLException {
4912+ // sanity check.
4913+ checkIndex(columnIndex);
4914+ // make sure the cursor is on a valid row
4915+ checkCursor();
4916+
4917+ getCurrentRow().setColumnObject(columnIndex, x);
4918+ }
4919+
4920+ /**
4921+ * Sets the designated nullable column in the current row or the
4922+ * insert row of this <code>CachedRowSetImpl</code> object with
4923+ * <code>null</code> value.
4924+ * <P>
4925+ * This method updates a column value in the current row or the insert
4926+ * row of this rowset, but it does not update the database.
4927+ * If the cursor is on a row in the rowset, the
4928+ * method {@link #updateRow} must be called to update the database.
4929+ * If the cursor is on the insert row, the method {@link #insertRow}
4930+ * must be called, which will insert the new row into both this rowset
4931+ * and the database.
4932+ *
4933+ * @param columnName a <code>String</code> object that must match the
4934+ * SQL name of a column in this rowset, ignoring case
4935+ * @throws SQLException if (1) the given column name does not match the
4936+ * name of a column in this rowset, (2) the cursor is not on
4937+ * one of this rowset's rows or its insert row, or (3) this
4938+ * rowset is <code>ResultSet.CONCUR_READ_ONLY</code>
4939+ */
4940+ public void updateNull(String columnName) throws SQLException {
4941+ updateNull(getColIdxByName(columnName));
4942+ }
4943+
4944+ /**
4945+ * Sets the designated column in either the current row or the insert
4946+ * row of this <code>CachedRowSetImpl</code> object with the given
4947+ * <code>boolean</code> value.
4948+ * <P>
4949+ * This method updates a column value in the current row or the insert
4950+ * row of this rowset, but it does not update the database.
4951+ * If the cursor is on a row in the rowset, the
4952+ * method {@link #updateRow} must be called to update the database.
4953+ * If the cursor is on the insert row, the method {@link #insertRow}
4954+ * must be called, which will insert the new row into both this rowset
4955+ * and the database. Both of these methods must be called before the
4956+ * cursor moves to another row.
4957+ *
4958+ * @param columnName a <code>String</code> object that must match the
4959+ * SQL name of a column in this rowset, ignoring case
4960+ * @param x the new column value
4961+ * @throws SQLException if (1) the given column name does not match the
4962+ * name of a column in this rowset, (2) the cursor is not on
4963+ * one of this rowset's rows or its insert row, or (3) this
4964+ * rowset is <code>ResultSet.CONCUR_READ_ONLY</code>
4965+ */
4966+ public void updateBoolean(String columnName, boolean x) throws SQLException {
4967+ updateBoolean(getColIdxByName(columnName), x);
4968+ }
4969+
4970+ /**
4971+ * Sets the designated column in either the current row or the insert
4972+ * row of this <code>CachedRowSetImpl</code> object with the given
4973+ * <code>byte</code> value.
4974+ * <P>
4975+ * This method updates a column value in the current row or the insert
4976+ * row of this rowset, but it does not update the database.
4977+ * If the cursor is on a row in the rowset, the
4978+ * method {@link #updateRow} must be called to update the database.
4979+ * If the cursor is on the insert row, the method {@link #insertRow}
4980+ * must be called, which will insert the new row into both this rowset
4981+ * and the database. Both of these methods must be called before the
4982+ * cursor moves to another row.
4983+ *
4984+ * @param columnName a <code>String</code> object that must match the
4985+ * SQL name of a column in this rowset, ignoring case
4986+ * @param x the new column value
4987+ * @throws SQLException if (1) the given column name does not match the
4988+ * name of a column in this rowset, (2) the cursor is not on
4989+ * one of this rowset's rows or its insert row, or (3) this
4990+ * rowset is <code>ResultSet.CONCUR_READ_ONLY</code>
4991+ */
4992+ public void updateByte(String columnName, byte x) throws SQLException {
4993+ updateByte(getColIdxByName(columnName), x);
4994+ }
4995+
4996+ /**
4997+ * Sets the designated column in either the current row or the insert
4998+ * row of this <code>CachedRowSetImpl</code> object with the given
4999+ * <code>short</code> value.

5134 more lines aren’t shown here.