0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041: package com.sun.sql.rowset;
0042:
0043: import javax.sql.rowset.*;
0044: import java.sql.*;
0045: import javax.sql.*;
0046: import javax.naming.*;
0047: import java.io.*;
0048: import java.math.*;
0049: import java.text.MessageFormat;
0050: import java.util.*;
0051:
0052: import java.beans.PropertyChangeListener;
0053: import java.beans.PropertyChangeSupport;
0054:
0055: import java.io.Serializable;
0056:
0057: import java.text.DateFormat;
0058: import java.text.ParseException;
0059:
0060: import javax.sql.rowset.serial.SerialArray;
0061: import javax.sql.rowset.serial.SerialBlob;
0062: import javax.sql.rowset.serial.SerialClob;
0063: import javax.sql.rowset.serial.SerialRef;
0064: import javax.sql.rowset.serial.SerialStruct;
0065: import javax.sql.rowset.serial.SQLInputImpl;
0066:
0067: import javax.sql.rowset.spi.SyncFactory;
0068: import javax.sql.rowset.spi.SyncProvider;
0069: import javax.sql.rowset.spi.SyncProviderException;
0070: import javax.sql.rowset.spi.TransactionalWriter;
0071:
0072: import com.sun.rowset.internal.BaseRow;
0073: import com.sun.rowset.internal.InsertRow;
0074: import com.sun.rowset.internal.Row;
0075:
0076: import com.sun.sql.rowset.internal.CachedRowSetXReader;
0077: import com.sun.sql.rowset.internal.CachedRowSetXWriter;
0078:
0079: /**
0080: * The reference implementation of the <code>CachedRowSetX</code> interface. See the interface
0081: * definition for full behavior and implementation requirements.
0082: *
0083: * Note: This implementation is based on the Sun Microsystems Reference Implemenation of
0084: * <code>CachedRowSet</code>
0085: *
0086: * All jdbc4.0-specific methods have been split offinto a sub-class CachedRowSetXImpl, to
0087: * enable usage in both JDK5 and JDK6. This class, which has been made abstract, is
0088: * used in the BeanInfo when running in JDK5.
0089: */
0090:
0091: public abstract class CachedRowSetXImpl5 extends BaseRowSetX implements
0092: CachedRowSetX, RowSetInternal, Serializable, Cloneable {
0093:
0094: protected static ResourceBundle rb = ResourceBundle.getBundle(
0095: "com.sun.sql.rowset.Bundle", Locale.getDefault()); // NOI18N
0096:
0097: /**
0098: * The <code>PropertyChangeSupport</code> object helps in providing
0099: * support for property change listeners.
0100: */
0101: protected PropertyChangeSupport propertyChangeSupport;
0102:
0103: /**
0104: * The <code>executed</code> flag tells us whether to throw exceptions
0105: * when methods are called that require the rowset to have been executed
0106: */
0107: private boolean executed;
0108:
0109: /**
0110: * The <code>internalUseInstance</code> flag tells to ignore exceptional conditions
0111: * with regard to the rowset not being executed. We must do this because this class
0112: * is also used internally and methods are called that would result in a rowset not
0113: * executed sqlexception if the user called them.
0114: */
0115: protected boolean internalUseInstance;
0116:
0117: protected void initParams() {
0118: super .initParams();
0119: propertyChangeSupport = new PropertyChangeSupport(this );
0120: insertableColumns = null;
0121: }
0122:
0123: /**
0124: * {@inheritDoc}
0125: */
0126: public boolean isExecuted() throws SQLException {
0127: return executed;
0128: }
0129:
0130: void checkExecuted() throws SQLException {
0131: // Don't throw an exception in the middle of commit or rollback changes
0132: if (internalUseInstance) {
0133: return;
0134: }
0135: // make sure we have a resultset (methods such as next()
0136: // prev(), first(), last(), beforeFirst(), beforeLast(),
0137: // getString() ,setString(), etc, etc., etc., will throw
0138: // a NPE if there is not resultset internally because
0139: // the rowset wasn't executed
0140: //
0141: // If the row set metadata has been set, even though we never
0142: // executed a command, then this is OK too. This is a cached
0143: // row set and can be initialized without executing a command.
0144: if (!isExecuted() && this .rowSetMD == null) {
0145: throw new SQLException(rb.getString("EXECUTE_NEVER_CALLED")); //NOI18N
0146: }
0147: }
0148:
0149: /**
0150: * {@inheritDoc}
0151: */
0152: public void setDataSourceName(String dataSourceName)
0153: throws SQLException {
0154: String oldValue = getDataSourceName();
0155: super .setDataSourceName(dataSourceName);
0156: release();
0157: propertyChangeSupport.firePropertyChange("dataSourceName",
0158: oldValue, dataSourceName); // NOI18N
0159: }
0160:
0161: /**
0162: * {@inheritDoc}
0163: */
0164: public void setUrl(String url) throws SQLException {
0165: String oldValue = getUrl();
0166: super .setUrl(url);
0167: release();
0168: propertyChangeSupport.firePropertyChange("url", oldValue, url); // NOI18N
0169: }
0170:
0171: /**
0172: * {@inheritDoc}
0173: */
0174: public void setUsername(String username) {
0175: String oldValue = getUsername();
0176: super .setUsername(username);
0177: try {
0178: release();
0179: } catch (SQLException e) {
0180: }
0181: propertyChangeSupport.firePropertyChange("username", oldValue,
0182: username); // NOI18N
0183: }
0184:
0185: /**
0186: * {@inheritDoc}
0187: */
0188: public void setPassword(String password) {
0189: String oldValue = getPassword();
0190: super .setPassword(password);
0191: propertyChangeSupport.firePropertyChange("password", oldValue,
0192: password); // NOI18N
0193: }
0194:
0195: /**
0196: * {@inheritDoc}
0197: */
0198: public void setType(int type) throws SQLException {
0199: int oldValue = 0;
0200: try {
0201: oldValue = getType();
0202: } catch (SQLException e) {
0203: }
0204: super .setType(type);
0205: propertyChangeSupport
0206: .firePropertyChange("type", oldValue, type); // NOI18N
0207: }
0208:
0209: /**
0210: * {@inheritDoc}
0211: */
0212: public void setConcurrency(int concurrency) throws SQLException {
0213: int oldValue = 0;
0214: try {
0215: oldValue = getConcurrency();
0216: } catch (SQLException e) {
0217: }
0218: super .setConcurrency(concurrency);
0219: propertyChangeSupport.firePropertyChange("concurrency",
0220: oldValue, concurrency); // NOI18N
0221: }
0222:
0223: /**
0224: * {@inheritDoc}
0225: */
0226: public void setTransactionIsolation(int transactionIsolation)
0227: throws SQLException {
0228: int oldValue = getTransactionIsolation();
0229: super .setTransactionIsolation(transactionIsolation);
0230: propertyChangeSupport.firePropertyChange(
0231: "transactionIsolation", oldValue, //NOI18N
0232: transactionIsolation); // NOI18N
0233: }
0234:
0235: /**
0236: * {@inheritDoc}
0237: */
0238: public void setMaxRows(int maxRows) throws SQLException {
0239: int oldValue = 0;
0240: try {
0241: oldValue = getMaxRows();
0242: } catch (SQLException e) {
0243: }
0244: super .setMaxRows(maxRows);
0245: propertyChangeSupport.firePropertyChange("maxRows", oldValue,
0246: maxRows); // NOI18N
0247: }
0248:
0249: /**
0250: * {@inheritDoc}
0251: */
0252: public void setReadOnly(boolean isReadOnly) {
0253: if (isReadOnly() != isReadOnly) {
0254: boolean oldValue = isReadOnly();
0255: super .setReadOnly(isReadOnly);
0256: propertyChangeSupport.firePropertyChange("readOnly",
0257: oldValue, isReadOnly); // NOI18N
0258: }
0259: }
0260:
0261: //--------------------------------------------------------------------
0262: // PropertyChangeEvents
0263: //--------------------------------------------------------------------
0264:
0265: /**
0266: * {@inheritDoc}
0267: */
0268: public void addPropertyChangeListener(
0269: PropertyChangeListener listener) {
0270: propertyChangeSupport.addPropertyChangeListener(listener);
0271: }
0272:
0273: /**
0274: * {@inheritDoc}
0275: */
0276: public void addPropertyChangeListener(String propertyName,
0277: PropertyChangeListener listener) {
0278: propertyChangeSupport.addPropertyChangeListener(propertyName,
0279: listener);
0280: }
0281:
0282: /**
0283: * {@inheritDoc}
0284: * @deprecated
0285: */
0286: public void removePropertyChangeListener(
0287: PropertyChangeListener listener) {
0288: propertyChangeSupport.removePropertyChangeListener(listener);
0289: };
0290:
0291: /**
0292: * {@inheritDoc}
0293: */
0294: public void removePropertyChangeListener(String propertyName,
0295: PropertyChangeListener listener) {
0296: propertyChangeSupport.removePropertyChangeListener(
0297: propertyName, listener);
0298: }
0299:
0300: /**
0301: * The <code>SyncProvider</code> used by the CachedRowSet
0302: */
0303: protected SyncProvider provider;
0304:
0305: /**
0306: * The <code>RowSetReaderImpl</code> object that is the reader
0307: * for this rowset. The method <code>execute</code> uses this
0308: * reader as part of its implementation.
0309: * @serial
0310: */
0311: protected RowSetReader rowSetReader;
0312:
0313: /**
0314: * The <code>RowSetWriterImpl</code> object that is the writer
0315: * for this rowset. The method <code>acceptChanges</code> uses
0316: * this writer as part of its implementation.
0317: * @serial
0318: */
0319: protected RowSetWriter rowSetWriter;
0320:
0321: /**
0322: * The <code>Connection</code> object that connects with this
0323: * <code>CachedRowSetXImpl</code> object's current underlying data source.
0324: */
0325: private transient Connection conn;
0326:
0327: /**
0328: * The <code>ResultSetMetaData</code> object that contains information
0329: * about the columns in the <code>ResultSet</code> object that is the
0330: * current source of data for this <code>CachedRowSetXImpl</code> object.
0331: */
0332: private transient ResultSetMetaData rsmd;
0333:
0334: /**
0335: * The <code>RowSetMetaData</code> object that contains information about
0336: * the columns in this <code>CachedRowSetXImpl</code> object.
0337: * @serial
0338: */
0339: protected RowSetMetaData rowSetMD;
0340:
0341: // Properties of this RowSet
0342:
0343: /**
0344: * An array containing the columns in this <code>CachedRowSetXImpl</code>
0345: * object that form a unique identifier for a row. This array
0346: * is used by the writer.
0347: * @serial
0348: */
0349: private int keyCols[];
0350:
0351: /**
0352: * The name of the table in the underlying database to which updates
0353: * should be written. This name is needed because most drivers
0354: * do not return this information in a <code>ResultSetMetaData</code>
0355: * object.
0356: * @serial
0357: */
0358: private String tableName;
0359:
0360: /**
0361: * A <code>Vector</code> object containing the <code>Row</code>
0362: * objects that comprise this <code>CachedRowSetXImpl</code> object.
0363: * @serial
0364: */
0365: protected Vector rvh;
0366: /**
0367: * The current postion of the cursor in this <code>CachedRowSetXImpl</code>
0368: * object.
0369: * @serial
0370: */
0371: protected int cursorPos;
0372:
0373: /**
0374: * The current postion of the cursor in this <code>CachedRowSetXImpl</code>
0375: * object not counting rows that have been deleted, if any.
0376: * <P>
0377: * For example, suppose that the cursor is on the last row of a rowset
0378: * that started with five rows and subsequently had the second and third
0379: * rows deleted. The <code>absolutePos</code> would be <code>3</code>,
0380: * whereas the <code>cursorPos</code> would be <code>5</code>.
0381: * @serial
0382: */
0383: private int absolutePos;
0384:
0385: /**
0386: * The number of deleted rows currently in this <code>CachedRowSetXImpl</code>
0387: * object.
0388: * @serial
0389: */
0390: protected int numDeleted;
0391:
0392: /**
0393: * The total number of rows currently in this <code>CachedRowSetXImpl</code>
0394: * object.
0395: * @serial
0396: */
0397: protected int numRows;
0398:
0399: /**
0400: * A special row used for constructing a new row. A new
0401: * row is constructed by using <code>ResultSet.updateXXX</code>
0402: * methods to insert column values into the insert row.
0403: * @serial
0404: */
0405: private InsertRow insertRow;
0406:
0407: /**
0408: * A <code>boolean</code> indicating whether the cursor is
0409: * currently on the insert row.
0410: * @serial
0411: */
0412: private boolean onInsertRow;
0413:
0414: /**
0415: * The field that temporarily holds the last position of the
0416: * cursor before it moved to the insert row, thus preserving
0417: * the number of the current row to which the cursor may return.
0418: * @serial
0419: */
0420: private int currentRow;
0421:
0422: /**
0423: * A <code>boolean</code> indicating whether the last value
0424: * returned was an SQL <code>NULL</code>.
0425: * @serial
0426: */
0427: private boolean lastValueNull;
0428:
0429: /**
0430: * A <code>SQLWarning</code> which logs on the warnings
0431: */
0432: protected SQLWarning sqlwarn;
0433:
0434: /**
0435: * Used to track match column for JoinRowSet consumption
0436: */
0437: private String strMatchColumn = ""; //NOI18N
0438:
0439: /**
0440: * Used to track match column for JoinRowSet consumption
0441: */
0442: private int iMatchColumn = -1;
0443:
0444: /**
0445: * A <code>RowSetWarning</code> which logs on the warnings
0446: */
0447: protected RowSetWarning rowsetWarning;
0448:
0449: /**
0450: * The default SyncProvider for the RI CachedRowSetXImpl
0451: */
0452: private String DEFAULT_SYNC_PROVIDER = "com.sun.sql.rowset.providers.RIOptimisticProvider"; //NOI18N
0453:
0454: /**
0455: * The boolean variable indicating locatorsUpdateValue
0456: */
0457: private boolean dbmslocatorsUpdateCopy;
0458:
0459: /**
0460: * The <code>ResultSet</code> object that is used to maintain the data when
0461: * a ResultSet and start position are passed as parameters to the populate function
0462: */
0463: private ResultSet resultSet;
0464:
0465: /**
0466: * The integer value indicating the end position in the ResultSetwhere the picking
0467: * up of rows for populating a CachedRowSet object was left off.
0468: */
0469: private int endPos;
0470:
0471: /**
0472: * The integer value indicating the end position in the ResultSetwhere the picking
0473: * up of rows for populating a CachedRowSet object was left off.
0474: */
0475: private int prevEndPos;
0476:
0477: /**
0478: * The integer value indicating the position in the ResultSet, to populate the
0479: * CachedRowSet object.
0480: */
0481: private int startPos;
0482:
0483: /**
0484: * The integer value indicating the positon from where the page prior to this
0485: * was populated.
0486: */
0487: private int startPrev;
0488:
0489: /**
0490: * The integer value indicating size of the page.
0491: */
0492: private int pageSize;
0493:
0494: /**
0495: * The integer value indicating number of rows that have been processed so far.
0496: * Used for checking whether maxRows has been reached or not.
0497: */
0498: private int maxRowsreached;
0499: /**
0500: * The boolean value when true signifies that pages are still to follow and a
0501: * false value indicates that this is the last page.
0502: */
0503: private boolean pagenotend = true;
0504:
0505: /**
0506: * The boolean value indicating whether this is the first page or not.
0507: */
0508: private boolean onFirstPage;
0509:
0510: /**
0511: * The boolean value indicating whether this is the last page or not.
0512: */
0513: private boolean onLastPage;
0514:
0515: /**
0516: * The integer value indicating how many times the populate function has been called.
0517: */
0518: private int populatecallcount;
0519:
0520: /**
0521: * The integer value indicating the total number of rows to be processed in the
0522: * ResultSet object passed to the populate function.
0523: */
0524: private int totalRows;
0525:
0526: /**
0527: * The boolean value indicating how the CahedRowSet object has been populated for
0528: * paging purpose. True indicates that connection parameter is passed.
0529: */
0530: private boolean callWithCon;
0531:
0532: /**
0533: * CachedRowSet reader object to read the data from the ResultSet when a connection
0534: * parameter is passed to populate the CachedRowSet object for paging.
0535: */
0536: private CachedRowSetXReader crsReader;
0537:
0538: /**
0539: * The Vector holding the Match Columns
0540: */
0541: private Vector iMatchColumns;
0542:
0543: /**
0544: * The Vector that will hold the Match Column names.
0545: */
0546: private Vector strMatchColumns;
0547:
0548: /**
0549: * Trigger that indicates whether the active SyncProvider is exposes the
0550: * additional TransactionalWriter method
0551: */
0552: private boolean tXWriter = false;
0553:
0554: /**
0555: * The field object for a transactional RowSet writer
0556: */
0557: private TransactionalWriter tWriter = null;
0558:
0559: /**
0560: * Sets the <code>rvh</code> field to a new <code>Vector</code>
0561: * object with a capacity of 100 and sets the
0562: * <code>cursorPos</code> and <code>numRows</code> fields to zero.
0563: */
0564: protected void initContainer() {
0565:
0566: rvh = new Vector(100);
0567: cursorPos = 0;
0568: absolutePos = 0;
0569: numRows = 0;
0570: numDeleted = 0;
0571: rsmd = null;
0572: rowSetMD = null;
0573: }
0574:
0575: /**
0576: * Sets the properties for this <code>CachedRowSetXImpl</code> object to
0577: * their default values. This method is called internally by the
0578: * default constructor.
0579: */
0580:
0581: protected void initProperties() throws SQLException {
0582: setShowDeleted(false);
0583: setQueryTimeout(0);
0584: setMaxRows(0);
0585: setMaxFieldSize(0);
0586: setType(ResultSet.TYPE_SCROLL_INSENSITIVE);
0587: setConcurrency(ResultSet.CONCUR_UPDATABLE);
0588: setReadOnly(true);
0589: setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
0590: setEscapeProcessing(true);
0591: setTypeMap(null);
0592: checkTransactionalWriter();
0593:
0594: // insert row setup
0595: onInsertRow = false;
0596: insertRow = null;
0597:
0598: executed = false;
0599:
0600: //Instantiating the vector for MatchColumns
0601:
0602: iMatchColumns = new Vector(10);
0603: for (int i = 0; i < 10; i++) {
0604: iMatchColumns.add(i, new Integer(-1));
0605: }
0606:
0607: strMatchColumns = new Vector(10);
0608: for (int j = 0; j < 10; j++) {
0609: strMatchColumns.add(j, null);
0610: }
0611: }
0612:
0613: /**
0614: * Determine whether the SyncProvider's writer implements the
0615: * <code>TransactionalWriter<code> interface
0616: */
0617: private void checkTransactionalWriter() {
0618: if (rowSetWriter != null) {
0619: Class c = rowSetWriter.getClass();
0620: if (c != null) {
0621: Class[] theInterfaces = c.getInterfaces();
0622: for (int i = 0; i < theInterfaces.length; i++) {
0623: if ((theInterfaces[i].getName())
0624: .indexOf("TransactionalWriter") > 0) { //NOI18N
0625: tXWriter = true;
0626: establishTransactionalWriter();
0627: }
0628: }
0629: }
0630: }
0631: }
0632:
0633: /**
0634: * Sets an private field to all transaction bounddaries to be set
0635: */
0636: private void establishTransactionalWriter() {
0637: tWriter = (TransactionalWriter) provider.getRowSetWriter();
0638: }
0639:
0640: //-----------------------------------------------------------------------
0641: // Properties
0642: //-----------------------------------------------------------------------
0643:
0644: /**
0645: * {@inheritDoc}
0646: */
0647: public void setCommand(String command) throws SQLException {
0648:
0649: String oldValue = getCommand();
0650: super .setCommand(command);
0651: release();
0652: propertyChangeSupport.firePropertyChange("command", oldValue,
0653: command); // NOI18N
0654: }
0655:
0656: //---------------------------------------------------------------------
0657: // Reading and writing data
0658: //---------------------------------------------------------------------
0659:
0660: /**
0661: * {@inheritDoc}
0662: */
0663: public void populate(ResultSet data) throws SQLException {
0664: int rowsFetched;
0665: Row currentRow;
0666: int numCols;
0667: int i;
0668: Map map = getTypeMap();
0669: Object obj;
0670: int mRows;
0671:
0672: if (data == null) {
0673: throw new SQLException(rb
0674: .getString("INVALID_RESULTSET_SUPPLIED")); //NOI18N
0675: }
0676:
0677: // get the meta data for this ResultSet
0678: rsmd = data.getMetaData();
0679:
0680: // set up the metadata
0681: rowSetMD = new RowSetMetaDataXImpl();
0682: initMetaData(rowSetMD, rsmd);
0683:
0684: // release the meta-data so that aren't tempted to use it.
0685: rsmd = null;
0686: numCols = rowSetMD.getColumnCount();
0687: mRows = this .getMaxRows();
0688: rowsFetched = 0;
0689: currentRow = null;
0690:
0691: while (data.next()) {
0692:
0693: currentRow = new Row(numCols);
0694:
0695: if (rowsFetched > mRows && mRows > 0) {
0696: rowsetWarning.setNextWarning(new RowSetWarning(rb
0697: .getString("MAX_ROWS_EXCEEDED"))); //NOI18N
0698: }
0699:
0700: for (i = 1; i <= numCols; i++) {
0701: /*
0702: * check if the user has set a map. If no map
0703: * is set then use plain getObject. This lets
0704: * us work with drivers that do not support
0705: * getObject with a map in fairly sensible way
0706: */
0707: if (map == null) {
0708: obj = data.getObject(i);
0709: } else {
0710: obj = data.getObject(i, map);
0711: }
0712: /*
0713: * the following block checks for the various
0714: * types that we have to serialize in order to
0715: * store - right now only structs have been tested
0716: */
0717: if (obj instanceof Struct) {
0718: obj = new SerialStruct((Struct) obj, map);
0719: } else if (obj instanceof SQLData) {
0720: obj = new SerialStruct((SQLData) obj, map);
0721: } else if (obj instanceof Blob) {
0722: obj = new SerialBlob((Blob) obj);
0723: } else if (obj instanceof Clob) {
0724: obj = new SerialClob((Clob) obj);
0725: } else if (obj instanceof java.sql.Array) {
0726: obj = new SerialArray((java.sql.Array) obj, map);
0727: }
0728:
0729: ((Row) currentRow).initColumnObject(i, obj);
0730: }
0731: rowsFetched++;
0732: rvh.add(currentRow);
0733: }
0734: executed = true;
0735:
0736: numRows = rowsFetched;
0737: // Also rowsFetched should be equal to rvh.size()
0738:
0739: // notify any listeners that the rowset has changed
0740: notifyRowSetChanged();
0741: }
0742:
0743: /**
0744: * Initializes the given <code>RowSetMetaData</code> object with the values
0745: * in the given <code>ResultSetMetaData</code> object.
0746: *
0747: * @param md the <code>RowSetMetaData</code> object for this
0748: * <code>CachedRowSetXImpl</code> object, which will be set with
0749: * values from rsmd
0750: * @param rsmd the <code>ResultSetMetaData</code> object from which new
0751: * values for md will be read
0752: * @throws SQLException if an error occurs
0753: */
0754: private void initMetaData(RowSetMetaData md, ResultSetMetaData rsmd)
0755: throws SQLException {
0756:
0757: RowSetMetaDataX mdx = null;
0758: if (md instanceof RowSetMetaDataX) {
0759: mdx = (RowSetMetaDataX) md;
0760: }
0761:
0762: Log.getLogger()
0763: .entering(getClass().getName(), "initMetaData()");
0764: int numCols = rsmd.getColumnCount();
0765:
0766: md.setColumnCount(numCols);
0767: for (int col = 1; col <= numCols; col++) {
0768: md.setAutoIncrement(col, rsmd.isAutoIncrement(col));
0769: md.setCaseSensitive(col, rsmd.isCaseSensitive(col));
0770: md.setCurrency(col, rsmd.isCurrency(col));
0771: md.setNullable(col, rsmd.isNullable(col));
0772: md.setSigned(col, rsmd.isSigned(col));
0773: md.setSearchable(col, rsmd.isSearchable(col));
0774:
0775: /*
0776: * The PostgreSQL drivers sometimes return negative columnDisplaySize,
0777: * which causes an exception to be thrown. Check for it.
0778: */
0779: int size = rsmd.getColumnDisplaySize(col);
0780: if (size < 0) {
0781: size = 0;
0782: }
0783: md.setColumnDisplaySize(col, size);
0784:
0785: md.setColumnLabel(col, rsmd.getColumnLabel(col));
0786: md.setColumnName(col, rsmd.getColumnName(col));
0787: md.setSchemaName(col, rsmd.getSchemaName(col));
0788:
0789: /*
0790: * Drivers return some strange values for precision, for non-numeric data, including reports of
0791: * non-integer values; maybe we should check type, & set to 0 for non-numeric types.
0792: */
0793: int precision = rsmd.getPrecision(col);
0794: if (precision < 0) {
0795: precision = 0;
0796: }
0797: md.setPrecision(col, precision);
0798:
0799: /*
0800: * It seems, from a bug report, that a driver can sometimes return a negative
0801: * value for scale. javax.sql.rowset.RowSetMetaDataImpl will throw an exception
0802: * if we attempt to set a negative value. As such, we'll check for this case.
0803: */
0804: int scale = rsmd.getScale(col);
0805: if (scale < 0) {
0806: scale = 0;
0807: }
0808: md.setScale(col, scale);
0809:
0810: md.setTableName(col, rsmd.getTableName(col));
0811: md.setCatalogName(col, rsmd.getCatalogName(col));
0812: md.setColumnType(col, rsmd.getColumnType(col));
0813: md.setColumnTypeName(col, rsmd.getColumnTypeName(col));
0814:
0815: if (mdx != null) {
0816: mdx.setColumnClassName(col, rsmd
0817: .getColumnClassName(col));
0818: /*
0819: * We face a dilemna here. The RI always says columns are writable.
0820: * We'd like to give a better answer; but since we allow joins that
0821: * would result in the database saying all columns are readonly, we
0822: * can't just hand back the information the driver gives about the
0823: * resultset. As such, we would really like to compute if the column is
0824: * writable in much the same way that CachedRowSetXWriter computes this
0825: * information. For now, we'll return true unless the user has provided
0826: * information otherwise in the updatable columns on the rowset.
0827: *
0828: * Actually, even this will cause problems as there is a difference between
0829: * insertable and updatable. We want to allow new rows to specify insertable
0830: * columns that are not updatable. So we will actually honor insertable if it
0831: * is present. If not, we'll use updatable if present. If not, we'll say the
0832: * column is writable.
0833: */
0834: if (insertableColumns != null
0835: && insertableColumns.length >= col) {
0836: mdx.setWritable(col, insertableColumns[col - 1]);
0837: mdx.setDefinitelyWritable(col,
0838: insertableColumns[col - 1]);
0839: mdx.setReadOnly(col, !insertableColumns[col - 1]);
0840: } else if (updatableColumns != null
0841: && updatableColumns.length >= col) {
0842: mdx.setWritable(col, updatableColumns[col - 1]);
0843: mdx.setDefinitelyWritable(col,
0844: updatableColumns[col - 1]);
0845: mdx.setReadOnly(col, !updatableColumns[col - 1]);
0846: } else {
0847: mdx.setWritable(col, true);
0848: mdx.setDefinitelyWritable(col, false); // We don't know for sure
0849: mdx.setReadOnly(col, false);
0850: }
0851: }
0852:
0853: dbmslocatorsUpdateCopy = false;
0854: if (conn != null) {
0855: try {
0856: dbmslocatorsUpdateCopy = conn.getMetaData()
0857: .locatorsUpdateCopy();
0858: } catch (SQLException e) {
0859: // It seems, some databases throw an exception here (e.g., Pointbase)
0860: // assume false (so updateClob/Blob will not work)
0861: }
0862: }
0863: }
0864: }
0865:
0866: /**
0867: * {@inheritDoc}
0868: */
0869: public void execute(Connection conn) throws SQLException {
0870:
0871: Log.getLogger().entering(getClass().getName(), "execute()");
0872:
0873: // store the connection so the reader can find it.
0874: setConnection(conn);
0875:
0876: if (getPageSize() != 0) {
0877: crsReader = (CachedRowSetXReader) provider
0878: .getRowSetReader();
0879: crsReader.setStartPosition(1);
0880: callWithCon = true;
0881: crsReader.readData((RowSetInternal) this );
0882: }
0883:
0884: // Now call the current reader's readData method
0885: else {
0886: rowSetReader.readData((RowSetInternal) this );
0887: }
0888:
0889: executed = true;
0890:
0891: rowSetMD = (RowSetMetaDataXImpl) this .getMetaData();
0892:
0893: if (conn != null) {
0894: try {
0895: dbmslocatorsUpdateCopy = conn.getMetaData()
0896: .locatorsUpdateCopy();
0897: } catch (SQLException e) {
0898: // It seems, some databases throw an exception here (e.g., Pointbase)
0899: // assume false (so updateClob/Blob will not work)
0900: dbmslocatorsUpdateCopy = false;
0901: }
0902: } else {
0903: Connection tempConn = null;
0904: try {
0905: tempConn = getConnection(getDataSourceName(), getUrl(),
0906: getUsername(), getPassword());
0907: dbmslocatorsUpdateCopy = tempConn.getMetaData()
0908: .locatorsUpdateCopy();
0909: } catch (SQLException e) {
0910: // It seems, some databases throw an exception here (e.g., Pointbase)
0911: // assume false (so updateClob/Blob will not work)
0912: dbmslocatorsUpdateCopy = false;
0913: } catch (AbstractMethodError e) {
0914: // Some drivers (e.g., Oracle 9) don't implement the locatorsUpdateCopy() method.
0915: // Assume false (so updateClob/Blob will not work)
0916: dbmslocatorsUpdateCopy = false;
0917: } finally {
0918: if (tempConn != null) {
0919: try {
0920: if (!tempConn.getAutoCommit()) {
0921: tempConn.rollback();
0922: }
0923: } catch (Exception dummy) {
0924: /*
0925: * not an error condition, we're closing anyway, but
0926: * we'd like to clean up any locks if we can since
0927: * it is not clear the connection pool will clean
0928: * these connections in a timely manner
0929: */
0930: }
0931: tempConn.close();
0932: }
0933: }
0934: }
0935: }
0936:
0937: /**
0938: * Sets this <code>CachedRowSetXImpl</code> object's connection property
0939: * to the given <code>Connection</code> object. This method is called
0940: * internally by the version of the method <code>execute</code> that takes a
0941: * <code>Connection</code> object as an argument. The reader for this
0942: * <code>CachedRowSetXImpl</code> object can retrieve the connection stored
0943: * in the rowset's connection property by calling its
0944: * <code>getConnection</code> method.
0945: *
0946: * @param connection the <code>Connection</code> object that was passed in
0947: * to the method <code>execute</code> and is to be stored
0948: * in this <code>CachedRowSetXImpl</code> object's connection
0949: * property
0950: */
0951: private void setConnection(Connection connection) {
0952: conn = connection;
0953: }
0954:
0955: /**
0956: * {@inheritDoc}
0957: */
0958: public void acceptChanges() throws SyncProviderException {
0959: try {
0960: checkExecuted();
0961: } catch (SQLException e) {
0962: throw new SyncProviderException(e.getMessage());
0963: }
0964: if (onInsertRow == true) {
0965: throw new SyncProviderException(rb
0966: .getString("INVALID_INSERT_ROW_OP")); //NOI18N
0967: }
0968:
0969: int saveCursorPos = cursorPos;
0970: boolean success = false;
0971: boolean conflict = false;
0972:
0973: try {
0974: if (rowSetWriter != null) {
0975: saveCursorPos = cursorPos;
0976: conflict = rowSetWriter
0977: .writeData((RowSetInternal) this );
0978: cursorPos = saveCursorPos;
0979: }
0980:
0981: if ((tXWriter) && this .COMMIT_ON_ACCEPT_CHANGES) {
0982: // do commit/rollback's here
0983: if (!conflict) {
0984: tWriter = (TransactionalWriter) rowSetWriter;
0985: tWriter.rollback();
0986: success = false;
0987: } else {
0988: tWriter = (TransactionalWriter) rowSetWriter;
0989: tWriter.commit();
0990: success = true;
0991: }
0992: }
0993:
0994: if (success == true) {
0995: setOriginal();
0996: } else if (!(success) && !(this .COMMIT_ON_ACCEPT_CHANGES)) {
0997: throw new SyncProviderException(rb
0998: .getString("ACCEPT_CHANGES_FAILED")); //NOI18N
0999: }
1000:
1001: } catch (SyncProviderException spe) {
1002: throw spe;
1003: } catch (SQLException e) {
1004: e.printStackTrace();
1005: throw new SyncProviderException(e.getMessage());
1006: } catch (SecurityException e) {
1007: throw new SyncProviderException(e.getMessage());
1008: } finally {
1009: try {
1010: if (tWriter instanceof CachedRowSetXWriter) {
1011: ((CachedRowSetXWriter) tWriter).closeConnection();
1012: }
1013: } catch (SQLException e) {
1014: // well, we tried
1015: }
1016: }
1017: }
1018:
1019: /**
1020: * {@inheritDoc}
1021: */
1022: public void acceptChanges(Connection con)
1023: throws SyncProviderException {
1024:
1025: try {
1026: checkExecuted();
1027: setConnection(con);
1028: acceptChanges();
1029: } catch (SyncProviderException spe) {
1030: throw spe;
1031: } catch (SQLException sqle) {
1032: throw new SyncProviderException(sqle.getMessage());
1033: }
1034: }
1035:
1036: /**
1037: * {@inheritDoc}
1038: */
1039: public void restoreOriginal() throws SQLException {
1040: checkExecuted();
1041: Row currentRow;
1042: for (Iterator i = rvh.iterator(); i.hasNext();) {
1043: currentRow = (Row) i.next();
1044: if (currentRow.getInserted() == true) {
1045: i.remove();
1046: --numRows;
1047: } else {
1048: if (currentRow.getDeleted() == true) {
1049: currentRow.clearDeleted();
1050: //!JK shouldn't we be doing a ++numRows here?
1051: }
1052: if (currentRow.getUpdated() == true) {
1053: currentRow.clearUpdated();
1054: }
1055: }
1056: }
1057: // move to before the first
1058: cursorPos = 0;
1059: absolutePos = 0; //!JK: added this
1060:
1061: // notify any listeners
1062: notifyRowSetChanged();
1063: }
1064:
1065: /**
1066: * {@inheritDoc}
1067: */
1068: public void release() throws SQLException {
1069: initContainer();
1070: executed = false;
1071: notifyRowSetChanged();
1072: }
1073:
1074: /**
1075: * {@inheritDoc}
1076: */
1077: public void undoDelete() throws SQLException {
1078: checkExecuted();
1079: if (getShowDeleted() == false) {
1080: return;
1081: }
1082: // make sure we are on a row
1083: checkCursor();
1084:
1085: // don't want this to happen...
1086: if (onInsertRow == true) {
1087: throw new SQLException(rb.getString("INVALID_CURSOR_POS")); //NOI18N
1088: }
1089:
1090: Row currentRow = (Row) getCurrentRow();
1091: if (currentRow.getDeleted() == true) {
1092: currentRow.clearDeleted();
1093: --numDeleted;
1094: notifyRowChanged();
1095: }
1096: }
1097:
1098: /**
1099: * {@inheritDoc}
1100: */
1101: public void undoInsert() throws SQLException {
1102: checkExecuted();
1103: // make sure we are on a row
1104: checkCursor();
1105:
1106: // don't want this to happen...
1107: if (onInsertRow == true) {
1108: throw new SQLException(rb.getString("INVALID_CURSOR_POS")); //NOI18N
1109: }
1110:
1111: Row currentRow = (Row) getCurrentRow();
1112: if (currentRow.getInserted() == true) {
1113: rvh.remove(cursorPos);
1114: --numRows;
1115: notifyRowChanged();
1116: } else {
1117: throw new SQLException(rb
1118: .getString("INVALID_INSERT_ROW_OP")); //NOI18N
1119: }
1120: }
1121:
1122: /**
1123: * {@inheritDoc}
1124: */
1125: public void undoUpdate() throws SQLException {
1126: checkExecuted();
1127: // if on insert row, cancel the insert row
1128: // make the insert row flag,
1129: // cursorPos back to the current row
1130: moveToCurrentRow();
1131:
1132: // else if not on insert row
1133: // call undoUpdate or undoInsert
1134: undoDelete();
1135:
1136: undoInsert();
1137:
1138: }
1139:
1140: //--------------------------------------------------------------------
1141: // Views
1142: //--------------------------------------------------------------------
1143:
1144: /**
1145: * {@inheritDoc}
1146: */
1147: public RowSet createShared() throws SQLException {
1148: checkExecuted(); //!JK ?
1149: RowSet clone;
1150: try {
1151: clone = (RowSet) clone();
1152: } catch (CloneNotSupportedException ex) {
1153: throw new SQLException(ex.getMessage());
1154: }
1155: return clone;
1156: }
1157:
1158: /**
1159: * Returns a new <code>RowSet</code> object containing by the same data
1160: * as this <code>CachedRowSetXImpl</code> object. This method
1161: * differs from the method <code>createCopy</code> in that it throws a
1162: * <code>CloneNotSupportedException</code> object instead of an
1163: * <code>SQLException</code> object, as the method <code>createShared</code>
1164: * does. This <code>clone</code>
1165: * method is called internally by the method <code>createShared</code>,
1166: * which catches the <code>CloneNotSupportedException</code> object
1167: * and in turn throws a new <code>SQLException</code> object.
1168: *
1169: * @return a copy of this <code>CachedRowSetXImpl</code> object
1170: * @throws CloneNotSupportedException if an error occurs when
1171: * attempting to clone this <code>CachedRowSetXImpl</code> object
1172: * @see #createShared
1173: */
1174: protected Object clone() throws CloneNotSupportedException {
1175: return (super .clone());
1176: }
1177:
1178: /**
1179: * {@inheritDoc}
1180: */
1181: public CachedRowSet createCopy() throws SQLException {
1182: checkExecuted(); //!JK ?
1183: ObjectOutputStream out;
1184: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
1185: try {
1186: out = new ObjectOutputStream(bOut);
1187: out.writeObject(this );
1188: } catch (IOException ex) {
1189: throw new SQLException(rb.getString("CLONE_FAILED"
1190: + ex.getMessage())); //NOI18N
1191: }
1192:
1193: ObjectInputStream in;
1194:
1195: try {
1196: ByteArrayInputStream bIn = new ByteArrayInputStream(bOut
1197: .toByteArray());
1198: in = new ObjectInputStream(bIn);
1199: } catch (StreamCorruptedException ex) {
1200: throw new SQLException(rb.getString("CLONE_FAILED"
1201: + ex.getMessage())); //NOI18N
1202: } catch (IOException ex) {
1203: throw new SQLException(rb.getString("CLONE_FAILED"
1204: + ex.getMessage())); //NOI18N
1205: }
1206:
1207: try {
1208: return ((CachedRowSet) (in.readObject()));
1209: } catch (ClassNotFoundException ex) {
1210: throw new SQLException(rb.getString("CLONE_FAILED"
1211: + ex.getMessage())); //NOI18N
1212: } catch (OptionalDataException ex) {
1213: throw new SQLException(rb.getString("CLONE_FAILED"
1214: + ex.getMessage())); //NOI18N
1215: } catch (IOException ex) {
1216: throw new SQLException(rb.getString("CLONE_FAILED"
1217: + ex.getMessage())); //NOI18N
1218: }
1219: }
1220:
1221: /**
1222: * {@inheritDoc}
1223: */
1224: public CachedRowSet createCopySchema() throws SQLException {
1225: checkExecuted(); //!JK ?
1226: // Copy everything except data i.e all constraints
1227:
1228: // Store the number of rows of "this"
1229: // and make numRows equals zero.
1230: // and make data also zero.
1231: int nRows = numRows;
1232: numRows = 0;
1233:
1234: CachedRowSet crs = this .createCopy();
1235:
1236: // reset this object back to number of rows.
1237: numRows = nRows;
1238:
1239: return crs;
1240: }
1241:
1242: /**
1243: * {@inheritDoc}
1244: */
1245: public CachedRowSet createCopyNoConstraints() throws SQLException {
1246: checkExecuted(); //!JK ?
1247: // Copy the whole data ONLY without any constraints.
1248: CachedRowSetXImpl5 crs;
1249: crs = (CachedRowSetXImpl5) this .createCopy();
1250:
1251: crs.initProperties();
1252: try {
1253: crs.unsetMatchColumn(crs.getMatchColumnIndexes());
1254: } catch (SQLException sqle) {
1255: //do nothing, if the setMatchColumn is not set.
1256: }
1257:
1258: try {
1259: crs.unsetMatchColumn(crs.getMatchColumnNames());
1260: } catch (SQLException sqle) {
1261: //do nothing, if the setMatchColumn is not set.
1262: }
1263:
1264: return crs;
1265: }
1266:
1267: /**
1268: * {@inheritDoc}
1269: */
1270: public Collection toCollection() throws SQLException {
1271: checkExecuted(); //!JK ?
1272:
1273: TreeMap tMap;
1274: int count = 0;
1275: Row origRow;
1276: Vector newRow;
1277:
1278: int colCount = rowSetMD.getColumnCount();
1279: tMap = new TreeMap();
1280:
1281: for (int i = 0; i < numRows; i++) {
1282: tMap.put(new Integer(i), rvh.get(i));
1283: }
1284:
1285: return (tMap.values());
1286: }
1287:
1288: /**
1289: * {@inheritDoc}
1290: */
1291: public Collection toCollection(int column) throws SQLException {
1292: checkExecuted(); //!JK ?
1293:
1294: Vector vec;
1295: Row origRow;
1296: int nRows = numRows;
1297: vec = new Vector(nRows);
1298:
1299: // create a copy
1300: CachedRowSetXImpl5 crsTemp;
1301: crsTemp = (CachedRowSetXImpl5) this .createCopy();
1302:
1303: while (nRows != 0) {
1304: crsTemp.next();
1305: vec.add(crsTemp.getObject(column));
1306: nRows--;
1307: }
1308:
1309: return (Collection) vec;
1310: }
1311:
1312: /**
1313: * {@inheritDoc}
1314: */
1315: public Collection toCollection(String column) throws SQLException {
1316: checkExecuted(); //!JK ?
1317: return toCollection(getColIdxByName(column));
1318: }
1319:
1320: //--------------------------------------------------------------------
1321: // Advanced features
1322: //--------------------------------------------------------------------
1323:
1324: /**
1325: * {@inheritDoc}
1326: */
1327: public SyncProvider getSyncProvider() throws SQLException {
1328: return provider;
1329: }
1330:
1331: /**
1332: * {@inheritDoc}
1333: */
1334: public void setSyncProvider(String providerStr) throws SQLException {
1335: provider = (SyncProvider) SyncFactory.getInstance(providerStr);
1336:
1337: rowSetReader = provider.getRowSetReader();
1338: rowSetWriter = (TransactionalWriter) provider.getRowSetWriter();
1339: }
1340:
1341: //-----------------
1342: // methods inherited from RowSet
1343: //-----------------
1344:
1345: //---------------------------------------------------------------------
1346: // Reading and writing data
1347: //---------------------------------------------------------------------
1348:
1349: /**
1350: * {@inheritDoc}
1351: */
1352: public void execute() throws SQLException {
1353: execute(null);
1354: }
1355:
1356: //-----------------------------------
1357: // Methods inherited from ResultSet
1358: //-----------------------------------
1359:
1360: /**
1361: * {@inheritDoc}
1362: */
1363: public boolean next() throws SQLException {
1364: checkExecuted();
1365: /*
1366: * make sure things look sane. The cursor must be
1367: * positioned in the rowset or before first (0) or
1368: * after last (numRows + 1)
1369: */
1370: if (cursorPos < 0 || cursorPos >= numRows + 1) {
1371: throw new SQLException(rb.getString("INVALID_CURSOR_POS")); //NOI18N
1372: }
1373: // now move and notify
1374: boolean ret = this .internalNext();
1375: notifyCursorMoved();
1376:
1377: return ret;
1378: }
1379:
1380: /**
1381: * Moves this <code>CachedRowSetXImpl</code> object's cursor to the next
1382: * row and returns <code>true</code> if the cursor is still in the rowset;
1383: * returns <code>false</code> if the cursor has moved to the position after
1384: * the last row.
1385: * <P>
1386: * This method handles the cases where the cursor moves to a row that
1387: * has been deleted.
1388: * If this rowset shows deleted rows and the cursor moves to a row
1389: * that has been deleted, this method moves the cursor to the next
1390: * row until the cursor is on a row that has not been deleted.
1391: * <P>
1392: * The method <code>internalNext</code> is called by methods such as
1393: * <code>next</code>, <code>absolute</code>, and <code>relative</code>,
1394: * and, as its name implies, is only called internally.
1395: * <p>
1396: * This is a implementation only method and is not required as a standard
1397: * implementation of the <code>CachedRowSet</code> interface.
1398: *
1399: * @return <code>true</code> if the cursor is on a valid row in this
1400: * rowset; <code>false</code> if it is after the last row
1401: * @throws SQLException if an error occurs
1402: */
1403: protected boolean internalNext() throws SQLException {
1404: boolean ret = false;
1405: //System.out.println("internalNext(): start");
1406:
1407: do {
1408: //System.out.println("internalNext(): do top: cursorPos: " + cursorPos + ", numRows: " + numRows);
1409: if (cursorPos < numRows) {
1410: ++cursorPos;
1411: ret = true;
1412: //System.out.println("internalNext(): do: case was cursorPos < numRows: cursorPos: " + cursorPos + ", ret: " + ret);
1413: } else if (cursorPos == numRows) {
1414: // increment to after last
1415: ++cursorPos;
1416: ret = false;
1417: //System.out.println("internalNext(): do: case was cursorPos == numRows: cursorPos: " + cursorPos + ", ret: " + ret);
1418: break;
1419: }
1420: } while ((getShowDeleted() == false) && (rowDeleted() == true));
1421: //System.out.println("internalNext(): fell through the while");
1422:
1423: /* each call to internalNext may increment cursorPos multiple
1424: * times however, the absolutePos only increments once per call.
1425: */
1426: if (ret == true)
1427: absolutePos++;
1428: else
1429: absolutePos = 0;
1430:
1431: //System.out.println("internalNext(): returning: cursorPos: " + cursorPos + ", absolutePos: " + absolutePos + ", numRows: " + numRows + ", ret: " + ret);
1432: return ret;
1433: }
1434:
1435: /**
1436: * {@inheritDoc}
1437: */
1438: public void close() {
1439:
1440: // close all data structures holding
1441: // the disconnected rowset
1442:
1443: cursorPos = 0;
1444: absolutePos = 0;
1445: numRows = 0;
1446: numDeleted = 0;
1447:
1448: // set all insert(s), update(s) & delete(s),
1449: // if at all, to their initial values.
1450: try {
1451: initProperties();
1452: } catch (SQLException e) {
1453: }
1454:
1455: // clear the vector of it's present contents
1456: rvh.clear();
1457:
1458: // this will make it eligible for gc
1459: // rvh = null;
1460: }
1461:
1462: /**
1463: * {@inheritDoc}
1464: */
1465: public boolean wasNull() throws SQLException {
1466: checkExecuted();
1467: return lastValueNull;
1468: }
1469:
1470: /**
1471: * Sets the field <code>lastValueNull</code> to the given
1472: * <code>boolean</code> value.
1473: *
1474: * @param value <code>true</code> to indicate that the value of
1475: * the last column read was SQL <code>NULL</code>;
1476: * <code>false</code> to indicate that it was not
1477: */
1478: private void setLastValueNull(boolean value) {
1479: lastValueNull = value;
1480: }
1481:
1482: //======================================================================
1483: // Methods for accessing results by column index
1484: //======================================================================
1485:
1486: /**
1487: * Checks to see whether the given index is a valid column number
1488: * in this <code>CachedRowSetXImpl</code> object and throws
1489: * an <code>SQLException</code> if it is not. The index is out of bounds
1490: * if it is less than <code>1</code> or greater than the number of
1491: * columns in this rowset.
1492: * <P>
1493: * This method is called internally by the <code>getXXX</code> and
1494: * <code>updateXXX</code> methods.
1495: *
1496: * @param idx the number of a column in this <code>CachedRowSetXImpl</code>
1497: * object; must be between <code>1</code> and the number of
1498: * rows in this rowset
1499: * @throws SQLException if the given index is out of bounds
1500: */
1501: private void checkIndex(int idx) throws SQLException {
1502: if (idx < 1 || idx > rowSetMD.getColumnCount()) {
1503: throw new SQLException(MessageFormat.format(rb
1504: .getString("INVALID_COLUMN_INDEX"), //NOI18N
1505: new Object[] { new Integer(idx) }));
1506: }
1507: }
1508:
1509: /**
1510: * Checks to see whether the cursor for this <code>CachedRowSetXImpl</code>
1511: * object is on a row in the rowset and throws an
1512: * <code>SQLException</code> if it is not.
1513: * <P>
1514: * This method is called internally by <code>getXXX</code> methods, by
1515: * <code>updateXXX</code> methods, and by methods that update, insert,
1516: * or delete a row or that cancel a row update, insert, or delete.
1517: *
1518: * @throws SQLException if the cursor for this <code>CachedRowSetXImpl</code>
1519: * object is not on a valid row
1520: */
1521: private void checkCursor() throws SQLException {
1522: if (isAfterLast() == true || isBeforeFirst() == true) {
1523: throw new SQLException(rb.getString("INVALID_CURSOR_POS")); //NOI18N
1524: }
1525: }
1526:
1527: /**
1528: * Returns the column number of the column with the given name in this
1529: * <code>CachedRowSetXImpl</code> object. This method throws an
1530: * <code>SQLException</code> if the given name is not the name of
1531: * one of the columns in this rowset.
1532: *
1533: * @param name a <code>String</code> object that is the name of a column in
1534: * this <code>CachedRowSetXImpl</code> object
1535: * @throws SQLException if the given name does not match the name of one of
1536: * the columns in this rowset
1537: */
1538: private int getColIdxByName(String name) throws SQLException {
1539: int cols = rowSetMD.getColumnCount();
1540:
1541: for (int i = 1; i <= cols; ++i) {
1542: String colName = rowSetMD.getColumnName(i);
1543: if (colName != null)
1544: if (name.equalsIgnoreCase(colName))
1545: return (i);
1546: else
1547: continue;
1548: }
1549: throw new SQLException(rb.getString("INVALID_COLUMN_NAME")); //NOI18N
1550:
1551: }
1552:
1553: /**
1554: * Returns the insert row or the current row of this
1555: * <code>CachedRowSetXImpl</code>object.
1556: *
1557: * @return the <code>Row</code> object on which this <code>CachedRowSetXImpl</code>
1558: * objects's cursor is positioned
1559: */
1560: protected BaseRow getCurrentRow() throws SQLException {
1561: if (onInsertRow == true) {
1562: return (BaseRow) insertRow;
1563: } else {
1564: if (cursorPos < 1 || cursorPos > rvh.size()) {
1565: throw new SQLException(rb
1566: .getString("INVALID_CURSOR_POS")); //NOI18N
1567: }
1568: return (BaseRow) (rvh.get(cursorPos - 1));
1569: }
1570: }
1571:
1572: /**
1573: * Removes the row on which the cursor is positioned.
1574: * <p>
1575: * This is a implementation only method and is not required as a standard
1576: * implementation of the <code>CachedRowSet</code> interface.
1577: *
1578: * @throws SQLException if the cursor is positioned on the insert
1579: * row
1580: */
1581: protected void removeCurrentRow() throws SQLException {
1582: ((Row) getCurrentRow()).setDeleted();
1583: rvh.remove(cursorPos);
1584: --numRows;
1585: }
1586:
1587: /**
1588: * {@inheritDoc}
1589: */
1590: public String getString(int columnIndex) throws SQLException {
1591: checkExecuted();
1592: Object value;
1593:
1594: // sanity check.
1595: checkIndex(columnIndex);
1596: // make sure the cursor is on a valid row
1597: checkCursor();
1598:
1599: setLastValueNull(false);
1600: value = getCurrentRow().getColumnObject(columnIndex);
1601:
1602: // check for SQL NULL
1603: if (value == null) {
1604: setLastValueNull(true);
1605: return null;
1606: }
1607:
1608: return value.toString();
1609: }
1610:
1611: /**
1612: * {@inheritDoc}
1613: */
1614: public boolean getBoolean(int columnIndex) throws SQLException {
1615: checkExecuted();
1616: Object value;
1617:
1618: // sanity check.
1619: checkIndex(columnIndex);
1620: // make sure the cursor is on a valid row
1621: checkCursor();
1622:
1623: setLastValueNull(false);
1624: value = getCurrentRow().getColumnObject(columnIndex);
1625:
1626: // check for SQL NULL
1627: if (value == null) {
1628: setLastValueNull(true);
1629: return false;
1630: }
1631:
1632: // check for Boolean...
1633: if (value instanceof Boolean) {
1634: return ((Boolean) value).booleanValue();
1635: }
1636:
1637: // convert to a Double and compare to zero
1638: try {
1639: Double d = new Double(value.toString());
1640: if (d.compareTo(new Double((double) 0)) == 0) {
1641: return false;
1642: } else {
1643: return true;
1644: }
1645: } catch (NumberFormatException ex) {
1646: throw new SQLException(MessageFormat.format(rb
1647: .getString("GET_BOOLEAN_FAILED"), //NOI18N
1648: new Object[] { value.toString().trim(),
1649: new Integer(columnIndex) }));
1650: }
1651: }
1652:
1653: /**
1654: * {@inheritDoc}
1655: */
1656: public byte getByte(int columnIndex) throws SQLException {
1657: checkExecuted();
1658: Object value;
1659:
1660: // sanity check.
1661: checkIndex(columnIndex);
1662: // make sure the cursor is on a valid row
1663: checkCursor();
1664:
1665: setLastValueNull(false);
1666: value = getCurrentRow().getColumnObject(columnIndex);
1667:
1668: // check for SQL NULL
1669: if (value == null) {
1670: setLastValueNull(true);
1671: return (byte) 0;
1672: }
1673: try {
1674: return ((new Byte(value.toString())).byteValue());
1675: } catch (NumberFormatException ex) {
1676: throw new SQLException(MessageFormat.format(rb
1677: .getString("GET_BYTE_FAILED"), //NOI18N
1678: new Object[] { value.toString().trim(),
1679: new Integer(columnIndex) }));
1680: }
1681: }
1682:
1683: /**
1684: * {@inheritDoc}
1685: */
1686: public short getShort(int columnIndex) throws SQLException {
1687: checkExecuted();
1688: Object value;
1689:
1690: // sanity check.
1691: checkIndex(columnIndex);
1692: // make sure the cursor is on a valid row
1693: checkCursor();
1694:
1695: setLastValueNull(false);
1696: value = getCurrentRow().getColumnObject(columnIndex);
1697:
1698: // check for SQL NULL
1699: if (value == null) {
1700: setLastValueNull(true);
1701: return (short) 0;
1702: }
1703:
1704: try {
1705: return ((new Short(value.toString().trim())).shortValue());
1706: } catch (NumberFormatException ex) {
1707: throw new SQLException(MessageFormat.format(rb
1708: .getString("GET_SHORT_FAILED"), //NOI18N
1709: new Object[] { value.toString().trim(),
1710: new Integer(columnIndex) }));
1711: }
1712: }
1713:
1714: public int getInt(int columnIndex) throws SQLException {
1715: checkExecuted();
1716: Object value;
1717:
1718: // sanity check.
1719: checkIndex(columnIndex);
1720: // make sure the cursor is on a valid row
1721: checkCursor();
1722:
1723: setLastValueNull(false);
1724: value = getCurrentRow().getColumnObject(columnIndex);
1725:
1726: // check for SQL NULL
1727: if (value == null) {
1728: setLastValueNull(true);
1729: return (int) 0;
1730: }
1731:
1732: try {
1733: return ((new Integer(value.toString().trim())).intValue());
1734: } catch (NumberFormatException ex) {
1735: throw new SQLException(MessageFormat.format(rb
1736: .getString("GET_INT_FAILED"), //NOI18N
1737: new Object[] { value.toString().trim(),
1738: new Integer(columnIndex) }));
1739: }
1740: }
1741:
1742: /**
1743: * {@inheritDoc}
1744: */
1745: public long getLong(int columnIndex) throws SQLException {
1746: checkExecuted();
1747: Object value;
1748:
1749: // sanity check.
1750: checkIndex(columnIndex);
1751: // make sure the cursor is on a valid row
1752: checkCursor();
1753:
1754: setLastValueNull(false);
1755: value = getCurrentRow().getColumnObject(columnIndex);
1756:
1757: // check for SQL NULL
1758: if (value == null) {
1759: setLastValueNull(true);
1760: return (long) 0;
1761: }
1762: try {
1763: return ((new Long(value.toString().trim())).longValue());
1764: } catch (NumberFormatException ex) {
1765: throw new SQLException(MessageFormat.format(rb
1766: .getString("GET_LONG_FAILED"), //NOI18N
1767: new Object[] { value.toString().trim(),
1768: new Integer(columnIndex) }));
1769: }
1770: }
1771:
1772: /**
1773: * {@inheritDoc}
1774: */
1775: public float getFloat(int columnIndex) throws SQLException {
1776: checkExecuted();
1777: Object value;
1778:
1779: // sanity check.
1780: checkIndex(columnIndex);
1781: // make sure the cursor is on a valid row
1782: checkCursor();
1783:
1784: setLastValueNull(false);
1785: value = getCurrentRow().getColumnObject(columnIndex);
1786:
1787: // check for SQL NULL
1788: if (value == null) {
1789: setLastValueNull(true);
1790: return (float) 0;
1791: }
1792: try {
1793: return ((new Float(value.toString())).floatValue());
1794: } catch (NumberFormatException ex) {
1795: throw new SQLException(MessageFormat.format(rb
1796: .getString("GET_FLOAT_FAILED"), //NOI18N
1797: new Object[] { value.toString().trim(),
1798: new Integer(columnIndex) }));
1799: }
1800: }
1801:
1802: /**
1803: * {@inheritDoc}
1804: */
1805: public double getDouble(int columnIndex) throws SQLException {
1806: checkExecuted();
1807: Object value;
1808:
1809: // sanity check.
1810: checkIndex(columnIndex);
1811: // make sure the cursor is on a valid row
1812: checkCursor();
1813:
1814: setLastValueNull(false);
1815: value = getCurrentRow().getColumnObject(columnIndex);
1816:
1817: // check for SQL NULL
1818: if (value == null) {
1819: setLastValueNull(true);
1820: return (double) 0;
1821: }
1822: try {
1823: return ((new Double(value.toString().trim())).doubleValue());
1824: } catch (NumberFormatException ex) {
1825: throw new SQLException(MessageFormat.format(rb
1826: .getString("GET_DOUBLE_FAILED"), //NOI18N
1827: new Object[] { value.toString().trim(),
1828: new Integer(columnIndex) }));
1829: }
1830: }
1831:
1832: /**
1833: * {@inheritDoc}
1834: */
1835: public BigDecimal getBigDecimal(int columnIndex, int scale)
1836: throws SQLException {
1837: checkExecuted();
1838: return getBigDecimal(columnIndex, scale);
1839: }
1840:
1841: /**
1842: * {@inheritDoc}
1843: */
1844: public byte[] getBytes(int columnIndex) throws SQLException {
1845: checkExecuted();
1846: // sanity check.
1847: checkIndex(columnIndex);
1848: // make sure the cursor is on a valid row
1849: checkCursor();
1850:
1851: if (isBinary(rowSetMD.getColumnType(columnIndex)) == false) {
1852: throw new SQLException(rb.getString("DATATYPE_MISMATCH")); //NOI18N
1853: }
1854:
1855: return (byte[]) (getCurrentRow().getColumnObject(columnIndex));
1856: }
1857:
1858: /**
1859: * {@inheritDoc}
1860: */
1861: public java.sql.Date getDate(int columnIndex) throws SQLException {
1862: checkExecuted();
1863: Object value;
1864:
1865: // sanity check.
1866: checkIndex(columnIndex);
1867: // make sure the cursor is on a valid row
1868: checkCursor();
1869:
1870: setLastValueNull(false);
1871: value = getCurrentRow().getColumnObject(columnIndex);
1872:
1873: // check for SQL NULL
1874: if (value == null) {
1875: setLastValueNull(true);
1876: return null;
1877: }
1878:
1879: /*
1880: * The object coming back from the db could be
1881: * a date, a timestamp, or a char field variety.
1882: * If it's a date type return it, a timestamp
1883: * we turn into a long and then into a date,
1884: * char strings we try to parse. Yuck.
1885: */
1886: switch (rowSetMD.getColumnType(columnIndex)) {
1887: case java.sql.Types.DATE: {
1888: long sec = ((java.sql.Date) value).getTime();
1889: return new java.sql.Date(sec);
1890: }
1891: case java.sql.Types.TIMESTAMP: {
1892: long sec = ((java.sql.Timestamp) value).getTime();
1893: return new java.sql.Date(sec);
1894: }
1895: case java.sql.Types.CHAR:
1896: case java.sql.Types.VARCHAR:
1897: case java.sql.Types.LONGVARCHAR: {
1898: try {
1899: DateFormat df = DateFormat.getDateInstance();
1900: return ((java.sql.Date) (df.parse(value.toString())));
1901: } catch (ParseException ex) {
1902: throw new SQLException(MessageFormat.format(rb
1903: .getString("GET_TIMESTAMP_FAILED"), //NOI18N
1904: new Object[] { value.toString().trim(),
1905: new Integer(columnIndex) }));
1906: }
1907: }
1908: default: {
1909: throw new SQLException(MessageFormat.format(rb
1910: .getString("GET_TIMESTAMP2_FAILED"), //NOI18N
1911: new Object[] { value.toString().trim(),
1912: new Integer(columnIndex) }));
1913: }
1914: }
1915: }
1916:
1917: /**
1918: * {@inheritDoc}
1919: */
1920: public java.sql.Time getTime(int columnIndex) throws SQLException {
1921: checkExecuted();
1922: Object value;
1923:
1924: // sanity check.
1925: checkIndex(columnIndex);
1926: // make sure the cursor is on a valid row
1927: checkCursor();
1928:
1929: setLastValueNull(false);
1930: value = getCurrentRow().getColumnObject(columnIndex);
1931:
1932: // check for SQL NULL
1933: if (value == null) {
1934: setLastValueNull(true);
1935: return null;
1936: }
1937:
1938: /*
1939: * The object coming back from the db could be
1940: * a date, a timestamp, or a char field variety.
1941: * If it's a date type return it, a timestamp
1942: * we turn into a long and then into a date,
1943: * char strings we try to parse. Yuck.
1944: */
1945: switch (rowSetMD.getColumnType(columnIndex)) {
1946: case java.sql.Types.TIME: {
1947: return (java.sql.Time) value;
1948: }
1949: case java.sql.Types.TIMESTAMP: {
1950: long sec = ((java.sql.Timestamp) value).getTime();
1951: return new java.sql.Time(sec);
1952: }
1953: case java.sql.Types.CHAR:
1954: case java.sql.Types.VARCHAR:
1955: case java.sql.Types.LONGVARCHAR: {
1956: try {
1957: DateFormat tf = DateFormat.getTimeInstance();
1958: return ((java.sql.Time) (tf.parse(value.toString())));
1959: } catch (ParseException ex) {
1960: throw new SQLException(MessageFormat.format(rb
1961: .getString("GET_TIME_FAILED"), //NOI18N
1962: new Object[] { value.toString().trim(),
1963: new Integer(columnIndex) }));
1964: }
1965: }
1966: default: {
1967: throw new SQLException(MessageFormat.format(rb
1968: .getString("GET_TIME2_FAILED"), //NOI18N
1969: new Object[] { value.toString().trim(),
1970: new Integer(columnIndex) }));
1971: }
1972: }
1973: }
1974:
1975: /**
1976: * {@inheritDoc}
1977: */
1978: public java.sql.Timestamp getTimestamp(int columnIndex)
1979: throws SQLException {
1980: // System.out.println("Entering CRSXI.getTimestamp");
1981: checkExecuted();
1982: Object value;
1983:
1984: // sanity check.
1985: checkIndex(columnIndex);
1986: // make sure the cursor is on a valid row
1987: checkCursor();
1988:
1989: setLastValueNull(false);
1990: value = getCurrentRow().getColumnObject(columnIndex);
1991: // System.out.println("CRSXI.getTimestamp/1, value: " + value);
1992:
1993: // check for SQL NULL
1994: if (value == null) {
1995: setLastValueNull(true);
1996: return null;
1997: }
1998:
1999: /*
2000: * The object coming back from the db could be
2001: * a date, a timestamp, or a char field variety.
2002: * If it's a date type return it; a timestamp
2003: * we turn into a long and then into a date;
2004: * char strings we try to parse. Yuck.
2005: */
2006: // System.out.println("CRSXI.getTimestamp/2, columnType: " + rowSetMD.getColumnType(columnIndex));
2007: switch (rowSetMD.getColumnType(columnIndex)) {
2008: case java.sql.Types.TIMESTAMP: {
2009: return (java.sql.Timestamp) value;
2010: }
2011: case java.sql.Types.TIME: {
2012: long sec = ((java.sql.Time) value).getTime();
2013: return new java.sql.Timestamp(sec);
2014: }
2015: case java.sql.Types.DATE: {
2016: long sec = ((java.sql.Date) value).getTime();
2017: return new java.sql.Timestamp(sec);
2018: }
2019: case java.sql.Types.CHAR:
2020: case java.sql.Types.VARCHAR:
2021: case java.sql.Types.LONGVARCHAR: {
2022: try {
2023: DateFormat tf = DateFormat.getTimeInstance();
2024: return ((java.sql.Timestamp) (tf
2025: .parse(value.toString())));
2026: } catch (ParseException ex) {
2027: throw new SQLException(MessageFormat.format(rb
2028: .getString("GET_TIMESTAMP_FAILED"), //NOI18N
2029: new Object[] { value.toString().trim(),
2030: new Integer(columnIndex) }));
2031: }
2032: }
2033: default: {
2034: throw new SQLException(MessageFormat.format(rb
2035: .getString("GET_TIMESTAMP2_FAILED"), //NOI18N
2036: new Object[] { value.toString().trim(),
2037: new Integer(columnIndex) }));
2038: }
2039: }
2040: }
2041:
2042: /**
2043: * {@inheritDoc}
2044: */
2045: public java.io.InputStream getAsciiStream(int columnIndex)
2046: throws SQLException {
2047: checkExecuted();
2048: Object value;
2049:
2050: // always free an old stream
2051: asciiStream = null;
2052:
2053: // sanity check
2054: checkIndex(columnIndex);
2055: //make sure the cursor is on a vlid row
2056: checkCursor();
2057:
2058: value = getCurrentRow().getColumnObject(columnIndex);
2059: if (value == null) {
2060: lastValueNull = true;
2061: return null;
2062: }
2063:
2064: try {
2065: if (isString(rowSetMD.getColumnType(columnIndex))) {
2066: asciiStream = new ByteArrayInputStream(((String) value)
2067: .getBytes("ASCII")); //NOI18N
2068: } else {
2069: throw new SQLException(rb
2070: .getString("DATATYPE_MISMATCH")); //NOI18N
2071: }
2072: } catch (java.io.UnsupportedEncodingException ex) {
2073: throw new SQLException(ex.getMessage());
2074: }
2075:
2076: return (java.io.InputStream) asciiStream;
2077: }
2078:
2079: /**
2080: * {@inheritDoc}
2081: */
2082: public java.io.InputStream getUnicodeStream(int columnIndex)
2083: throws SQLException {
2084: checkExecuted();
2085: // always free an old stream
2086: unicodeStream = null;
2087:
2088: // sanity check.
2089: checkIndex(columnIndex);
2090: // make sure the cursor is on a valid row
2091: checkCursor();
2092:
2093: if (isBinary(rowSetMD.getColumnType(columnIndex)) == false
2094: && isString(rowSetMD.getColumnType(columnIndex)) == false) {
2095: throw new SQLException(rb.getString("DATATYPE_MISMATCH")); //NOI18N
2096: }
2097:
2098: Object value = getCurrentRow().getColumnObject(columnIndex);
2099: if (value == null) {
2100: lastValueNull = true;
2101: return null;
2102: }
2103:
2104: unicodeStream = new StringBufferInputStream(value.toString());
2105:
2106: return (java.io.InputStream) unicodeStream;
2107: }
2108:
2109: /**
2110: * {@inheritDoc}
2111: */
2112: public java.io.InputStream getBinaryStream(int columnIndex)
2113: throws SQLException {
2114: checkExecuted();
2115:
2116: // always free an old stream
2117: binaryStream = null;
2118:
2119: // sanity check.
2120: checkIndex(columnIndex);
2121: // make sure the cursor is on a valid row
2122: checkCursor();
2123:
2124: if (isBinary(rowSetMD.getColumnType(columnIndex)) == false) {
2125: throw new SQLException(rb.getString("DATATYPE_MISMATCH")); //NOI18N
2126: }
2127:
2128: Object value = getCurrentRow().getColumnObject(columnIndex);
2129: if (value == null) {
2130: lastValueNull = true;
2131: return null;
2132: }
2133:
2134: binaryStream = new ByteArrayInputStream((byte[]) value);
2135:
2136: return (java.io.InputStream) binaryStream;
2137:
2138: }
2139:
2140: //======================================================================
2141: // Methods for accessing results by column name
2142: //======================================================================
2143:
2144: /**
2145: * {@inheritDoc}
2146: */
2147: public String getString(String columnName) throws SQLException {
2148: checkExecuted();
2149: return getString(getColIdxByName(columnName));
2150: }
2151:
2152: /**
2153: * {@inheritDoc}
2154: */
2155: public boolean getBoolean(String columnName) throws SQLException {
2156: checkExecuted();
2157: return getBoolean(getColIdxByName(columnName));
2158: }
2159:
2160: /**
2161: * {@inheritDoc}
2162: */
2163: public byte getByte(String columnName) throws SQLException {
2164: checkExecuted();
2165: return getByte(getColIdxByName(columnName));
2166: }
2167:
2168: /**
2169: * {@inheritDoc}
2170: */
2171: public short getShort(String columnName) throws SQLException {
2172: checkExecuted();
2173: return getShort(getColIdxByName(columnName));
2174: }
2175:
2176: /**
2177: * {@inheritDoc}
2178: */
2179: public int getInt(String columnName) throws SQLException {
2180: checkExecuted();
2181: return getInt(getColIdxByName(columnName));
2182: }
2183:
2184: /**
2185: * {@inheritDoc}
2186: */
2187: public long getLong(String columnName) throws SQLException {
2188: checkExecuted();
2189: return getLong(getColIdxByName(columnName));
2190: }
2191:
2192: /**
2193: * {@inheritDoc}
2194: */
2195: public float getFloat(String columnName) throws SQLException {
2196: checkExecuted();
2197: return getFloat(getColIdxByName(columnName));
2198: }
2199:
2200: /**
2201: * {@inheritDoc}
2202: */
2203: public double getDouble(String columnName) throws SQLException {
2204: checkExecuted();
2205: return getDouble(getColIdxByName(columnName));
2206: }
2207:
2208: /**
2209: * {@inheritDoc}
2210: */
2211: public BigDecimal getBigDecimal(String columnName, int scale)
2212: throws SQLException {
2213: checkExecuted();
2214: return getBigDecimal(getColIdxByName(columnName), scale);
2215: }
2216:
2217: /**
2218: * {@inheritDoc}
2219: */
2220: public byte[] getBytes(String columnName) throws SQLException {
2221: checkExecuted();
2222: return getBytes(getColIdxByName(columnName));
2223: }
2224:
2225: /**
2226: * {@inheritDoc}
2227: */
2228: public java.sql.Date getDate(String columnName) throws SQLException {
2229: checkExecuted();
2230: return getDate(getColIdxByName(columnName));
2231: }
2232:
2233: /**
2234: * {@inheritDoc}
2235: */
2236: public java.sql.Time getTime(String columnName) throws SQLException {
2237: checkExecuted();
2238: return getTime(getColIdxByName(columnName));
2239: }
2240:
2241: /**
2242: * {@inheritDoc}
2243: */
2244: public java.sql.Timestamp getTimestamp(String columnName)
2245: throws SQLException {
2246: checkExecuted();
2247: return getTimestamp(getColIdxByName(columnName));
2248: }
2249:
2250: /**
2251: * {@inheritDoc}
2252: */
2253: public java.io.InputStream getAsciiStream(String columnName)
2254: throws SQLException {
2255: checkExecuted();
2256: return getAsciiStream(getColIdxByName(columnName));
2257:
2258: }
2259:
2260: /**
2261: * {@inheritDoc}
2262: */
2263: public java.io.InputStream getUnicodeStream(String columnName)
2264: throws SQLException {
2265: checkExecuted();
2266: return getUnicodeStream(getColIdxByName(columnName));
2267: }
2268:
2269: /**
2270: * {@inheritDoc}
2271: */
2272: public java.io.InputStream getBinaryStream(String columnName)
2273: throws SQLException {
2274: checkExecuted();
2275: return getBinaryStream(getColIdxByName(columnName));
2276: }
2277:
2278: //=====================================================================
2279: // Advanced features:
2280: //=====================================================================
2281:
2282: /**
2283: * {@inheritDoc}
2284: */
2285: public SQLWarning getWarnings() {
2286: return sqlwarn;
2287: }
2288:
2289: /**
2290: * {@inheritDoc}
2291: */
2292: public void clearWarnings() {
2293: sqlwarn = null;
2294: }
2295:
2296: /**
2297: * {@inheritDoc}
2298: */
2299: public String getCursorName() throws SQLException {
2300: throw new SQLException(rb
2301: .getString("POSITIONED_UPDATES_NOT_SUPPORTED")); //NOI18N
2302: }
2303:
2304: /**
2305: * {@inheritDoc}
2306: */
2307: public ResultSetMetaData getMetaData() throws SQLException {
2308:
2309: Log.getLogger().entering(getClass().getName(), "getMetaData()");
2310:
2311: // if we haven't yet executed, rowSetMD will be null.
2312: // we don't want to execute here, so let's get a connection
2313: // and manufacture the rowsetmd
2314: if (rowSetMD == null) {
2315:
2316: Connection tempConn = null;
2317: PreparedStatement tempPS = null;
2318: try {
2319: tempConn = getConnection(getDataSourceName(), getUrl(),
2320: getUsername(), getPassword());
2321: Log.getLogger().finest(
2322: "Connection: " + tempConn
2323: + " DataSourceName: "
2324: + getDataSourceName() + " URL: "
2325: + getUrl());
2326: tempPS = tempConn.prepareStatement(getCommand());
2327: // System.out.println("Prepared Statement: " + tempPS);
2328:
2329: rowSetMD = new RowSetMetaDataXImpl();
2330: ResultSetMetaData rsmd;
2331: try {
2332: rsmd = tempPS.getMetaData();
2333: Log.getLogger().finest(
2334: "After calling tempPS.getMetaData(), rsmd: "
2335: + rsmd);
2336:
2337: if (rsmd == null
2338: && "Oracle".equals(tempConn.getMetaData()
2339: .getDatabaseProductName())) {
2340: // Oracle 9 driver problem -- silently returns null rsmd
2341: rsmd = oracleFixup(tempConn, getCommand());
2342: }
2343: } catch (SQLException e) {
2344:
2345: Log.getLogger().finest(
2346: "Exception caught: " + e.getErrorCode()
2347: + " : " + e.getMessage());
2348: if (e.getErrorCode() == 17144) {
2349: // Oracle 10 driver problem -- throws SQLException, "statement handle not executed"
2350: rsmd = oracleFixup(tempConn, getCommand());
2351:
2352: } else {
2353: // Some other problem. Re-throw.
2354: throw (e);
2355: }
2356: }
2357:
2358: initMetaData(rowSetMD, rsmd);
2359: // System.out.println("After calling initMetaData, rsmd: " + rsmd);
2360: }
2361: // catch (SQLException e) {
2362: // }
2363: finally {
2364: if (tempPS != null) {
2365: tempPS.close();
2366: }
2367: if (tempConn != null) {
2368: try {
2369: if (!tempConn.getAutoCommit()) {
2370: tempConn.rollback();
2371: }
2372: } catch (Exception dummy) {
2373: /*
2374: * not an error condition, we're closing anyway, but
2375: * we'd like to clean up any locks if we can since
2376: * it is not clear the connection pool will clean
2377: * these connections in a timely manner
2378: */
2379: }
2380: tempConn.close();
2381: }
2382: }
2383: }
2384: Log.getLogger().exiting(getClass().getName(), "getMetaData()");
2385: return rowSetMD;
2386: }
2387:
2388: // Work around Oracle driver problem by executing modified command, to populate metadata
2389: // Strip off unnecessary stuff, and add where clause that is always false
2390: private ResultSetMetaData oracleFixup(Connection tempConn,
2391: String command) throws SQLException {
2392: Log.getLogger().entering("CachedRowSetXImpl", "oracleFixup()",
2393: command);
2394: String cmd = command;
2395:
2396: // Extract the GROUP BY, to use later
2397: String groupBy = "";
2398: int pos = cmd.toUpperCase().indexOf("GROUP BY");
2399: if (pos != -1) {
2400: groupBy = cmd.substring(pos);
2401: cmd = cmd.substring(0, pos);
2402: }
2403:
2404: // Retain SELECT/FROM, remove WHERE/HAVING/ORDER BY
2405: String[] parts = cmd.split("(?i:where|having|order by)");
2406:
2407: // Attach new WHERE clause, previous GROUP BY
2408: String newCommand = parts[0] + " WHERE 1=0 " + groupBy;
2409:
2410: Log.getLogger().finest(
2411: "Executing modified statement: " + newCommand);
2412: PreparedStatement tempPS = tempConn
2413: .prepareStatement(newCommand);
2414: tempPS.execute();
2415: return tempPS.getMetaData();
2416: }
2417:
2418: /**
2419: * {@inheritDoc}
2420: */
2421: public Object getObject(int columnIndex) throws SQLException {
2422: checkExecuted();
2423: Object value;
2424: java.util.Map map;
2425:
2426: // sanity check.
2427: checkIndex(columnIndex);
2428: // make sure the cursor is on a valid row
2429: checkCursor();
2430:
2431: setLastValueNull(false);
2432: value = getCurrentRow().getColumnObject(columnIndex);
2433:
2434: // check for SQL NULL
2435: if (value == null) {
2436: setLastValueNull(true);
2437: return null;
2438: }
2439: if (value instanceof Struct) {
2440: Struct s = (Struct) value;
2441: map = getTypeMap();
2442: // look up the class in the map
2443: Class c = (Class) map.get(s.getSQLTypeName());
2444: if (c != null) {
2445: // create new instance of the class
2446: SQLData obj = null;
2447: try {
2448: obj = (SQLData) c.newInstance();
2449: } catch (java.lang.InstantiationException ex) {
2450: throw new SQLException(rb
2451: .getString("UNABLE_TO_INSTANTIATE")
2452: + ex.getMessage()); //NOI18N
2453: } catch (java.lang.IllegalAccessException ex) {
2454: throw new SQLException(rb
2455: .getString("UNABLE_TO_INSTANTIATE")
2456: + ex.getMessage()); //NOI18N
2457: }
2458: // get the attributes from the struct
2459: Object attribs[] = s.getAttributes(map);
2460: // create the SQLInput "stream"
2461: SQLInputImpl sqlInput = new SQLInputImpl(attribs, map);
2462: // read the values...
2463: obj.readSQL(sqlInput, s.getSQLTypeName());
2464: return (Object) obj;
2465: }
2466: }
2467: return value;
2468: }
2469:
2470: /**
2471: * {@inheritDoc}
2472: */
2473: public Object getObject(String columnName) throws SQLException {
2474: checkExecuted();
2475: return getObject(getColIdxByName(columnName));
2476: }
2477:
2478: //----------------------------------------------------------------
2479:
2480: /**
2481: * {@inheritDoc}
2482: */
2483: public int findColumn(String columnName) throws SQLException {
2484: return getColIdxByName(columnName);
2485: }
2486:
2487: //--------------------------JDBC 2.0-----------------------------------
2488:
2489: //---------------------------------------------------------------------
2490: // Getter's and Setter's
2491: //---------------------------------------------------------------------
2492:
2493: /**
2494: * {@inheritDoc}
2495: */
2496: public java.io.Reader getCharacterStream(int columnIndex)
2497: throws SQLException {
2498: checkExecuted();
2499:
2500: // sanity check.
2501: checkIndex(columnIndex);
2502: // make sure the cursor is on a valid row
2503: checkCursor();
2504:
2505: if (isBinary(rowSetMD.getColumnType(columnIndex))) {
2506: Object value = getCurrentRow().getColumnObject(columnIndex);
2507: if (value == null) {
2508: lastValueNull = true;
2509: return null;
2510: }
2511: charStream = new InputStreamReader(
2512: new ByteArrayInputStream((byte[]) value));
2513: } else if (isString(rowSetMD.getColumnType(columnIndex))) {
2514: Object value = getCurrentRow().getColumnObject(columnIndex);
2515: if (value == null) {
2516: lastValueNull = true;
2517: return null;
2518: }
2519: charStream = new StringReader(value.toString());
2520: } else {
2521: throw new SQLException(rb.getString("DATATYPE_MISMATCH")); //NOI18N
2522: }
2523:
2524: return (java.io.Reader) charStream;
2525: }
2526:
2527: /**
2528: * {@inheritDoc}
2529: */
2530: public java.io.Reader getCharacterStream(String columnName)
2531: throws SQLException {
2532: checkExecuted();
2533: return getCharacterStream(getColIdxByName(columnName));
2534: }
2535:
2536: /**
2537: * {@inheritDoc}
2538: */
2539: public BigDecimal getBigDecimal(int columnIndex)
2540: throws SQLException {
2541: checkExecuted();
2542: Object value;
2543:
2544: // sanity check.
2545: checkIndex(columnIndex);
2546: // make sure the cursor is on a valid row
2547: checkCursor();
2548:
2549: setLastValueNull(false);
2550: value = getCurrentRow().getColumnObject(columnIndex);
2551:
2552: // check for SQL NULL
2553: if (value == null) {
2554: setLastValueNull(true);
2555: return null;
2556: }
2557: try {
2558: return (new BigDecimal(value.toString().trim()));
2559: } catch (NumberFormatException ex) {
2560: throw new SQLException(MessageFormat.format(rb
2561: .getString("GET_DOUBLE_FAILED"), //NOI18N
2562: new Object[] { value.toString().trim(),
2563: new Integer(columnIndex) }));
2564: }
2565: }
2566:
2567: /**
2568: * {@inheritDoc}
2569: */
2570: public BigDecimal getBigDecimal(String columnName)
2571: throws SQLException {
2572: checkExecuted();
2573: return getBigDecimal(getColIdxByName(columnName));
2574: }
2575:
2576: //---------------------------------------------------------------------
2577: // Traversal/Positioning
2578: //---------------------------------------------------------------------
2579:
2580: /**
2581: * {@inheritDoc}
2582: */
2583: public int size() {
2584: // checkExecuted(); !JK Doesn't allow SQLException!
2585: return numRows;
2586: }
2587:
2588: /**
2589: * {@inheritDoc}
2590: */
2591: public boolean isBeforeFirst() throws SQLException {
2592: checkExecuted();
2593: if (cursorPos == 0 && numRows > 0) {
2594: return true;
2595: } else {
2596: return false;
2597: }
2598: }
2599:
2600: /**
2601: * {@inheritDoc}
2602: */
2603: public boolean isAfterLast() throws SQLException {
2604: checkExecuted();
2605: if (cursorPos == numRows + 1 && numRows > 0) {
2606: return true;
2607: } else {
2608: return false;
2609: }
2610: }
2611:
2612: /**
2613: * {@inheritDoc}
2614: */
2615: public boolean isFirst() throws SQLException {
2616: checkExecuted();
2617: // this becomes nasty because of deletes.
2618: int saveCursorPos = cursorPos;
2619: int saveAbsoluteCursorPos = absolutePos;
2620: internalFirst();
2621: if (cursorPos == saveCursorPos) {
2622: return true;
2623: } else {
2624: cursorPos = saveCursorPos;
2625: absolutePos = saveAbsoluteCursorPos;
2626: return false;
2627: }
2628: }
2629:
2630: /**
2631: * {@inheritDoc}
2632: */
2633: public boolean isLast() throws SQLException {
2634: checkExecuted();
2635: int saveCursorPos = cursorPos;
2636: int saveAbsoluteCursorPos = absolutePos;
2637: boolean saveShowDeleted = getShowDeleted();
2638: setShowDeleted(true);
2639: internalLast();
2640: if (cursorPos == saveCursorPos) {
2641: setShowDeleted(saveShowDeleted);
2642: return true;
2643: } else {
2644: setShowDeleted(saveShowDeleted);
2645: cursorPos = saveCursorPos;
2646: absolutePos = saveAbsoluteCursorPos;
2647: return false;
2648: }
2649: }
2650:
2651: /**
2652: * {@inheritDoc}
2653: */
2654: public void beforeFirst() throws SQLException {
2655: checkExecuted();
2656: if (getType() == ResultSet.TYPE_FORWARD_ONLY) {
2657: throw new SQLException(rb
2658: .getString("RESULTSET_TYPE_FORWARD_ONLY")); //NOI18N
2659: }
2660: cursorPos = 0;
2661: absolutePos = 0;
2662: notifyCursorMoved();
2663: }
2664:
2665: /**
2666: * {@inheritDoc}
2667: */
2668: public void afterLast() throws SQLException {
2669: checkExecuted();
2670: if (numRows > 0) {
2671: cursorPos = numRows + 1;
2672: absolutePos = 0;
2673: notifyCursorMoved();
2674: }
2675: }
2676:
2677: /**
2678: * {@inheritDoc}
2679: */
2680: public boolean first() throws SQLException {
2681: checkExecuted();
2682: if (getType() == ResultSet.TYPE_FORWARD_ONLY) {
2683: throw new SQLException(rb
2684: .getString("RESULTSET_TYPE_FORWARD_ONLY")); //NOI18N
2685: }
2686:
2687: // move and notify
2688: boolean ret = this .internalFirst();
2689: notifyCursorMoved();
2690:
2691: return ret;
2692: }
2693:
2694: protected boolean internalFirst() throws SQLException {
2695: boolean ret = false;
2696:
2697: if (numRows > 0) {
2698: cursorPos = 1;
2699: if ((getShowDeleted() == false) && (rowDeleted() == true)) {
2700: ret = internalNext();
2701: } else {
2702: ret = true;
2703: }
2704: }
2705:
2706: if (ret == true)
2707: absolutePos = 1;
2708: else
2709: absolutePos = 0;
2710:
2711: return ret;
2712: }
2713:
2714: /**
2715: * {@inheritDoc}
2716: */
2717: public boolean last() throws SQLException {
2718: checkExecuted();
2719: if (getType() == ResultSet.TYPE_FORWARD_ONLY) {
2720: throw new SQLException(rb
2721: .getString("RESULTSET_TYPE_FORWARD_ONLY")); //NOI18N
2722: }
2723:
2724: // move and notify
2725: boolean ret = this .internalLast();
2726: notifyCursorMoved();
2727:
2728: return ret;
2729: }
2730:
2731: protected boolean internalLast() throws SQLException {
2732: boolean ret = false;
2733:
2734: if (numRows > 0) {
2735: cursorPos = numRows;
2736: if ((getShowDeleted() == false) && (rowDeleted() == true)) {
2737: ret = internalPrevious();
2738: } else {
2739: ret = true;
2740: }
2741: }
2742: if (ret == true)
2743: absolutePos = numRows - numDeleted;
2744: else
2745: absolutePos = 0;
2746: return ret;
2747: }
2748:
2749: /**
2750: * {@inheritDoc}
2751: */
2752: public int getRow() throws SQLException {
2753: checkExecuted();
2754: // are we on a valid row? Valid rows are between first and last
2755: if (numRows > 0 && cursorPos > 0 && cursorPos < (numRows + 1)
2756: && (getShowDeleted() == false && rowDeleted() == false)) {
2757: return absolutePos;
2758: } else if (getShowDeleted() == true) {
2759: return cursorPos;
2760: } else {
2761: return 0;
2762: }
2763: }
2764:
2765: /**
2766: * {@inheritDoc}
2767: */
2768: public boolean absolute(int row) throws SQLException {
2769: checkExecuted();
2770: if (row == 0 || getType() == ResultSet.TYPE_FORWARD_ONLY) {
2771: throw new SQLException(rb
2772: .getString("RESULTSET_TYPE_FORWARD_ONLY")); //NOI18N
2773: }
2774:
2775: if (row > 0) { // we are moving foward
2776: if (row > numRows) {
2777: // fell off the end
2778: afterLast();
2779: return false;
2780: } else {
2781: if (absolutePos <= 0)
2782: internalFirst();
2783: }
2784: } else { // we are moving backward
2785: if (cursorPos + row < 0) {
2786: // fell off the front
2787: beforeFirst();
2788: return false;
2789: } else {
2790: if (absolutePos >= 0)
2791: internalLast();
2792: }
2793: }
2794:
2795: // Now move towards the absolute row that we're looking for
2796: while (absolutePos != row) {
2797: if (absolutePos < row) {
2798: if (!internalNext())
2799: break;
2800: } else {
2801: if (!internalPrevious())
2802: break;
2803: }
2804: }
2805:
2806: notifyCursorMoved();
2807:
2808: if (isAfterLast() || isBeforeFirst()) {
2809: return false;
2810: } else {
2811: return true;
2812: }
2813: }
2814:
2815: /**
2816: * {@inheritDoc}
2817: */
2818: public boolean relative(int rows) throws SQLException {
2819: checkExecuted();
2820: if (numRows == 0 || isBeforeFirst() || isAfterLast()
2821: || getType() == ResultSet.TYPE_FORWARD_ONLY) {
2822: throw new SQLException(rb
2823: .getString("RESULTSET_TYPE_FORWARD_ONLY")); //NOI18N
2824: }
2825:
2826: if (rows == 0) {
2827: return true;
2828: }
2829:
2830: if (rows > 0) { // we are moving forward
2831: if (cursorPos + rows > numRows) {
2832: // fell off the end
2833: afterLast();
2834: } else {
2835: for (int i = 0; i < rows; i++) {
2836: if (!internalNext())
2837: break;
2838: }
2839: }
2840: } else { // we are moving backward
2841: if (cursorPos + rows < 0) {
2842: // fell off the front
2843: beforeFirst();
2844: } else {
2845: for (int i = rows; i < 0; i++) {
2846: if (!internalPrevious())
2847: break;
2848: }
2849: }
2850: }
2851: notifyCursorMoved();
2852:
2853: if (isAfterLast() || isBeforeFirst()) {
2854: return false;
2855: } else {
2856: return true;
2857: }
2858: }
2859:
2860: /**
2861: * {@inheritDoc}
2862: */
2863: public boolean previous() throws SQLException {
2864: checkExecuted();
2865: if (getType() == ResultSet.TYPE_FORWARD_ONLY) {
2866: throw new SQLException(rb
2867: .getString("RESULTSET_TYPE_FORWARD_ONLY")); //NOI18N
2868: }
2869: /*
2870: * make sure things look sane. The cursor must be
2871: * positioned in the rowset or before first (0) or
2872: * after last (numRows + 1)
2873: */
2874: if (cursorPos < 0 || cursorPos > numRows + 1) {
2875: throw new SQLException(rb.getString("INVALID_CURSOR_POS")); //NOI18N
2876: }
2877: // move and notify
2878: boolean ret = this .internalPrevious();
2879: notifyCursorMoved();
2880:
2881: return ret;
2882: }
2883:
2884: protected boolean internalPrevious() throws SQLException {
2885: boolean ret = false;
2886:
2887: do {
2888: if (cursorPos > 1) {
2889: --cursorPos;
2890: ret = true;
2891: } else if (cursorPos == 1) {
2892: // decrement to before first
2893: --cursorPos;
2894: ret = false;
2895: break;
2896: }
2897: } while ((getShowDeleted() == false) && (rowDeleted() == true));
2898:
2899: /*
2900: * Each call to internalPrevious may move the cursor
2901: * over multiple rows, the absolute postion moves one one row
2902: */
2903: if (ret == true)
2904: --absolutePos;
2905: else
2906: absolutePos = 0;
2907:
2908: return ret;
2909: }
2910:
2911: //---------------------------------------------------------------------
2912: // Updates
2913: //---------------------------------------------------------------------
2914:
2915: /**
2916: * {@inheritDoc}
2917: */
2918: public boolean rowUpdated() throws SQLException {
2919: checkExecuted();
2920: // make sure the cursor is on a valid row
2921: checkCursor();
2922: if (onInsertRow == true) {
2923: throw new SQLException(rb
2924: .getString("INVALID_INSERT_ROW_OP")); // NOI18N
2925: }
2926: return (((Row) getCurrentRow()).getUpdated());
2927: }
2928:
2929: /**
2930: * {@inheritDoc}
2931: */
2932: public boolean columnUpdated(int idx) throws SQLException {
2933: checkExecuted();
2934: // make sure the cursor is on a valid row
2935: checkCursor();
2936: if (onInsertRow == true) {
2937: throw new SQLException(rb
2938: .getString("INVALID_INSERT_ROW_OP")); // NOI18N
2939: }
2940: return (((Row) getCurrentRow()).getColUpdated(idx - 1));
2941: }
2942:
2943: /**
2944: * {@inheritDoc}
2945: */
2946: public boolean columnUpdated(String columnName) throws SQLException {
2947: checkExecuted();
2948: return columnUpdated(getColIdxByName(columnName));
2949: }
2950:
2951: /**
2952: * {@inheritDoc}
2953: */
2954: public boolean rowInserted() throws SQLException {
2955: checkExecuted();
2956: // make sure the cursor is on a valid row
2957: checkCursor();
2958: if (onInsertRow == true) {
2959: throw new SQLException(rb
2960: .getString("INVALID_INSERT_ROW_OP")); // NOI18N
2961: }
2962: return (((Row) getCurrentRow()).getInserted());
2963: }
2964:
2965: /**
2966: * {@inheritDoc}
2967: */
2968: public boolean rowDeleted() throws SQLException {
2969: checkExecuted();
2970: // make sure the cursor is on a valid row
2971:
2972: if (isAfterLast() == true || isBeforeFirst() == true
2973: || onInsertRow == true) {
2974:
2975: throw new SQLException(rb.getString("INVALID_CURSOR_POS")); //NOI18N
2976: }
2977: return (((Row) getCurrentRow()).getDeleted());
2978: }
2979:
2980: /**
2981: * Indicates whether the given SQL data type is a numberic type.
2982: *
2983: * @param type one of the constants from <code>java.sql.Types</code>
2984: * @return <code>true</code> if the given type is <code>NUMERIC</code>,'
2985: * <code>DECIMAL</code>, <code>BIT</code>, <code>TINYINT</code>,
2986: * <code>SMALLINT</code>, <code>INTEGER</code>, <code>BIGINT</code>,
2987: * <code>REAL</code>, <code>DOUBLE</code>, or <code>FLOAT</code>;
2988: * <code>false</code> otherwise
2989: */
2990: private boolean isNumeric(int type) {
2991: switch (type) {
2992: case java.sql.Types.NUMERIC:
2993: case java.sql.Types.DECIMAL:
2994: case java.sql.Types.BIT:
2995: case java.sql.Types.TINYINT:
2996: case java.sql.Types.SMALLINT:
2997: case java.sql.Types.INTEGER:
2998: case java.sql.Types.BIGINT:
2999: case java.sql.Types.REAL:
3000: case java.sql.Types.DOUBLE:
3001: case java.sql.Types.FLOAT:
3002: return true;
3003: default:
3004: return false;
3005: }
3006: }
3007:
3008: /**
3009: * Indicates whether the given SQL data type is a string type.
3010: *
3011: * @param type one of the constants from <code>java.sql.Types</code>
3012: * @return <code>true</code> if the given type is <code>CHAR</code>,'
3013: * <code>VARCHAR</code>, or <code>LONGVARCHAR</code>;
3014: * <code>false</code> otherwise
3015: */
3016: private boolean isString(int type) {
3017: switch (type) {
3018: case java.sql.Types.CHAR:
3019: case java.sql.Types.VARCHAR:
3020: case java.sql.Types.LONGVARCHAR:
3021: return true;
3022: default:
3023: return false;
3024: }
3025: }
3026:
3027: /**
3028: * Indicates whether the given SQL data type is a binary type.
3029: *
3030: * @param type one of the constants from <code>java.sql.Types</code>
3031: * @return <code>true</code> if the given type is <code>BINARY</code>,'
3032: * <code>VARBINARY</code>, or <code>LONGVARBINARY</code>;
3033: * <code>false</code> otherwise
3034: */
3035: private boolean isBinary(int type) {
3036: switch (type) {
3037: case java.sql.Types.BINARY:
3038: case java.sql.Types.VARBINARY:
3039: case java.sql.Types.LONGVARBINARY:
3040: return true;
3041: default:
3042: return false;
3043: }
3044: }
3045:
3046: /**
3047: * Indicates whether the given SQL data type is a temporal type.
3048: * This method is called internally by the conversion methods
3049: * <code>convertNumeric</code> and <code>convertTemporal</code>.
3050: *
3051: * @param type one of the constants from <code>java.sql.Types</code>
3052: * @return <code>true</code> if the given type is <code>DATE</code>,
3053: * <code>TIME</code>, or <code>TIMESTAMP</code>;
3054: * <code>false</code> otherwise
3055: */
3056: private boolean isTemporal(int type) {
3057: switch (type) {
3058: case java.sql.Types.DATE:
3059: case java.sql.Types.TIME:
3060: case java.sql.Types.TIMESTAMP:
3061: return true;
3062: default:
3063: return false;
3064: }
3065: }
3066:
3067: /**
3068: * Converts the given <code>Object</code> in the Java programming language
3069: * to the standard mapping for the specified SQL target data type.
3070: * The conversion must be to a string or numeric type, but there are no
3071: * restrictions on the type to be converted. If the source type and target
3072: * type are the same, the given object is simply returned.
3073: *
3074: * @param srcObj the <code>Object</code> in the Java programming language
3075: * that is to be converted to the target type
3076: * @param srcType the data type that is the standard mapping in SQL of the
3077: * object to be converted; must be one of the constants in
3078: * <code>java.sql.Types</code>
3079: * @param trgType the SQL data type to which to convert the given object;
3080: * must be one of the following constants in
3081: * <code>java.sql.Types</code>: <code>NUMERIC</code>,
3082: * <code>DECIMAL</code>, <code>BIT</code>, <code>TINYINT</code>,
3083: * <code>SMALLINT</code>, <code>INTEGER</code>, <code>BIGINT</code>,
3084: * <code>REAL</code>, <code>DOUBLE</code>, <code>FLOAT</code>,
3085: * <code>VARCHAR</code>, <code>LONGVARCHAR</code>, or <code>CHAR</code>
3086: * @return an <code>Object</code> value.that is
3087: * the standard object mapping for the target SQL type
3088: * @throws SQLException if the given target type is not one of the string or
3089: * numeric types in <code>java.sql.Types</code>
3090: */
3091: private Object convertNumeric(Object srcObj, int srcType,
3092: int trgType) throws SQLException {
3093:
3094: if (srcType == trgType) {
3095: return srcObj;
3096: }
3097:
3098: if (isNumeric(trgType) == false && isString(trgType) == false) {
3099: throw new SQLException(rb.getString("DATATYPE_MISMATCH")
3100: + trgType); //NOI18N
3101: }
3102:
3103: try {
3104: switch (trgType) {
3105: case java.sql.Types.BIT:
3106: Integer i = new Integer(srcObj.toString().trim());
3107: return i.equals(new Integer((int) 0)) ? new Boolean(
3108: false) : new Boolean(true);
3109: case java.sql.Types.TINYINT:
3110: return new Byte(srcObj.toString().trim());
3111: case java.sql.Types.SMALLINT:
3112: return new Short(srcObj.toString().trim());
3113: case java.sql.Types.INTEGER:
3114: return new Integer(srcObj.toString().trim());
3115: case java.sql.Types.BIGINT:
3116: return new Long(srcObj.toString().trim());
3117: case java.sql.Types.NUMERIC:
3118: case java.sql.Types.DECIMAL:
3119: return new BigDecimal(srcObj.toString().trim());
3120: case java.sql.Types.REAL:
3121: case java.sql.Types.FLOAT:
3122: return new Float(srcObj.toString().trim());
3123: case java.sql.Types.DOUBLE:
3124: return new Double(srcObj.toString().trim());
3125: case java.sql.Types.CHAR:
3126: case java.sql.Types.VARCHAR:
3127: case java.sql.Types.LONGVARCHAR:
3128: return new String(srcObj.toString());
3129: default:
3130: throw new SQLException(rb
3131: .getString("DATATYPE_MISMATCH")
3132: + trgType); //NOI18N
3133: }
3134: } catch (NumberFormatException ex) {
3135: throw new SQLException(rb.getString("DATATYPE_MISMATCH")
3136: + trgType); //NOI18N
3137: }
3138: }
3139:
3140: /**
3141: * Converts the given <code>Object</code> in the Java programming language
3142: * to the standard object mapping for the specified SQL target data type.
3143: * The conversion must be to a string or temporal type, and there are also
3144: * restrictions on the type to be converted.
3145: * <P>
3146: * <TABLE ALIGN="CENTER" BORDER CELLPADDING=10 BORDERCOLOR="#0000FF"
3147: * <CAPTION ALIGN="CENTER"><B>Parameters and Return Values</B></CAPTION>
3148: * <TR>
3149: * <TD><B>Source SQL Type</B>
3150: * <TD><B>Target SQL Type</B>
3151: * <TD><B>Object Returned</B>
3152: * </TR>
3153: * <TR>
3154: * <TD><code>TIMESTAMP</code>
3155: * <TD><code>DATE</code>
3156: * <TD><code>java.sql.Date</code>
3157: * </TR>
3158: * <TR>
3159: * <TD><code>TIMESTAMP</code>
3160: * <TD><code>TIME</code>
3161: * <TD><code>java.sql.Time</code>
3162: * </TR>
3163: * <TR>
3164: * <TD><code>TIME</code>
3165: * <TD><code>TIMESTAMP</code>
3166: * <TD><code>java.sql.Timestamp</code>
3167: * </TR>
3168: * <TR>
3169: * <TD><code>DATE</code>, <code>TIME</code>, or <code>TIMESTAMP</code>
3170: * <TD><code>CHAR</code>, <code>VARCHAR</code>, or <code>LONGVARCHAR</code>
3171: * <TD><code>java.lang.String</code>
3172: * </TR>
3173: * </TABLE>
3174: * <P>
3175: * If the source type and target type are the same,
3176: * the given object is simply returned.
3177: *
3178: * @param srcObj the <code>Object</code> in the Java programming language
3179: * that is to be converted to the target type
3180: * @param srcType the data type that is the standard mapping in SQL of the
3181: * object to be converted; must be one of the constants in
3182: * <code>java.sql.Types</code>
3183: * @param trgType the SQL data type to which to convert the given object;
3184: * must be one of the following constants in
3185: * <code>java.sql.Types</code>: <code>DATE</code>,
3186: * <code>TIME</code>, <code>TIMESTAMP</code>, <code>CHAR</code>,
3187: * <code>VARCHAR</code>, or <code>LONGVARCHAR</code>
3188: * @return an <code>Object</code> value.that is
3189: * the standard object mapping for the target SQL type
3190: * @throws SQLException if the given target type is not one of the string or
3191: * temporal types in <code>java.sql.Types</code>
3192: */
3193: private Object convertTemporal(Object srcObj, int srcType,
3194: int trgType) throws SQLException {
3195:
3196: if (srcType == trgType) {
3197: return srcObj;
3198: }
3199:
3200: if (isNumeric(trgType) == true
3201: || (isString(trgType) == false && isTemporal(trgType) == false)) {
3202: throw new SQLException(rb.getString("DATATYPE_MISMATCH")
3203: + trgType); //NOI18N
3204: }
3205:
3206: try {
3207: switch (trgType) {
3208: case java.sql.Types.DATE:
3209: if (srcType == java.sql.Types.TIMESTAMP) {
3210: return new java.sql.Date(
3211: ((java.sql.Timestamp) srcObj).getTime());
3212: } else {
3213: throw new SQLException(rb
3214: .getString("DATATYPE_MISMATCH")); //NOI18N
3215: }
3216: case java.sql.Types.TIMESTAMP:
3217: if (srcType == java.sql.Types.TIME) {
3218: return new Timestamp(((java.sql.Time) srcObj)
3219: .getTime());
3220: } else {
3221: return new Timestamp(((java.sql.Date) srcObj)
3222: .getTime());
3223: }
3224: case java.sql.Types.TIME:
3225: if (srcType == java.sql.Types.TIMESTAMP) {
3226: return new Time(((java.sql.Timestamp) srcObj)
3227: .getTime());
3228: } else {
3229: throw new SQLException(rb
3230: .getString("DATATYPE_MISMATCH")); //NOI18N
3231: }
3232: case java.sql.Types.CHAR:
3233: case java.sql.Types.VARCHAR:
3234: case java.sql.Types.LONGVARCHAR:
3235: return new String(srcObj.toString());
3236: default:
3237: throw new SQLException(rb
3238: .getString("DATATYPE_MISMATCH")); //NOI18N
3239: }
3240: } catch (NumberFormatException ex) {
3241: throw new SQLException(rb.getString("DATATYPE_MISMATCH")); //NOI18N
3242: }
3243:
3244: }
3245:
3246: /**
3247: * {@inheritDoc}
3248: */
3249: public void updateNull(int columnIndex) throws SQLException {
3250: checkExecuted();
3251: // sanity check.
3252: checkIndex(columnIndex);
3253: // make sure the cursor is on a valid row
3254: checkCursor();
3255:
3256: BaseRow row = getCurrentRow();
3257: row.setColumnObject(columnIndex, null);
3258: }
3259:
3260: /**
3261: * {@inheritDoc}
3262: */
3263: public void updateBoolean(int columnIndex, boolean x)
3264: throws SQLException {
3265: checkExecuted();
3266: // sanity check.
3267: checkIndex(columnIndex);
3268: // make sure the cursor is on a valid row
3269: checkCursor();
3270: Object obj = convertNumeric(new Boolean(x), java.sql.Types.BIT,
3271: rowSetMD.getColumnType(columnIndex));
3272:
3273: getCurrentRow().setColumnObject(columnIndex, obj);
3274: }
3275:
3276: /**
3277: * {@inheritDoc}
3278: */
3279: public void updateByte(int columnIndex, byte x) throws SQLException {
3280: checkExecuted();
3281: // sanity check.
3282: checkIndex(columnIndex);
3283: // make sure the cursor is on a valid row
3284: checkCursor();
3285:
3286: Object obj = convertNumeric(new Byte(x),
3287: java.sql.Types.TINYINT, rowSetMD
3288: .getColumnType(columnIndex));
3289:
3290: getCurrentRow().setColumnObject(columnIndex, obj);
3291: }
3292:
3293: /**
3294: * {@inheritDoc}
3295: */
3296: public void updateShort(int columnIndex, short x)
3297: throws SQLException {
3298: checkExecuted();
3299: // sanity check.
3300: checkIndex(columnIndex);
3301: // make sure the cursor is on a valid row
3302: checkCursor();
3303:
3304: Object obj = convertNumeric(new Short(x),
3305: java.sql.Types.SMALLINT, rowSetMD
3306: .getColumnType(columnIndex));
3307:
3308: getCurrentRow().setColumnObject(columnIndex, obj);
3309: }
3310:
3311: /**
3312: * {@inheritDoc}
3313: */
3314: public void updateInt(int columnIndex, int x) throws SQLException {
3315: checkExecuted();
3316: // sanity check.
3317: checkIndex(columnIndex);
3318: // make sure the cursor is on a valid row
3319: checkCursor();
3320: Object obj = convertNumeric(new Integer(x),
3321: java.sql.Types.INTEGER, rowSetMD
3322: .getColumnType(columnIndex));
3323:
3324: getCurrentRow().setColumnObject(columnIndex, obj);
3325: }
3326:
3327: /**
3328: * {@inheritDoc}
3329: */
3330: public void updateLong(int columnIndex, long x) throws SQLException {
3331: checkExecuted();
3332: // sanity check.
3333: checkIndex(columnIndex);
3334: // make sure the cursor is on a valid row
3335: checkCursor();
3336:
3337: Object obj = convertNumeric(new Long(x), java.sql.Types.BIGINT,
3338: rowSetMD.getColumnType(columnIndex));
3339:
3340: getCurrentRow().setColumnObject(columnIndex, obj);
3341:
3342: }
3343:
3344: /**
3345: * {@inheritDoc}
3346: */
3347: public void updateFloat(int columnIndex, float x)
3348: throws SQLException {
3349: checkExecuted();
3350: // sanity check.
3351: checkIndex(columnIndex);
3352: // make sure the cursor is on a valid row
3353: checkCursor();
3354:
3355: Object obj = convertNumeric(new Float(x), java.sql.Types.REAL,
3356: rowSetMD.getColumnType(columnIndex));
3357:
3358: getCurrentRow().setColumnObject(columnIndex, obj);
3359: }
3360:
3361: /**
3362: * {@inheritDoc}
3363: */
3364: public void updateDouble(int columnIndex, double x)
3365: throws SQLException {
3366: checkExecuted();
3367: // sanity check.
3368: checkIndex(columnIndex);
3369: // make sure the cursor is on a valid row
3370: checkCursor();
3371: Object obj = convertNumeric(new Double(x),
3372: java.sql.Types.DOUBLE, rowSetMD
3373: .getColumnType(columnIndex));
3374:
3375: getCurrentRow().setColumnObject(columnIndex, obj);
3376: }
3377:
3378: /**
3379: * {@inheritDoc}
3380: */
3381: public void updateBigDecimal(int columnIndex, BigDecimal x)
3382: throws SQLException {
3383: checkExecuted();
3384: // sanity check.
3385: checkIndex(columnIndex);
3386: // make sure the cursor is on a valid row
3387: checkCursor();
3388:
3389: Object obj = convertNumeric(x, java.sql.Types.NUMERIC, rowSetMD
3390: .getColumnType(columnIndex));
3391:
3392: getCurrentRow().setColumnObject(columnIndex, obj);
3393: }
3394:
3395: /**
3396: * {@inheritDoc}
3397: */
3398: public void updateString(int columnIndex, String x)
3399: throws SQLException {
3400: checkExecuted();
3401: // sanity check.
3402: checkIndex(columnIndex);
3403: // make sure the cursor is on a valid row
3404: checkCursor();
3405:
3406: getCurrentRow().setColumnObject(columnIndex, x);
3407: }
3408:
3409: /**
3410: * {@inheritDoc}
3411: */
3412: public void updateBytes(int columnIndex, byte x[])
3413: throws SQLException {
3414: checkExecuted();
3415: // sanity check.
3416: checkIndex(columnIndex);
3417: // make sure the cursor is on a valid row
3418: checkCursor();
3419:
3420: if (isBinary(rowSetMD.getColumnType(columnIndex)) == false) {
3421: throw new SQLException(rb.getString("DATATYPE_MISMATCH")); //NOI18N
3422: }
3423:
3424: getCurrentRow().setColumnObject(columnIndex, x);
3425: }
3426:
3427: /**
3428: * {@inheritDoc}
3429: */
3430: public void updateDate(int columnIndex, java.sql.Date x)
3431: throws SQLException {
3432: checkExecuted();
3433: // sanity check.
3434: checkIndex(columnIndex);
3435: // make sure the cursor is on a valid row
3436: checkCursor();
3437:
3438: Object obj = convertTemporal(x, java.sql.Types.DATE, rowSetMD
3439: .getColumnType(columnIndex));
3440:
3441: getCurrentRow().setColumnObject(columnIndex, obj);
3442: }
3443:
3444: /**
3445: * {@inheritDoc}
3446: */
3447: public void updateTime(int columnIndex, java.sql.Time x)
3448: throws SQLException {
3449: checkExecuted();
3450: // sanity check.
3451: checkIndex(columnIndex);
3452: // make sure the cursor is on a valid row
3453: checkCursor();
3454:
3455: Object obj = convertTemporal(x, java.sql.Types.TIME, rowSetMD
3456: .getColumnType(columnIndex));
3457:
3458: getCurrentRow().setColumnObject(columnIndex, obj);
3459: }
3460:
3461: /**
3462: * {@inheritDoc}
3463: */
3464: public void updateTimestamp(int columnIndex, java.sql.Timestamp x)
3465: throws SQLException {
3466: checkExecuted();
3467: // sanity check.
3468: checkIndex(columnIndex);
3469: // make sure the cursor is on a valid row
3470: checkCursor();
3471:
3472: Object obj = convertTemporal(x, java.sql.Types.TIMESTAMP,
3473: rowSetMD.getColumnType(columnIndex));
3474:
3475: getCurrentRow().setColumnObject(columnIndex, obj);
3476: }
3477:
3478: /**
3479: * {@inheritDoc}
3480: */
3481: public void updateAsciiStream(int columnIndex,
3482: java.io.InputStream x, int length) throws SQLException {
3483: checkExecuted();
3484: // sanity Check
3485: checkIndex(columnIndex);
3486: // make sure the cursor is on a valid row
3487: checkCursor();
3488:
3489: if (isString(rowSetMD.getColumnType(columnIndex)) == false
3490: && isBinary(rowSetMD.getColumnType(columnIndex)) == false) {
3491: throw new SQLException(rb.getString("DATATYPE_MISMATCH")); //NOI18N
3492: }
3493:
3494: byte buf[] = new byte[length];
3495: try {
3496: int charsRead = 0;
3497: do {
3498: charsRead += x.read(buf, charsRead, length - charsRead);
3499: } while (charsRead != length);
3500: //Changed the condition check to check for length instead of -1
3501: } catch (java.io.IOException ex) {
3502: throw new SQLException(rb
3503: .getString("READ_FAILED_ASCII_STREAM")); //NOI18N
3504: }
3505: String str = new String(buf);
3506:
3507: getCurrentRow().setColumnObject(columnIndex, str);
3508:
3509: }
3510:
3511: /**
3512: * {@inheritDoc}
3513: */
3514: public void updateBinaryStream(int columnIndex,
3515: java.io.InputStream x, int length) throws SQLException {
3516: checkExecuted();
3517: // sanity Check
3518: checkIndex(columnIndex);
3519: // make sure the cursor is on a valid row
3520: checkCursor();
3521:
3522: if (isBinary(rowSetMD.getColumnType(columnIndex)) == false) {
3523: throw new SQLException(rb.getString("DATATYPE_MISMATCH")); //NOI18N
3524: }
3525:
3526: byte buf[] = new byte[length];
3527: try {
3528: int bytesRead = 0;
3529: do {
3530: bytesRead += x.read(buf, bytesRead, length - bytesRead);
3531: } while (bytesRead != -1);
3532: } catch (java.io.IOException ex) {
3533: throw new SQLException(rb
3534: .getString("READ_FAILED_BINARY_STREAM")); //NOI18N
3535: }
3536:
3537: getCurrentRow().setColumnObject(columnIndex, buf);
3538: }
3539:
3540: /**
3541: * {@inheritDoc}
3542: */
3543: public void updateCharacterStream(int columnIndex,
3544: java.io.Reader x, int length) throws SQLException {
3545: checkExecuted();
3546: // sanity Check
3547: checkIndex(columnIndex);
3548: // make sure the cursor is on a valid row
3549: checkCursor();
3550:
3551: if (isString(rowSetMD.getColumnType(columnIndex)) == false
3552: && isBinary(rowSetMD.getColumnType(columnIndex)) == false) {
3553: throw new SQLException(rb.getString("DATATYPE_MISMATCH")); //NOI18N
3554: }
3555:
3556: char buf[] = new char[length];
3557: try {
3558: int charsRead = 0;
3559: do {
3560: charsRead += x.read(buf, charsRead, length - charsRead);
3561: } while (charsRead != length);
3562: //Changed the condition checking to check for length instead of -1
3563: } catch (java.io.IOException ex) {
3564: throw new SQLException(rb
3565: .getString("READ_FAILED_BINARY_STREAM")); //NOI18N
3566: }
3567: String str = new String(buf);
3568:
3569: getCurrentRow().setColumnObject(columnIndex, str);
3570: }
3571:
3572: /**
3573: * {@inheritDoc}
3574: */
3575: public void updateObject(int columnIndex, Object x, int scale)
3576: throws SQLException {
3577: checkExecuted();
3578: // sanity check.
3579: checkIndex(columnIndex);
3580: // make sure the cursor is on a valid row
3581: checkCursor();
3582:
3583: int type = rowSetMD.getColumnType(columnIndex);
3584: if (type == Types.DECIMAL || type == Types.NUMERIC) {
3585: ((java.math.BigDecimal) x).setScale(scale);
3586: }
3587: getCurrentRow().setColumnObject(columnIndex, x);
3588: }
3589:
3590: /**
3591: * {@inheritDoc}
3592: */
3593: public void updateObject(int columnIndex, Object x)
3594: throws SQLException {
3595: checkExecuted();
3596: // sanity check.
3597: checkIndex(columnIndex);
3598: // make sure the cursor is on a valid row
3599: checkCursor();
3600:
3601: getCurrentRow().setColumnObject(columnIndex, x);
3602: }
3603:
3604: /**
3605: * {@inheritDoc}
3606: */
3607: public void updateNull(String columnName) throws SQLException {
3608: checkExecuted();
3609: updateNull(getColIdxByName(columnName));
3610: }
3611:
3612: /**
3613: * {@inheritDoc}
3614: */
3615: public void updateBoolean(String columnName, boolean x)
3616: throws SQLException {
3617: checkExecuted();
3618: updateBoolean(getColIdxByName(columnName), x);
3619: }
3620:
3621: public void updateByte(String columnName, byte x)
3622: throws SQLException {
3623: checkExecuted();
3624: updateByte(getColIdxByName(columnName), x);
3625: }
3626:
3627: public void updateShort(String columnName, short x)
3628: throws SQLException {
3629: checkExecuted();
3630: updateShort(getColIdxByName(columnName), x);
3631: }
3632:
3633: public void updateInt(String columnName, int x) throws SQLException {
3634: checkExecuted();
3635: updateInt(getColIdxByName(columnName), x);
3636: }
3637:
3638: public void updateLong(String columnName, long x)
3639: throws SQLException {
3640: checkExecuted();
3641: updateLong(getColIdxByName(columnName), x);
3642: }
3643:
3644: public void updateFloat(String columnName, float x)
3645: throws SQLException {
3646: checkExecuted();
3647: updateFloat(getColIdxByName(columnName), x);
3648: }
3649:
3650: public void updateDouble(String columnName, double x)
3651: throws SQLException {
3652: checkExecuted();
3653: updateDouble(getColIdxByName(columnName), x);
3654: }
3655:
3656: public void updateBigDecimal(String columnName, BigDecimal x)
3657: throws SQLException {
3658: checkExecuted();
3659: updateBigDecimal(getColIdxByName(columnName), x);
3660: }
3661:
3662: public void updateString(String columnName, String x)
3663: throws SQLException {
3664: checkExecuted();
3665: updateString(getColIdxByName(columnName), x);
3666: }
3667:
3668: public void updateBytes(String columnName, byte x[])
3669: throws SQLException {
3670: checkExecuted();
3671: updateBytes(getColIdxByName(columnName), x);
3672: }
3673:
3674: public void updateDate(String columnName, java.sql.Date x)
3675: throws SQLException {
3676: checkExecuted();
3677: updateDate(getColIdxByName(columnName), x);
3678: }
3679:
3680: public void updateTime(String columnName, java.sql.Time x)
3681: throws SQLException {
3682: checkExecuted();
3683: updateTime(getColIdxByName(columnName), x);
3684: }
3685:
3686: public void updateTimestamp(String columnName, java.sql.Timestamp x)
3687: throws SQLException {
3688: checkExecuted();
3689: updateTimestamp(getColIdxByName(columnName), x);
3690: }
3691:
3692: public void updateAsciiStream(String columnName,
3693: java.io.InputStream x, int length) throws SQLException {
3694: checkExecuted();
3695: updateAsciiStream(getColIdxByName(columnName), x, length);
3696: }
3697:
3698: public void updateBinaryStream(String columnName,
3699: java.io.InputStream x, int length) throws SQLException {
3700: checkExecuted();
3701: updateBinaryStream(getColIdxByName(columnName), x, length);
3702: }
3703:
3704: public void updateCharacterStream(String columnName,
3705: java.io.Reader reader, int length) throws SQLException {
3706: checkExecuted();
3707: updateCharacterStream(getColIdxByName(columnName), reader,
3708: length);
3709: }
3710:
3711: public void updateObject(String columnName, Object x, int scale)
3712: throws SQLException {
3713: checkExecuted();
3714: updateObject(getColIdxByName(columnName), x, scale);
3715: }
3716:
3717: public void updateObject(String columnName, Object x)
3718: throws SQLException {
3719: checkExecuted();
3720: updateObject(getColIdxByName(columnName), x);
3721: }
3722:
3723: public void insertRow() throws SQLException {
3724: checkExecuted();
3725: int pos;
3726:
3727: if (onInsertRow == false) {
3728: throw new SQLException(rb.getString("INSERT_ROW_FAILED")); //NOI18N
3729: }
3730: /* We cannot reliably compute whether or not this is a complete row without
3731: * obtaining a connection to see what is and isn't an insertable column. For
3732: * now, we will relax this requirement. In the future, perhaps we will obtain this
3733: * information when the rowset is populated -- and then hand it off to the writer
3734: * (which is currently computing this type of information.
3735: *
3736: if (insertRow.isCompleteRow(rowSetMD) == false) {
3737: throw new SQLException(rb.getString("INSERT_ROW_FAILED")); //NOI18N
3738: }
3739: */
3740: // Added the setting of parameters that are passed
3741: // to setXXX methods after an empty CRS Object is
3742: // created through RowSetMetaData object
3743: // removed what came from the RI version - bug 6345804
3744: Row insRow = new Row(rowSetMD.getColumnCount(), insertRow
3745: .getOrigRow());
3746: insRow.setInserted();
3747: /*
3748: * The new row is inserted into the RowSet
3749: * immediately following the current row.
3750: *
3751: * If we are afterlast then the rows are
3752: * inserted at the end.
3753: */
3754: if (currentRow >= numRows || currentRow < 0) {
3755: pos = numRows;
3756: } else {
3757: pos = currentRow;
3758: }
3759:
3760: rvh.add(pos, insRow);
3761: ++numRows;
3762: onInsertRow = false;
3763: cursorPos = currentRow; /*!JK: aded this */
3764: // notify the listeners that the row changed.
3765: notifyRowChanged();
3766: }
3767:
3768: public void updateRow() throws SQLException {
3769: checkExecuted();
3770: // make sure we aren't on the insert row
3771: if (onInsertRow == true) {
3772: throw new SQLException(rb
3773: .getString("UPDATE_ROW_CALLED_ON_INSERT_ROW")); //NOI18N
3774: }
3775:
3776: ((Row) getCurrentRow()).setUpdated();
3777:
3778: // notify the listeners that the row changed.
3779: notifyRowChanged();
3780: }
3781:
3782: public void deleteRow() throws SQLException {
3783: checkExecuted();
3784: // make sure the cursor is on a valid row
3785: checkCursor();
3786:
3787: ((Row) getCurrentRow()).setDeleted();
3788: ++numDeleted;
3789:
3790: // notify the listeners that the row changed.
3791: notifyRowChanged();
3792: }
3793:
3794: public void refreshRow() throws SQLException {
3795: checkExecuted();
3796: // make sure we are on a row
3797: checkCursor();
3798:
3799: // don't want this to happen...
3800: if (onInsertRow == true) {
3801: throw new SQLException(rb.getString("INVALID_CURSOR_POS")); //NOI18N
3802: }
3803:
3804: Row currentRow = (Row) getCurrentRow();
3805: // just undo any changes made to this row.
3806: currentRow.clearUpdated();
3807:
3808: }
3809:
3810: public void cancelRowUpdates() throws SQLException {
3811: checkExecuted();
3812: // make sure we are on a row
3813: checkCursor();
3814:
3815: // don't want this to happen...
3816: if (onInsertRow == true) {
3817: throw new SQLException(rb.getString("INVALID_CURSOR_POS")); //NOI18N
3818: }
3819:
3820: Row currentRow = (Row) getCurrentRow();
3821: if (currentRow.getUpdated() == true) {
3822: currentRow.clearUpdated();
3823: notifyRowChanged();
3824: }
3825: }
3826:
3827: public void moveToInsertRow() throws SQLException {
3828: checkExecuted();
3829: if (getConcurrency() == ResultSet.CONCUR_READ_ONLY) {
3830: throw new SQLException(rb
3831: .getString("RESULTSET_IS_READONLY")); //NOI18N
3832: }
3833: if (insertRow == null) {
3834: if (rowSetMD == null)
3835: throw new SQLException(rb
3836: .getString("MOVE_TO_INSERT_ROW_NO_MD")); //NOI18N
3837: int numCols = rowSetMD.getColumnCount();
3838: if (numCols > 0) {
3839: insertRow = new InsertRow(numCols);
3840: } else {
3841: throw new SQLException(
3842: rb
3843: .getString("MOVE_TO_INSERT_ROW_INVALID_NO_OF_COLS")); //NOI18N
3844: }
3845: }
3846: onInsertRow = true;
3847: // %%% setCurrentRow called in BaseRow
3848:
3849: currentRow = cursorPos;
3850: cursorPos = -1;
3851:
3852: insertRow.initInsertRow();
3853: }
3854:
3855: public void moveToCurrentRow() throws SQLException {
3856: checkExecuted();
3857: if (onInsertRow == false) {
3858: return;
3859: } else {
3860: cursorPos = currentRow;
3861: onInsertRow = false;
3862: }
3863: }
3864:
3865: /**
3866: * Returns <code>null</code>.
3867: *
3868: * @return <code>null</code>
3869: * @throws SQLException if an error occurs
3870: */
3871: public Statement getStatement() throws SQLException {
3872: return null;
3873: }
3874:
3875: public Object getObject(int columnIndex, java.util.Map map)
3876: throws SQLException {
3877: checkExecuted();
3878: Object value;
3879:
3880: // sanity check.
3881: checkIndex(columnIndex);
3882: // make sure the cursor is on a valid row
3883: checkCursor();
3884:
3885: setLastValueNull(false);
3886: value = getCurrentRow().getColumnObject(columnIndex);
3887:
3888: // check for SQL NULL
3889: if (value == null) {
3890: setLastValueNull(true);
3891: return null;
3892: }
3893: if (value instanceof Struct) {
3894: Struct s = (Struct) value;
3895:
3896: // look up the class in the map
3897: Class c = (Class) map.get(s.getSQLTypeName());
3898: if (c != null) {
3899: // create new instance of the class
3900: SQLData obj = null;
3901: try {
3902: obj = (SQLData) c.newInstance();
3903: } catch (java.lang.InstantiationException ex) {
3904: throw new SQLException(rb
3905: .getString("UNABLE_TO_INSTANTIATE")
3906: + ex.getMessage()); //NOI18N
3907: } catch (java.lang.IllegalAccessException ex) {
3908: throw new SQLException(rb
3909: .getString("UNABLE_TO_INSTANTIATE")
3910: + ex.getMessage()); //NOI18N
3911: }
3912: // get the attributes from the struct
3913: Object attribs[] = s.getAttributes(map);
3914: // create the SQLInput "stream"
3915: SQLInputImpl sqlInput = new SQLInputImpl(attribs, map);
3916: // read the values...
3917: obj.readSQL(sqlInput, s.getSQLTypeName());
3918: return (Object) obj;
3919: }
3920: }
3921: return value;
3922: }
3923:
3924: public Ref getRef(int columnIndex) throws SQLException {
3925: checkExecuted();
3926: Ref value;
3927:
3928: // sanity check.
3929: checkIndex(columnIndex);
3930: // make sure the cursor is on a valid row
3931: checkCursor();
3932:
3933: if (rowSetMD.getColumnType(columnIndex) != java.sql.Types.REF) {
3934: throw new SQLException(rb.getString("DATATYPE_MISMATCH")); //NOI18N
3935: }
3936:
3937: setLastValueNull(false);
3938: value = (Ref) (getCurrentRow().getColumnObject(columnIndex));
3939:
3940: // check for SQL NULL
3941: if (value == null) {
3942: setLastValueNull(true);
3943: return null;
3944: }
3945:
3946: return value;
3947: }
3948:
3949: public Blob getBlob(int columnIndex) throws SQLException {
3950: checkExecuted();
3951: Blob value;
3952:
3953: // sanity check.
3954: checkIndex(columnIndex);
3955: // make sure the cursor is on a valid row
3956: checkCursor();
3957:
3958: if (rowSetMD.getColumnType(columnIndex) != java.sql.Types.BLOB) {
3959: //System.out.println("Type is: "+rowSetMD.getColumnType(columnIndex));
3960: throw new SQLException(rb.getString("DATATYPE_MISMATCH")); //NOI18N
3961: }
3962:
3963: setLastValueNull(false);
3964: value = (Blob) (getCurrentRow().getColumnObject(columnIndex));
3965:
3966: // check for SQL NULL
3967: if (value == null) {
3968: setLastValueNull(true);
3969: return null;
3970: }
3971:
3972: return value;
3973: }
3974:
3975: public Clob getClob(int columnIndex) throws SQLException {
3976: checkExecuted();
3977: Clob value;
3978:
3979: // sanity check.
3980: checkIndex(columnIndex);
3981: // make sure the cursor is on a valid row
3982: checkCursor();
3983:
3984: if (rowSetMD.getColumnType(columnIndex) != java.sql.Types.CLOB) {
3985: //System.out.println("Type is: "+rowSetMD.getColumnType(columnIndex));
3986: throw new SQLException(rb.getString("DATATYPE_MISMATCH")); //NOI18N
3987: }
3988:
3989: setLastValueNull(false);
3990: value = (Clob) (getCurrentRow().getColumnObject(columnIndex));
3991:
3992: // check for SQL NULL
3993: if (value == null) {
3994: setLastValueNull(true);
3995: return null;
3996: }
3997:
3998: return value;
3999: }
4000:
4001: public Array getArray(int columnIndex) throws SQLException {
4002: checkExecuted();
4003: java.sql.Array value;
4004:
4005: // sanity check.
4006: checkIndex(columnIndex);
4007: // make sure the cursor is on a valid row
4008: checkCursor();
4009:
4010: if (rowSetMD.getColumnType(columnIndex) != java.sql.Types.ARRAY) {
4011: throw new SQLException(rb.getString("DATATYPE_MISMATCH")); //NOI18N
4012: }
4013:
4014: setLastValueNull(false);
4015: value = (java.sql.Array) (getCurrentRow()
4016: .getColumnObject(columnIndex));
4017:
4018: // check for SQL NULL
4019: if (value == null) {
4020: setLastValueNull(true);
4021: return null;
4022: }
4023:
4024: return value;
4025: }
4026:
4027: public Object getObject(String columnName, java.util.Map map)
4028: throws SQLException {
4029: checkExecuted();
4030: return getObject(getColIdxByName(columnName), map);
4031: }
4032:
4033: public Ref getRef(String colName) throws SQLException {
4034: checkExecuted();
4035: return getRef(getColIdxByName(colName));
4036: }
4037:
4038: public Blob getBlob(String colName) throws SQLException {
4039: checkExecuted();
4040: return getBlob(getColIdxByName(colName));
4041: }
4042:
4043: public Clob getClob(String colName) throws SQLException {
4044: checkExecuted();
4045: return getClob(getColIdxByName(colName));
4046: }
4047:
4048: public Array getArray(String colName) throws SQLException {
4049: checkExecuted();
4050: return getArray(getColIdxByName(colName));
4051: }
4052:
4053: public java.sql.Date getDate(int columnIndex, Calendar cal)
4054: throws SQLException {
4055: checkExecuted();
4056: Object value;
4057:
4058: // sanity check.
4059: checkIndex(columnIndex);
4060: // make sure the cursor is on a valid row
4061: checkCursor();
4062:
4063: setLastValueNull(false);
4064: value = getCurrentRow().getColumnObject(columnIndex);
4065:
4066: // check for SQL NULL
4067: if (value == null) {
4068: setLastValueNull(true);
4069: return null;
4070: }
4071:
4072: value = convertTemporal(value, rowSetMD
4073: .getColumnType(columnIndex), java.sql.Types.DATE);
4074:
4075: // create a default calendar
4076: Calendar defaultCal = Calendar.getInstance();
4077: // set this Calendar to the time we have
4078: defaultCal.setTime((java.util.Date) value);
4079:
4080: /*
4081: * Now we can pull the pieces of the date out
4082: * of the default calendar and put them into
4083: * the user provided calendar
4084: */
4085: cal.set(Calendar.YEAR, defaultCal.get(Calendar.YEAR));
4086: cal.set(Calendar.MONTH, defaultCal.get(Calendar.MONTH));
4087: cal.set(Calendar.DAY_OF_MONTH, defaultCal
4088: .get(Calendar.DAY_OF_MONTH));
4089:
4090: /*
4091: * This looks a little odd but it is correct -
4092: * Calendar.getTime() returns a Date...
4093: */
4094: return new java.sql.Date(cal.getTime().getTime());
4095: }
4096:
4097: public java.sql.Date getDate(String columnName, Calendar cal)
4098: throws SQLException {
4099: checkExecuted();
4100: return getDate(getColIdxByName(columnName), cal);
4101: }
4102:
4103: public java.sql.Time getTime(int columnIndex, Calendar cal)
4104: throws SQLException {
4105: checkExecuted();
4106: Object value;
4107:
4108: // sanity check.
4109: checkIndex(columnIndex);
4110: // make sure the cursor is on a valid row
4111: checkCursor();
4112:
4113: setLastValueNull(false);
4114: value = getCurrentRow().getColumnObject(columnIndex);
4115:
4116: // check for SQL NULL
4117: if (value == null) {
4118: setLastValueNull(true);
4119: return null;
4120: }
4121:
4122: value = convertTemporal(value, rowSetMD
4123: .getColumnType(columnIndex), java.sql.Types.TIME);
4124:
4125: // create a default calendar
4126: Calendar defaultCal = Calendar.getInstance();
4127: // set the time in the default calendar
4128: defaultCal.setTime((java.util.Date) value);
4129:
4130: /*
4131: * Now we can pull the pieces of the date out
4132: * of the default calendar and put them into
4133: * the user provided calendar
4134: */
4135: cal.set(Calendar.HOUR_OF_DAY, defaultCal
4136: .get(Calendar.HOUR_OF_DAY));
4137: cal.set(Calendar.MINUTE, defaultCal.get(Calendar.MINUTE));
4138: cal.set(Calendar.SECOND, defaultCal.get(Calendar.SECOND));
4139:
4140: return new java.sql.Time(cal.getTime().getTime());
4141: }
4142:
4143: public java.sql.Time getTime(String columnName, Calendar cal)
4144: throws SQLException {
4145: checkExecuted();
4146: return getTime(getColIdxByName(columnName), cal);
4147: }
4148:
4149: public java.sql.Timestamp getTimestamp(int columnIndex, Calendar cal)
4150: throws SQLException {
4151: checkExecuted();
4152: Object value;
4153:
4154: // sanity check.
4155: checkIndex(columnIndex);
4156: // make sure the cursor is on a valid row
4157: checkCursor();
4158:
4159: setLastValueNull(false);
4160: value = getCurrentRow().getColumnObject(columnIndex);
4161:
4162: // check for SQL NULL
4163: if (value == null) {
4164: setLastValueNull(true);
4165: return null;
4166: }
4167:
4168: value = convertTemporal(value, rowSetMD
4169: .getColumnType(columnIndex), java.sql.Types.TIMESTAMP);
4170:
4171: // create a default calendar
4172: Calendar defaultCal = Calendar.getInstance();
4173: // set the time in the default calendar
4174: defaultCal.setTime((java.util.Date) value);
4175:
4176: /*
4177: * Now we can pull the pieces of the date out
4178: * of the default calendar and put them into
4179: * the user provided calendar
4180: */
4181: cal.set(Calendar.YEAR, defaultCal.get(Calendar.YEAR));
4182: cal.set(Calendar.MONTH, defaultCal.get(Calendar.MONTH));
4183: cal.set(Calendar.DAY_OF_MONTH, defaultCal
4184: .get(Calendar.DAY_OF_MONTH));
4185: cal.set(Calendar.HOUR_OF_DAY, defaultCal
4186: .get(Calendar.HOUR_OF_DAY));
4187: cal.set(Calendar.MINUTE, defaultCal.get(Calendar.MINUTE));
4188: cal.set(Calendar.SECOND, defaultCal.get(Calendar.SECOND));
4189:
4190: return new java.sql.Timestamp(cal.getTime().getTime());
4191: }
4192:
4193: public java.sql.Timestamp getTimestamp(String columnName,
4194: Calendar cal) throws SQLException {
4195: checkExecuted();
4196: return getTimestamp(getColIdxByName(columnName), cal);
4197: }
4198:
4199: /*
4200: * RowSetInternal Interface
4201: */
4202:
4203: /**
4204: * Retrieves the <code>Connection</code> object passed to this
4205: * <code>CachedRowSetXImpl</code> object. This connection may be
4206: * used to populate this rowset with data or to write data back
4207: * to its underlying data source.
4208: *
4209: * @return the <code>Connection</code> object passed to this rowset;
4210: * may be <code>null</code> if there is no connection
4211: * @throws SQLException if an error occurs
4212: */
4213: public Connection getConnection() throws SQLException {
4214:
4215: return conn;
4216: }
4217:
4218: /**
4219: * Given a dataSourceName, url, username and password, create a connection
4220: * If dataSourceName is null, assume a Driver Manager connection
4221: * If username is null, don't pass them to the lookup method
4222: *
4223: * @return the <code>Connection</code> object
4224: *
4225: * @throws SQLException if an error occurs
4226: */
4227: static private Connection getConnection(String dataSourceName,
4228: String url, String username, String password)
4229: throws SQLException {
4230:
4231: Log.getLogger()
4232: .entering(
4233: "CachedRowSetXImpl",
4234: "getConnection()",
4235: new Object[] { dataSourceName, url, username,
4236: password });
4237:
4238: Connection conn = null;
4239: if (dataSourceName != null) {
4240: // Connect using JNDI.
4241: try {
4242: Context ctx = new InitialContext();
4243: Log.getLogger().finest(
4244: "About to get DataSource, ctx: " + ctx);
4245:
4246: DataSource ds = (DataSource) ctx.lookup(dataSourceName);
4247:
4248: Log.getLogger().finest(
4249: "About to get connection, DataSource: " + ds);
4250:
4251: if (username == null || username.equals("")) { //NOI18N
4252: conn = ds.getConnection();
4253: } else {
4254: conn = ds.getConnection(username, password);
4255: }
4256: } catch (javax.naming.NamingException ex) {
4257: Log.getLogger().finest(
4258: "Caught exception: " + ex + " "
4259: + ex.getMessage());
4260: throw new SQLException(rb
4261: .getString("UNABLE_TO_CONNECT")
4262: + ex.getMessage()); //NOI18N
4263: }
4264: } else if (url != null) {
4265: // Check only for url != null because
4266: // user, passwd can be null
4267: // Connect using the driver manager.
4268: conn = DriverManager.getConnection(url, username, password);
4269: } else {
4270: throw new SQLException(rb
4271: .getString("BOTH_DS_AND_URL_CANNOT_BE_NULL")); //NOI18N
4272: }
4273: return conn;
4274: }
4275:
4276: public void setMetaData(RowSetMetaData md) throws SQLException {
4277: rowSetMD = md;
4278: }
4279:
4280: // Implemented in CachedRowSetXImpl
4281: public abstract ResultSet getOriginal() throws SQLException;
4282:
4283: // Implemented in CachedRowSetXImpl
4284: public abstract ResultSet getOriginalRow() throws SQLException;
4285:
4286: public void setOriginalRow() throws SQLException {
4287: checkExecuted();
4288: if (onInsertRow == true) {
4289: throw new SQLException(rb
4290: .getString("INVALID_INSERT_ROW_OP")); //NOI18N
4291: }
4292:
4293: Row row = (Row) getCurrentRow();
4294: makeRowOriginal(row);
4295:
4296: // this can happen if deleted rows are being shown
4297: if (row.getDeleted() == true) {
4298: removeCurrentRow();
4299: --numRows;
4300: }
4301: }
4302:
4303: private void makeRowOriginal(Row row) {
4304: if (row.getInserted() == true) {
4305: row.clearInserted();
4306: }
4307:
4308: if (row.getUpdated() == true) {
4309: row.moveCurrentToOrig();
4310: }
4311: }
4312:
4313: public void setOriginal() throws SQLException {
4314: checkExecuted();
4315: for (Iterator i = rvh.iterator(); i.hasNext();) {
4316: Row row = (Row) i.next();
4317: makeRowOriginal(row);
4318: // remove deleted rows from the collection.
4319: if (row.getDeleted() == true) {
4320: i.remove();
4321: --numRows;
4322: }
4323: }
4324: numDeleted = 0;
4325:
4326: // notify any listeners that the rowset has changed
4327: notifyRowSetChanged();
4328: }
4329:
4330: public String getTableName() throws SQLException {
4331: return tableName;
4332: }
4333:
4334: public void setTableName(String tabName) throws SQLException {
4335: if (tabName == null)
4336: throw new SQLException(rb
4337: .getString("TABLENAME_CANNOT_BE_NULL")); //NOI18N
4338: else
4339: tableName = new String(tabName);
4340: }
4341:
4342: public int[] getKeyColumns() throws SQLException {
4343: return keyCols;
4344: }
4345:
4346: public void setKeyColumns(int[] keys) throws SQLException {
4347: int numCols = 0;
4348: if (rowSetMD != null) {
4349: numCols = rowSetMD.getColumnCount();
4350: if (keys.length > numCols)
4351: throw new SQLException(rb.getString("INVALID_KEY_COLS")); //NOI18N
4352: }
4353: keyCols = new int[keys.length];
4354: for (int i = 0; i < keys.length; i++) {
4355: if (rowSetMD != null && (keys[i] <= 0 || keys[i] > numCols)) {
4356: throw new SQLException(MessageFormat.format(rb
4357: .getString("INVALID_COLUMN_INDEX"), //NOI18N
4358: new Object[] { new Integer(keys[i]) }));
4359: }
4360: keyCols[i] = keys[i];
4361: }
4362: }
4363:
4364: public void updateRef(int columnIndex, java.sql.Ref ref)
4365: throws SQLException {
4366: checkExecuted();
4367: // sanity check.
4368: checkIndex(columnIndex);
4369: // make sure the cursor is on a valid row
4370: checkCursor();
4371:
4372: // SerialClob will help in getting the byte array and storing it.
4373: // We need to be checking DatabaseMetaData.locatorsUpdatorCopy()
4374: // or through RowSetMetaData.locatorsUpdatorCopy()
4375: getCurrentRow()
4376: .setColumnObject(columnIndex, new SerialRef(ref));
4377: }
4378:
4379: public void updateRef(String columnName, java.sql.Ref ref)
4380: throws SQLException {
4381: checkExecuted();
4382: updateRef(getColIdxByName(columnName), ref);
4383: }
4384:
4385: public void updateClob(int columnIndex, Clob c) throws SQLException {
4386: checkExecuted();
4387: // sanity check.
4388: checkIndex(columnIndex);
4389: // make sure the cursor is on a valid row
4390: checkCursor();
4391:
4392: // SerialClob will help in getting the byte array and storing it.
4393: // We need to be checking DatabaseMetaData.locatorsUpdatorCopy()
4394: // or through RowSetMetaData.locatorsUpdatorCopy()
4395:
4396: if (dbmslocatorsUpdateCopy) {
4397: getCurrentRow().setColumnObject(columnIndex,
4398: new SerialClob(c));
4399: } else {
4400: throw new SQLException(rb
4401: .getString("OP_NOT_SUPPORTED_BY_DB")); //NOI18N
4402: }
4403: }
4404:
4405: public void updateClob(String columnName, Clob c)
4406: throws SQLException {
4407: checkExecuted();
4408: updateClob(getColIdxByName(columnName), c);
4409: }
4410:
4411: public void updateBlob(int columnIndex, Blob b) throws SQLException {
4412: checkExecuted();
4413: // sanity check.
4414: checkIndex(columnIndex);
4415: // make sure the cursor is on a valid row
4416: checkCursor();
4417:
4418: // SerialBlob will help in getting the byte array and storing it.
4419: // We need to be checking DatabaseMetaData.locatorsUpdatorCopy()
4420: // or through RowSetMetaData.locatorsUpdatorCopy()
4421:
4422: if (dbmslocatorsUpdateCopy) {
4423: getCurrentRow().setColumnObject(columnIndex,
4424: new SerialBlob(b));
4425: } else {
4426: throw new SQLException(rb
4427: .getString("OP_NOT_SUPPORTED_BY_DB")); //NOI18N
4428: }
4429: }
4430:
4431: public void updateBlob(String columnName, Blob b)
4432: throws SQLException {
4433: checkExecuted();
4434: updateBlob(getColIdxByName(columnName), b);
4435: }
4436:
4437: public void updateArray(int columnIndex, Array a)
4438: throws SQLException {
4439: checkExecuted();
4440: // sanity check.
4441: checkIndex(columnIndex);
4442: // make sure the cursor is on a valid row
4443: checkCursor();
4444:
4445: // SerialArray will help in getting the byte array and storing it.
4446: // We need to be checking DatabaseMetaData.locatorsUpdatorCopy()
4447: // or through RowSetMetaData.locatorsUpdatorCopy()
4448: getCurrentRow()
4449: .setColumnObject(columnIndex, new SerialArray(a));
4450: }
4451:
4452: public void updateArray(String columnName, Array a)
4453: throws SQLException {
4454: checkExecuted();
4455: updateArray(getColIdxByName(columnName), a);
4456: }
4457:
4458: public java.net.URL getURL(int columnIndex) throws SQLException {
4459: checkExecuted();
4460:
4461: java.net.URL value;
4462:
4463: // sanity check.
4464: checkIndex(columnIndex);
4465: // make sure the cursor is on a valid row
4466: checkCursor();
4467:
4468: if (rowSetMD.getColumnType(columnIndex) != java.sql.Types.DATALINK) {
4469: throw new SQLException(rb.getString("DATATYPE_MISMATCH")); //NOI18N
4470: }
4471:
4472: setLastValueNull(false);
4473: value = (java.net.URL) (getCurrentRow()
4474: .getColumnObject(columnIndex));
4475:
4476: // check for SQL NULL
4477: if (value == null) {
4478: setLastValueNull(true);
4479: return null;
4480: }
4481:
4482: return value;
4483: }
4484:
4485: public java.net.URL getURL(String columnName) throws SQLException {
4486: checkExecuted();
4487: return getURL(getColIdxByName(columnName));
4488:
4489: }
4490:
4491: public RowSetWarning getRowSetWarnings() {
4492: try {
4493: notifyCursorMoved();
4494: } catch (SQLException e) {
4495: } // mask exception
4496: return rowsetWarning;
4497: }
4498:
4499: public void commit() throws SQLException {
4500: checkExecuted();
4501: if (conn != null) {
4502: conn.commit();
4503: }
4504: }
4505:
4506: public void rollback() throws SQLException {
4507: checkExecuted();
4508: if (conn != null) {
4509: conn.rollback();
4510: }
4511: }
4512:
4513: public void rollback(Savepoint s) throws SQLException {
4514: checkExecuted();
4515: if (conn != null) {
4516: conn.rollback(s);
4517: }
4518: }
4519:
4520: public void unsetMatchColumn(int[] columnIdxes) throws SQLException {
4521:
4522: int i_val;
4523: for (int j = 0; j < columnIdxes.length; j++) {
4524: i_val = (Integer.parseInt(iMatchColumns.get(j).toString()));
4525: if (columnIdxes[j] != i_val) {
4526: throw new SQLException(rb
4527: .getString("MATCH_COLUMNS_NOT_THE_SAME")); //NOI18N
4528: }
4529: }
4530:
4531: for (int i = 0; i < columnIdxes.length; i++) {
4532: iMatchColumns.set(i, new Integer(-1));
4533: }
4534: }
4535:
4536: public void unsetMatchColumn(String[] columnIdxes)
4537: throws SQLException {
4538:
4539: for (int j = 0; j < columnIdxes.length; j++) {
4540: if (!columnIdxes[j].equals(strMatchColumns.get(j))) {
4541: throw new SQLException(rb
4542: .getString("MATCH_COLUMNS_NOT_THE_SAME")); //NOI18N
4543: }
4544: }
4545:
4546: for (int i = 0; i < columnIdxes.length; i++) {
4547: strMatchColumns.set(i, null);
4548: }
4549: }
4550:
4551: public String[] getMatchColumnNames() throws SQLException {
4552:
4553: String[] str_temp = new String[strMatchColumns.size()];
4554:
4555: if (strMatchColumns.get(0) == null) {
4556: throw new SQLException(rb
4557: .getString("SET_MATCH_COLUMNS_BEFORE_GETTING")); //NOI18N
4558: }
4559:
4560: strMatchColumns.copyInto(str_temp);
4561: return str_temp;
4562: }
4563:
4564: public int[] getMatchColumnIndexes() throws SQLException {
4565:
4566: Integer[] int_temp = new Integer[iMatchColumns.size()];
4567: int[] i_temp = new int[iMatchColumns.size()];
4568: int i_val;
4569:
4570: i_val = ((Integer) iMatchColumns.get(0)).intValue();
4571:
4572: if (i_val == -1) {
4573: throw new SQLException(rb
4574: .getString("SET_MATCH_COLUMNS_BEFORE_GETTING")); //NOI18N
4575: }
4576:
4577: iMatchColumns.copyInto(int_temp);
4578:
4579: for (int i = 0; i < int_temp.length; i++) {
4580: i_temp[i] = (int_temp[i]).intValue();
4581: }
4582:
4583: return i_temp;
4584: }
4585:
4586: public void setMatchColumn(int[] columnIdxes) throws SQLException {
4587:
4588: for (int j = 0; j < columnIdxes.length; j++) {
4589: if (columnIdxes[j] < 0) {
4590: throw new SQLException(rb
4591: .getString("MATCH_COL_MUST_BE_GT_0")); //NOI18N
4592: }
4593: }
4594: for (int i = 0; i < columnIdxes.length; i++) {
4595: iMatchColumns.add(i, new Integer(columnIdxes[i]));
4596: }
4597: }
4598:
4599: public void setMatchColumn(String[] columnNames)
4600: throws SQLException {
4601:
4602: for (int j = 0; j < columnNames.length; j++) {
4603: if (columnNames[j] == null || columnNames[j].equals("")) { //NOI18N
4604: throw new SQLException(rb
4605: .getString("MATCH_COL_CANNOT_BE_NULL_OR_EMPTY")); //NOI18N
4606: }
4607: }
4608: for (int i = 0; i < columnNames.length; i++) {
4609: strMatchColumns.add(i, columnNames[i]);
4610: }
4611: }
4612:
4613: public void setMatchColumn(int columnIdx) throws SQLException {
4614: // validate, if col is ok to be set
4615: if (columnIdx < 0) {
4616: throw new SQLException(rb
4617: .getString("COL_ID_HAS_TO_BE_GT_0")); //NOI18N
4618: } else {
4619: // set iMatchColumn
4620: iMatchColumns.set(0, new Integer(columnIdx));
4621: //strMatchColumn = null;
4622: }
4623: }
4624:
4625: public void setMatchColumn(String columnName) throws SQLException {
4626: // validate, if col is ok to be set
4627: columnName = columnName.trim();
4628: if (columnName == "" || columnName.equals(null)) { //NOI18N
4629: throw new SQLException(rb
4630: .getString("COL_ID_HAS_TO_BE_NON_NULL")); //NOI18N
4631: } else {
4632: // set strMatchColumn
4633: strMatchColumns.set(0, columnName);
4634: //iMatchColumn = -1;
4635: }
4636: }
4637:
4638: public void unsetMatchColumn(int columnIdx) throws SQLException {
4639: // check if we are unsetting the SAME column
4640: if (!iMatchColumns.get(0).equals(new Integer(columnIdx))) {
4641: throw new SQLException(rb
4642: .getString("COL_UNSET_NOT_SAME_AS_SET")); //NOI18N
4643: } else if (strMatchColumns.get(0) != null) {
4644: throw new SQLException(rb
4645: .getString("USE_COL_NAME_AS_ARG_TO_UNSETMATCHCOL")); //NOI18N
4646: } else {
4647: // that is, we are unsetting it.
4648: iMatchColumns.set(0, new Integer(-1));
4649: }
4650: }
4651:
4652: public void unsetMatchColumn(String columnName) throws SQLException {
4653: // check if we are unsetting the same column
4654: columnName = columnName.trim();
4655:
4656: if (!((strMatchColumns.get(0)).equals(columnName))) {
4657: throw new SQLException(rb
4658: .getString("COL_UNSET_NOT_SAME_AS_SET")); //NOI18N
4659: } else if (((Integer) (iMatchColumns.get(0))).intValue() > 0) {
4660: throw new SQLException(rb
4661: .getString("USE_COL_ID_AS_ARG_TO_UNSETMATCHCOL")); //NOI18N
4662: } else {
4663: strMatchColumns.set(0, null); // that is, we are unsetting it.
4664: }
4665: }
4666:
4667: public void rowSetPopulated(RowSetEvent event, int numRows)
4668: throws SQLException {
4669:
4670: if (numRows < 0 || numRows < getFetchSize()) {
4671: throw new SQLException(
4672: rb
4673: .getString("NUM_ROWS_CANNOT_BE_LT_0_OR_LT_FETCHSIZE")); // NOI18N
4674: }
4675:
4676: if (size() % numRows == 0) {
4677: RowSetEvent event_temp = new RowSetEvent(this );
4678: event = event_temp;
4679: notifyRowSetChanged();
4680: }
4681: }
4682:
4683: public void populate(ResultSet data, int start) throws SQLException {
4684:
4685: int rowsFetched;
4686: Row currentRow;
4687: int numCols;
4688: int i;
4689: Map map = getTypeMap();
4690: Object obj;
4691: int mRows;
4692:
4693: cursorPos = 0;
4694: if (populatecallcount == 0) {
4695: if (start < 0) {
4696: throw new SQLException(rb
4697: .getString("START_POS_CANNOT_BE_NEGATIVE")); //NOI18N
4698: }
4699: if (getMaxRows() == 0) {
4700: data.absolute(start);
4701: while (data.next()) {
4702: totalRows++;
4703: }
4704: totalRows++;
4705: }
4706: startPos = start;
4707: }
4708: populatecallcount = populatecallcount + 1;
4709: resultSet = data;
4710: if ((endPos - startPos) >= getMaxRows() && (getMaxRows() > 0)) {
4711: endPos = prevEndPos;
4712: pagenotend = false;
4713: return;
4714: }
4715:
4716: if ((maxRowsreached != getMaxRows() || maxRowsreached != totalRows)
4717: && pagenotend) {
4718: startPrev = start - getPageSize();
4719: }
4720:
4721: if (pageSize == 0) {
4722: prevEndPos = endPos;
4723: endPos = start + getMaxRows();
4724: } else {
4725: prevEndPos = endPos;
4726: endPos = start + getPageSize();
4727: }
4728:
4729: if (start == 1) {
4730: resultSet.beforeFirst();
4731: } else {
4732: resultSet.absolute(start - 1);
4733: }
4734: if (pageSize == 0) {
4735: rvh = new Vector(getMaxRows());
4736:
4737: } else {
4738: rvh = new Vector(getPageSize());
4739: }
4740:
4741: if (data == null) {
4742: throw new SQLException(rb
4743: .getString("INVALID_RESULTSET_SUPPLIED")); //NOI18N
4744: }
4745:
4746: // get the meta data for this ResultSet
4747: rsmd = data.getMetaData();
4748:
4749: // set up the metadata
4750: rowSetMD = new RowSetMetaDataXImpl();
4751: initMetaData(rowSetMD, rsmd);
4752:
4753: // release the meta-data so that aren't tempted to use it.
4754: rsmd = null;
4755: numCols = rowSetMD.getColumnCount();
4756: mRows = this .getMaxRows();
4757: rowsFetched = 0;
4758: currentRow = null;
4759:
4760: if (!data.next() && mRows == 0) {
4761: endPos = prevEndPos;
4762: pagenotend = false;
4763: return;
4764: }
4765:
4766: data.previous();
4767:
4768: while (data.next()) {
4769:
4770: currentRow = new Row(numCols);
4771: if (pageSize == 0) {
4772: if (rowsFetched >= mRows && mRows > 0) {
4773: rowsetWarning.setNextException(new SQLException(rb
4774: .getString("MAX_ROWS_EXCEEDED"))); //NOI18N
4775: break;
4776: }
4777: } else {
4778: if ((rowsFetched >= pageSize)
4779: || (maxRowsreached >= mRows && mRows > 0)) {
4780: rowsetWarning.setNextException(new SQLException(rb
4781: .getString("MAX_ROWS_EXCEEDED"))); //NOI18N
4782: break;
4783: }
4784: }
4785:
4786: for (i = 1; i <= numCols; i++) {
4787: /*
4788: * check if the user has set a map. If no map
4789: * is set then use plain getObject. This lets
4790: * us work with drivers that do not support
4791: * getObject with a map in fairly sensible way
4792: */
4793: if (map == null) {
4794: obj = data.getObject(i);
4795: } else {
4796: obj = data.getObject(i, map);
4797: }
4798: /*
4799: * the following block checks for the various
4800: * types that we have to serialize in order to
4801: * store - right now only structs have been tested
4802: */
4803: if (obj instanceof Struct) {
4804: obj = new SerialStruct((Struct) obj, map);
4805: } else if (obj instanceof SQLData) {
4806: obj = new SerialStruct((SQLData) obj, map);
4807: } else if (obj instanceof Blob) {
4808: obj = new SerialBlob((Blob) obj);
4809: } else if (obj instanceof Clob) {
4810: obj = new SerialClob((Clob) obj);
4811: } else if (obj instanceof java.sql.Array) {
4812: obj = new SerialArray((java.sql.Array) obj, map);
4813: }
4814:
4815: ((Row) currentRow).initColumnObject(i, obj);
4816: }
4817: rowsFetched++;
4818: maxRowsreached++;
4819: rvh.add(currentRow);
4820: }
4821: numRows = rowsFetched;
4822: executed = true;
4823: // Also rowsFetched should be equal to rvh.size()
4824: // notify any listeners that the rowset has changed
4825: notifyRowSetChanged();
4826:
4827: }
4828:
4829: public boolean nextPage() throws SQLException {
4830: // checkExecuted(); //!JK: ??
4831:
4832: if (populatecallcount == 0) {
4833: throw new SQLException(rb
4834: .getString("INVALID_OP_ROWSET_NOT_POPULATED")); //NOI18N
4835: }
4836: if (populatecallcount == 1) {
4837: populatecallcount++;
4838: return pagenotend;
4839: } else {
4840: onFirstPage = false;
4841: if (callWithCon) {
4842: crsReader.setStartPosition(endPos);
4843: crsReader.readData((RowSetInternal) this );
4844: resultSet = null;
4845: } else {
4846: populate(resultSet, endPos);
4847: }
4848: return pagenotend;
4849: }
4850: }
4851:
4852: public void setPageSize(int size) throws SQLException {
4853: if (size < 0) {
4854: throw new SQLException(rb
4855: .getString("PAGESIZE_MUST_BE_GE_0")); //NOI18N
4856: }
4857: if (size > getMaxRows() && getMaxRows() != 0) {
4858: throw new SQLException(rb
4859: .getString("PAGESIZE_MUST_BE_LE_MAXROWS")); //NOI18N
4860: }
4861: pageSize = size;
4862: }
4863:
4864: public int getPageSize() {
4865: return pageSize;
4866: }
4867:
4868: public boolean previousPage() throws SQLException {
4869: // checkExecuted(); //!JK: ??
4870: int pS;
4871: int mR;
4872: int rem;
4873:
4874: pS = getPageSize();
4875: mR = maxRowsreached;
4876:
4877: if (populatecallcount == 0) {
4878: throw new SQLException(rb
4879: .getString("INVALID_OP_ROWSET_NOT_POPULATED")); //NOI18N
4880: }
4881:
4882: if (!callWithCon) {
4883: if (resultSet.getType() == ResultSet.TYPE_FORWARD_ONLY) {
4884: throw new SQLException(rb
4885: .getString("RESULTSET_TYPE_FORWARD_ONLY")); //NOI18N
4886: }
4887: }
4888:
4889: pagenotend = true;
4890:
4891: if (startPrev < startPos) {
4892: onFirstPage = true;
4893: return false;
4894: }
4895:
4896: if (onFirstPage) {
4897: return false;
4898: }
4899:
4900: rem = mR % pS;
4901:
4902: if (rem == 0) {
4903: maxRowsreached -= (2 * pS);
4904: if (callWithCon) {
4905: crsReader.setStartPosition(startPrev);
4906: crsReader.readData((RowSetInternal) this );
4907: resultSet = null;
4908: } else {
4909: populate(resultSet, startPrev);
4910: }
4911: return true;
4912: } else {
4913: maxRowsreached -= (pS + rem);
4914: if (callWithCon) {
4915: crsReader.setStartPosition(startPrev);
4916: crsReader.readData((RowSetInternal) this );
4917: resultSet = null;
4918: } else {
4919: populate(resultSet, startPrev);
4920: }
4921: return true;
4922: }
4923: }
4924:
4925: private String catalogName = null;
4926:
4927: /**
4928: * {@inheritDoc}
4929: */
4930: public String getCatalogName() {
4931: return catalogName;
4932: }
4933:
4934: /**
4935: * {@inheritDoc}
4936: */
4937: public void setCatalogName(String catalogName) {
4938: this .catalogName = catalogName;
4939: }
4940:
4941: private String schemaName = null;
4942:
4943: /**
4944: * {@inheritDoc}
4945: */
4946: public String getSchemaName() {
4947: return schemaName;
4948: }
4949:
4950: /**
4951: * {@inheritDoc}
4952: */
4953: public void setSchemaName(String schemaName) {
4954: this .schemaName = schemaName;
4955: }
4956:
4957: private String[] columnCatalogNames = null;
4958:
4959: /**
4960: * {@inheritDoc}
4961: */
4962: public String[] getColumnCatalogNames() {
4963: return columnCatalogNames;
4964: }
4965:
4966: /**
4967: * {@inheritDoc}
4968: */
4969: public String getColumnCatalogNames(int index) {
4970: return columnCatalogNames[index];
4971: }
4972:
4973: /**
4974: * {@inheritDoc}
4975: */
4976: public void setColumnCatalogNames(String[] columnCatalogNames) {
4977: this .columnCatalogNames = columnCatalogNames;
4978: }
4979:
4980: /**
4981: * {@inheritDoc}
4982: */
4983: public void setColumnCatalogNames(int index,
4984: String columnCatalogName) {
4985: this .columnCatalogNames[index] = columnCatalogName;
4986: }
4987:
4988: private String[] columnSchemaNames = null;
4989:
4990: /**
4991: * {@inheritDoc}
4992: */
4993: public String[] getColumnSchemaNames() {
4994: return columnSchemaNames;
4995: }
4996:
4997: /**
4998: * {@inheritDoc}
4999: */
5000: public String getColumnSchemaNames(int index) {
5001: return columnSchemaNames[index];
5002: }
5003:
5004: /**
5005: * {@inheritDoc}
5006: */
5007: public void setColumnSchemaNames(String[] columnSchemaNames) {
5008: this .columnSchemaNames = columnSchemaNames;
5009: }
5010:
5011: /**
5012: * {@inheritDoc}
5013: */
5014: public void setColumnSchemaNames(int index, String columnSchemaName) {
5015: this .columnSchemaNames[index] = columnSchemaName;
5016: }
5017:
5018: private String[] columnTableNames = null;
5019:
5020: /**
5021: * {@inheritDoc}
5022: */
5023: public String[] getColumnTableNames() {
5024: return columnTableNames;
5025: }
5026:
5027: /**
5028: * {@inheritDoc}
5029: */
5030: public String getColumnTableNames(int index) {
5031: return columnTableNames[index];
5032: }
5033:
5034: /**
5035: * {@inheritDoc}
5036: */
5037: public void setColumnTableNames(String[] columnTableNames) {
5038: this .columnTableNames = columnTableNames;
5039: }
5040:
5041: /**
5042: * {@inheritDoc}
5043: */
5044: public void setColumnTableNames(int index, String columnTableName) {
5045: this .columnTableNames[index] = columnTableName;
5046: }
5047:
5048: private String[] columnNames = null;
5049:
5050: /**
5051: * {@inheritDoc}
5052: */
5053: public String[] getColumnNames() {
5054: return columnNames;
5055: }
5056:
5057: /**
5058: * {@inheritDoc}
5059: */
5060: public String getColumnNames(int index) {
5061: return columnNames[index];
5062: }
5063:
5064: /**
5065: * {@inheritDoc}
5066: */
5067: public void setColumnNames(String[] columnNames) {
5068: this .columnNames = columnNames;
5069: }
5070:
5071: /**
5072: * {@inheritDoc}
5073: */
5074: public void setColumnNames(int index, String columnName) {
5075: this .columnNames[index] = columnName;
5076: }
5077:
5078: private boolean[] insertableColumns = null;
5079:
5080: /**
5081: * {@inheritDoc}
5082: */
5083: public boolean[] getInsertableColumns() {
5084: return insertableColumns;
5085: }
5086:
5087: /**
5088: * {@inheritDoc}
5089: */
5090: public boolean getInsertableColumns(int index) {
5091: return insertableColumns[index];
5092: }
5093:
5094: /**
5095: * {@inheritDoc}
5096: */
5097: public void setInsertableColumns(boolean[] insertableColumns) {
5098: this .insertableColumns = insertableColumns;
5099: }
5100:
5101: /**
5102: * {@inheritDoc}
5103: */
5104: public void setInsertableColumns(int index, boolean insertableColumn) {
5105: this .insertableColumns[index] = insertableColumn;
5106: }
5107:
5108: private boolean[] updatableColumns = null;
5109:
5110: /**
5111: * {@inheritDoc}
5112: */
5113: public boolean[] getUpdatableColumns() {
5114: return updatableColumns;
5115: }
5116:
5117: /**
5118: * {@inheritDoc}
5119: */
5120: public boolean getUpdatableColumns(int index) {
5121: return updatableColumns[index];
5122: }
5123:
5124: /**
5125: * {@inheritDoc}
5126: */
5127: public void setUpdatableColumns(boolean[] updatableColumns) {
5128: this .updatableColumns = updatableColumns;
5129: }
5130:
5131: /**
5132: * {@inheritDoc}
5133: */
5134: public void setUpdatableColumns(int index, boolean updatableColumn) {
5135: this .updatableColumns[index] = updatableColumn;
5136: }
5137:
5138: private boolean printStatements;
5139:
5140: /**
5141: * {@inheritDoc}
5142: */
5143: public boolean getPrintStatements() {
5144: return printStatements;
5145: }
5146:
5147: /**
5148: * {@inheritDoc}
5149: */
5150: public void setPrintStatements(boolean printStatements) {
5151: this .printStatements = printStatements;
5152: }
5153:
5154: } //end class
|