0001: /**
0002: * Sequoia: Database clustering technology.
0003: * Copyright (C) 2002-2004 French National Institute For Research In Computer
0004: * Science And Control (INRIA).
0005: * Copyright (C) 2005 AmicoSoft, Inc. dba Emic Networks
0006: * Contact: sequoia@continuent.org
0007: *
0008: * Licensed under the Apache License, Version 2.0 (the "License");
0009: * you may not use this file except in compliance with the License.
0010: * You may obtain a copy of the License at
0011: *
0012: * http://www.apache.org/licenses/LICENSE-2.0
0013: *
0014: * Unless required by applicable law or agreed to in writing, software
0015: * distributed under the License is distributed on an "AS IS" BASIS,
0016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: * See the License for the specific language governing permissions and
0018: * limitations under the License.
0019: *
0020: * Initial developer(s): Mark Matthews.
0021: * Contributor(s): Emmanuel Cecchet, Andre Austin, Marc Wick, Jean-Bernard
0022: * van Zuylen, Marc Herbert, Edward Archibald, Stephane Giron.
0023: */package org.continuent.sequoia.driver;
0024:
0025: import java.io.ByteArrayInputStream;
0026: import java.io.IOException;
0027: import java.io.InputStream;
0028: import java.io.UnsupportedEncodingException;
0029: import java.math.BigDecimal;
0030: import java.math.BigInteger;
0031: import java.net.URL;
0032: import java.nio.CharBuffer;
0033: import java.nio.charset.CharacterCodingException;
0034: import java.nio.charset.Charset;
0035: import java.sql.Clob;
0036: import java.sql.PreparedStatement;
0037: import java.sql.Ref;
0038: import java.sql.ResultSet;
0039: import java.sql.SQLException;
0040: import java.sql.SQLWarning;
0041: import java.sql.Time;
0042: import java.sql.Timestamp;
0043: import java.util.ArrayList;
0044: import java.util.Calendar;
0045: import java.util.Hashtable;
0046:
0047: import org.continuent.sequoia.common.exceptions.NotImplementedException;
0048: import org.continuent.sequoia.common.exceptions.ProtocolException;
0049: import org.continuent.sequoia.common.exceptions.driver.DriverSQLException;
0050: import org.continuent.sequoia.common.exceptions.driver.protocol.BackendDriverException;
0051: import org.continuent.sequoia.common.protocol.ByteArrayBlob;
0052: import org.continuent.sequoia.common.protocol.Field;
0053: import org.continuent.sequoia.common.protocol.SQLDataSerialization;
0054: import org.continuent.sequoia.common.protocol.StringClob;
0055: import org.continuent.sequoia.common.protocol.TypeTag;
0056: import org.continuent.sequoia.common.stream.DriverBufferedInputStream;
0057:
0058: /**
0059: * A <code>ResultSet</code> provides access to a table of data generated by
0060: * executing a Statement. The table rows are retrieved in sequence. Within a row
0061: * its column values can be accessed in any order.
0062: * <p>
0063: * A <code>ResultSet</code> maintains a cursor pointing to its current row of
0064: * data. Initially the cursor is positioned before the first row. The 'next'
0065: * method moves the cursor to the next row.
0066: * <p>
0067: * The <code>getXXX</code> methods retrieve column values for the current row.
0068: * You can retrieve values either using the index number of the column, or by
0069: * using the name of the column. In general using the column index will be more
0070: * efficient. Columns are numbered from 1.
0071: * <p>
0072: * For maximum portability, <code>ResultSet</code> columns within each row
0073: * should be read in left-to-right order and each column should be read only
0074: * once.
0075: * <p>
0076: * For the <code>getXXX</code> methods, the JDBC driver attempts to convert
0077: * the underlying data to the specified Java type and returns a suitable Java
0078: * value. See the JDBC specification for allowable mappings from SQL types to
0079: * Java types with the <code>ResultSet</code> <code>getXXX</code> methods.
0080: * <p>
0081: * Column names used as input to <code>getXXX</code> methods are case
0082: * insenstive. When performing a <code>getXXX</code> using a column name, if
0083: * several columns have the same name, then the value of the first matching
0084: * column will be returned. The column name option is designed to be used when
0085: * column names are used in the SQL Query. For columns that are NOT explicitly
0086: * named in the query, it is best to use column numbers. If column names were
0087: * used there is no way for the programmer to guarentee that they actually refer
0088: * to the intended columns.
0089: * <P>
0090: * A <code>ResultSet</code> is automatically closed by the
0091: * <code>Statement</code> that generated it when that <code>Statement</code>
0092: * is closed, re-executed, or is used to retrieve the next result from a
0093: * sequence of multiple results.
0094: * <P>
0095: * The number, types and properties of a ResultSet's columns are provided by the
0096: * <code>ResultSetMetaData</code> object returned by the
0097: * <code>getMetaData</code> method.
0098: *
0099: * @see java.sql.ResultSetMetaData
0100: * @see java.sql.ResultSet
0101: * @author Mark Matthews <mmatthew@worldserver.com>
0102: * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
0103: * @author <a href="mailto:alexander.laamanen@tecnomen.com">Alexander Laamanen
0104: * </a>
0105: * @author <a href="mailto:Nicolas.Modrzyk@inrialpes.fr">Nicolas Modrzyk </a>
0106: * @author <a href="mailto:jbvanzuylen@transwide.com">Jean-Bernard van Zuylen
0107: * </a>
0108: * @author <a href="mailto:Marc.Herbert@emicnetworks.com">Marc Herbert </a>
0109: * @author <a href="mailto:ed.archibald@continuent.com">Edward Archibald</a>
0110: * @author <a href="mailto:stephane.giron@continuent.com">Stephane Giron</a>
0111: * @version 1.0
0112: */
0113: public class DriverResultSet implements java.sql.ResultSet,
0114: java.io.Serializable, java.lang.Cloneable {
0115: private static final long serialVersionUID = 7408879935608629886L;
0116:
0117: /** Cursor to current row */
0118: protected int currentRow = -1;
0119: /** Number of rows */
0120: protected int nbOfRows = -1;
0121: /** Number of columns */
0122: protected int nbOfColumns = -1;
0123: /** The results */
0124: protected ArrayList data;
0125: /** True if there is more data to fetch from the controller */
0126: private boolean hasMoreData;
0127: /** The fetch direction (not used yet) */
0128: protected int fetchDirection = FETCH_FORWARD;
0129: /** The fetch size */
0130: protected int fetchSize = 0;
0131: /** ResultSet cursor name */
0132: private String cursorName;
0133:
0134: /** The fields */
0135: protected Field[] fields;
0136:
0137: /** Pointers to column-specific de/serializer */
0138: private SQLDataSerialization.Serializer[] serializers;
0139:
0140: /** for wasNull() */
0141: protected boolean wasNullFlag = false;
0142: /** column name -> index in ResultSet data array */
0143: protected transient Hashtable lowerNameToIndex = null;
0144: /** case sensitive column name -> index in ResultSet data array */
0145: protected transient Hashtable sensitiveNameToIndex = null;
0146:
0147: /** Type of ResultSet */
0148: protected int resultSetType = 0;
0149: /** Concurrency for this ResultSet */
0150: protected int resultSetConcurrency = 0;
0151: /** the warning chain */
0152: protected BackendDriverException warnings = null;
0153: /** warnings associated to the statement that created us */
0154: protected SQLWarning statementWarnings = null;
0155: /** Statement corresponding to this ResultSet, if any (not for metadata) */
0156: protected transient Statement owningStatement;
0157: /** The driver connection we were received from. Useful for streaming */
0158: private final Connection connection;
0159:
0160: private boolean isClosed = true;
0161:
0162: /** Statement for deleting rows with Updatable ResultSets * */
0163: private transient PreparedStatement deleteStatement = null;
0164: /** Statement for inserting rows with Updatable ResultSets * */
0165: private transient PreparedStatement insertStatement = null;
0166: /** Statement for refreshing rows with Updatable ResultSets * */
0167: private transient PreparedStatement refreshStatement = null;
0168: /** Statement for updating rows with Updatable ResultSets * */
0169: private transient PreparedStatement updateStatement = null;
0170: /** Indicates whether cursor is on the insert row * */
0171: private transient boolean inserting = false;
0172: /** Indicates if the current row is being updated * */
0173: private transient boolean updating = false;
0174: /** Temporary object for not yet comitted ResultSet updates * */
0175: private transient Object[] tempRow = null;
0176: /** Cache the columns forming the primary key * */
0177: private transient String[] primaryKeyColumns = null;
0178:
0179: private static final String UPDATEABLE_MESSAGE = "ResultSet not updateable. The "
0180: + "query that generated this result set must select only one table, and must "
0181: + "select all primary keys from that table. See the JDBC 2.1 API Specification, "
0182: + "section 5.6 for more details.";
0183: /**
0184: * Hold a reference to the returned stream so we can close it as soon as the
0185: * application is no more allowed to use it (per the JDBC spec).
0186: */
0187: private InputStream currentStream = null;
0188:
0189: // ---------------------------------------------------------------------
0190: // Traversal/Positioning
0191: // ---------------------------------------------------------------------
0192:
0193: /**
0194: * A ResultSet is initially positioned before its first row, the first call to
0195: * next makes the first row the current row; the second call makes the second
0196: * row the current row, etc.
0197: * <p>
0198: * If an input stream from the previous row is open, it is implicitly closed.
0199: * The ResultSet's warning chain is cleared when a new row is read
0200: *
0201: * @return <code>true</code> if the new current is valid; <code>false</code>
0202: * if there are no more rows
0203: * @exception java.sql.SQLException if a database access error occurs
0204: */
0205: public boolean next() throws java.sql.SQLException {
0206: checkIfClosed();
0207:
0208: if (inserting) {
0209: insertStatement.clearParameters();
0210: tempRow = null;
0211: inserting = false;
0212: }
0213:
0214: if (updating)
0215: cancelRowUpdates();
0216:
0217: if (nbOfRows == 0)
0218: return false;
0219:
0220: if (currentRow + 1 >= nbOfRows) {
0221: if (hasMoreData) {
0222: // TODO: what happens if user closed this connection? What says JDBC?
0223: this .connection.tryFetchNext(cursorName, fetchSize);
0224: // no SQLException from controller, so let's receive our new rows
0225: try {
0226: receiveRows();
0227: } catch (IOException ioe) {
0228: throw new DriverSQLException(
0229: "I/O Error while fetching new rows:\n"
0230: + ioe.getLocalizedMessage(), ioe);
0231: }
0232: currentRow = 0;
0233: if (data == null) {
0234: nbOfRows = 0;
0235: return false;
0236: } else {
0237: nbOfRows = data.size();
0238: return true;
0239: }
0240: }
0241:
0242: // force scroll past end
0243: currentRow = nbOfRows;
0244: return false;
0245: }
0246:
0247: clearWarnings();
0248: currentRow++;
0249: return true;
0250: }
0251:
0252: /**
0253: * The prev method is not part of JDBC, but because of the architecture of
0254: * this driver it is possible to move both forward and backward within the
0255: * result set.
0256: * <p>
0257: * If an input stream from the previous row is open, it is implicitly closed.
0258: * The ResultSet's warning chain is cleared when a new row is read
0259: *
0260: * @return <code>true</code> if the new current is valid; <code>false</code>
0261: * if there are no more rows
0262: * @exception SQLException if a database access error occurs
0263: */
0264: public boolean prev() throws SQLException {
0265: checkIfClosed();
0266:
0267: if (inserting) {
0268: insertStatement.clearParameters();
0269: tempRow = null;
0270: inserting = false;
0271: }
0272:
0273: if (updating)
0274: cancelRowUpdates();
0275:
0276: if (currentRow - 1 >= 0) {
0277: currentRow--;
0278: return true;
0279: }
0280:
0281: return false;
0282: }
0283:
0284: /**
0285: * JDBC 2.0.
0286: * <p>
0287: * Determine if the cursor is before the first row in the result set.
0288: *
0289: * @return <code>true</code> if before the first row, <code>false</code>
0290: * otherwise. Returns <code>false</code> when the result set
0291: * contains no rows.
0292: * @exception SQLException if a database-access error occurs.
0293: */
0294: public boolean isBeforeFirst() throws SQLException {
0295: checkIfClosed();
0296: if (nbOfRows == 0)
0297: return false;
0298: else
0299: return (currentRow == -1);
0300: }
0301:
0302: /**
0303: * JDBC 2.0
0304: * <p>
0305: * Determine if the cursor is after the last row in the result set.
0306: *
0307: * @return <code>true</code> if after the last row, <code>false</code>
0308: * otherwise. Returns <code>false</code> when the result set
0309: * contains no rows.
0310: * @exception SQLException if a database-access error occurs.
0311: */
0312: public boolean isAfterLast() throws SQLException {
0313: checkIfClosed();
0314: if (nbOfRows == 0)
0315: return false;
0316: else
0317: return (currentRow >= nbOfRows);
0318: }
0319:
0320: /**
0321: * JDBC 2.0
0322: * <p>
0323: * Determine if the cursor is on the first row of the result set.
0324: *
0325: * @return <code>true</code> if on the first row, <code>false</code>
0326: * otherwise.
0327: * @exception SQLException if a database-access error occurs.
0328: */
0329: public boolean isFirst() throws SQLException {
0330: checkIfClosed();
0331: if (nbOfRows == 0)
0332: return false;
0333: else
0334: return (currentRow == 0);
0335: }
0336:
0337: /**
0338: * JDBC 2.0
0339: * <p>
0340: * Determine if the cursor is on the last row of the result set. Note: Calling
0341: * isLast() may be expensive since the JDBC driver might need to fetch ahead
0342: * one row in order to determine whether the current row is the last row in
0343: * the result set.
0344: *
0345: * @return <code>true</code> if on the last row, <code>false</code>
0346: * otherwise.
0347: * @exception SQLException if a database-access error occurs.
0348: */
0349: public boolean isLast() throws SQLException {
0350: checkIfClosed();
0351: if (nbOfRows == 0)
0352: return false;
0353: else
0354: return (currentRow == nbOfRows - 1);
0355: }
0356:
0357: /**
0358: * JDBC 2.0
0359: * <p>
0360: * Moves to the front of the result set, just before the first row. Has no
0361: * effect if the result set contains no rows.
0362: *
0363: * @exception SQLException if a database-access error occurs, or result set
0364: * type is TYPE_FORWARD_ONLY
0365: */
0366: public void beforeFirst() throws SQLException {
0367: checkIfScrollable();
0368:
0369: if (inserting) {
0370: insertStatement.clearParameters();
0371: tempRow = null;
0372: inserting = false;
0373: }
0374:
0375: if (updating)
0376: cancelRowUpdates();
0377:
0378: currentRow = -1;
0379: }
0380:
0381: /**
0382: * JDBC 2.0
0383: * <p>
0384: * Moves to the end of the result set, just after the last row. Has no effect
0385: * if the result set contains no rows.
0386: *
0387: * @exception SQLException if a database-access error occurs, or result set
0388: * type is TYPE_FORWARD_ONLY.
0389: */
0390: public void afterLast() throws SQLException {
0391: checkIfScrollable();
0392:
0393: if (inserting) {
0394: insertStatement.clearParameters();
0395: tempRow = null;
0396: inserting = false;
0397: }
0398:
0399: if (updating)
0400: cancelRowUpdates();
0401:
0402: if (nbOfRows != 0)
0403: currentRow = nbOfRows;
0404: }
0405:
0406: /**
0407: * JDBC 2.0
0408: * <p>
0409: * Moves to the first row in the result set.
0410: *
0411: * @return <code>true</code> if on a valid row, false if no rows in the
0412: * result set.
0413: * @exception SQLException if a database-access error occurs, or result set
0414: * type is TYPE_FORWARD_ONLY.
0415: */
0416: public boolean first() throws SQLException {
0417: checkIfScrollable();
0418:
0419: if (inserting) {
0420: insertStatement.clearParameters();
0421: tempRow = null;
0422: inserting = false;
0423: }
0424:
0425: if (updating)
0426: cancelRowUpdates();
0427:
0428: if (nbOfRows == 0)
0429: return false;
0430:
0431: currentRow = 0;
0432: return true;
0433: }
0434:
0435: /**
0436: * JDBC 2.0
0437: * <p>
0438: * Moves to the last row in the result set.
0439: *
0440: * @return <code>true</code> if on a valid row, false if no rows in the
0441: * result set.
0442: * @exception SQLException if a database-access error occurs, or result set
0443: * type is TYPE_FORWARD_ONLY.
0444: */
0445: public boolean last() throws SQLException {
0446: checkIfScrollable();
0447:
0448: if (inserting) {
0449: insertStatement.clearParameters();
0450: tempRow = null;
0451: inserting = false;
0452: }
0453:
0454: if (updating)
0455: cancelRowUpdates();
0456:
0457: if (nbOfRows == 0)
0458: return false;
0459:
0460: currentRow = nbOfRows - 1;
0461: return true;
0462: }
0463:
0464: /**
0465: * JDBC 2.0
0466: * <p>
0467: * Determine the current row number. The first row is number 1, the second
0468: * number 2, etc.
0469: *
0470: * @return the current row number, else return 0 if there is no current row
0471: * @exception SQLException if a database-access error occurs.
0472: */
0473: public int getRow() throws SQLException {
0474: checkIfClosed();
0475: if (currentRow < 0 || currentRow >= nbOfRows || nbOfRows == 0)
0476: return 0;
0477: else
0478: return currentRow + 1;
0479: }
0480:
0481: /**
0482: * JDBC 2.0
0483: * <p>
0484: * Move to an absolute row number in the result set.
0485: * <p>
0486: * If row is positive, moves to an absolute row with respect to the beginning
0487: * of the result set. The first row is row 1, the second is row 2, etc.
0488: * <p>
0489: * If row is negative, moves to an absolute row position with respect to the
0490: * end of result set. For example, calling absolute(-1) positions the cursor
0491: * on the last row, absolute(-2) indicates the next-to-last row, etc.
0492: * <p>
0493: * An attempt to position the cursor beyond the first/last row in the result
0494: * set, leaves the cursor before/after the first/last row, respectively.
0495: * <p>
0496: * Note: Calling absolute(1) is the same as calling first(). Calling
0497: * absolute(-1) is the same as calling last().
0498: *
0499: * @param row the row to move to
0500: * @return <code>true</code> if on the result set, false if off.
0501: * @exception SQLException if a database-access error occurs, or row is 0, or
0502: * result set type is TYPE_FORWARD_ONLY.
0503: */
0504: public boolean absolute(int row) throws SQLException {
0505: checkIfScrollable();
0506:
0507: if (inserting) {
0508: insertStatement.clearParameters();
0509: tempRow = null;
0510: inserting = false;
0511: }
0512:
0513: if (updating)
0514: cancelRowUpdates();
0515:
0516: if (nbOfRows == 0)
0517: return false;
0518:
0519: if (row == 0) {
0520: beforeFirst();
0521: return false;
0522: }
0523:
0524: if (row == 1)
0525: return first();
0526:
0527: if (row == -1)
0528: return last();
0529:
0530: if (row > nbOfRows) {
0531: afterLast();
0532: return false;
0533: }
0534:
0535: if (row < 0) { // adjust to reflect after end of result set
0536: int newRowPosition = nbOfRows + row + 1;
0537:
0538: if (newRowPosition <= 0) {
0539: beforeFirst();
0540: return false;
0541: }
0542:
0543: return absolute(newRowPosition);
0544: } else {
0545: row--; // adjust for index difference
0546: currentRow = row;
0547: return true;
0548: }
0549: }
0550:
0551: /**
0552: * JDBC 2.0
0553: * <p>
0554: * Moves a relative number of rows, either positive or negative. Attempting to
0555: * move beyond the first/last row in the result set positions the cursor
0556: * before/after the the first/last row. Calling relative(0) is valid, but does
0557: * not change the cursor position.
0558: * <p>
0559: * Note: Calling relative(1) is different than calling next() since is makes
0560: * sense to call next() when there is no current row, for example, when the
0561: * cursor is positioned before the first row or after the last row of the
0562: * result set.
0563: *
0564: * @param rows the number of rows
0565: * @return <code>true</code> if on a row, false otherwise.
0566: * @exception SQLException if a database-access error occurs, or there is no
0567: * current row, or result set type is TYPE_FORWARD_ONLY.
0568: */
0569: public boolean relative(int rows) throws SQLException {
0570: checkIfScrollable();
0571:
0572: if (inserting) {
0573: insertStatement.clearParameters();
0574: tempRow = null;
0575: inserting = false;
0576: }
0577:
0578: if (updating)
0579: cancelRowUpdates();
0580:
0581: if (nbOfRows == 0)
0582: return false;
0583:
0584: return absolute(currentRow + rows + 1);
0585: }
0586:
0587: /**
0588: * JDBC 2.0
0589: * <p>
0590: * Moves to the previous row in the result set.
0591: * <p>
0592: * Note: previous() is not the same as relative(-1) since it makes sense to
0593: * call previous() when there is no current row.
0594: *
0595: * @return <code>true</code> if on a valid row, false if off the result set.
0596: * @exception SQLException if a database-access error occurs, or result set
0597: * type is TYPE_FORWAR_DONLY.
0598: */
0599: public boolean previous() throws SQLException {
0600: checkIfScrollable();
0601: return prev();
0602: }
0603:
0604: /**
0605: * JDBC 2.0 Give a hint as to the direction in which the rows in this result
0606: * set will be processed. The initial value is determined by the statement
0607: * that produced the result set. The fetch direction may be changed at any
0608: * time.
0609: *
0610: * @param direction the fetch direction
0611: * @exception SQLException if a database-access error occurs, or the result
0612: * set type is TYPE_FORWARD_ONLY and direction is not
0613: * FETCH_FORWARD. MM.MySQL actually ignores this, because it has
0614: * the whole result set anyway, so the direction is immaterial.
0615: */
0616: public void setFetchDirection(int direction) throws SQLException {
0617: if (direction != FETCH_FORWARD && direction != FETCH_REVERSE)
0618: throw new SQLException("Illegal value for fetch direction");
0619:
0620: if (resultSetType == ResultSet.TYPE_FORWARD_ONLY
0621: && direction != FETCH_FORWARD)
0622: throw new SQLException(
0623: "Operation requires a scrollable ResultSet, but this ResultSet is FORWARD_ONLY");
0624:
0625: fetchDirection = direction;
0626: }
0627:
0628: /**
0629: * JDBC 2.0 Return the fetch direction for this result set.
0630: *
0631: * @return the fetch direction
0632: * @exception SQLException if a database-access error occurs
0633: */
0634: public int getFetchDirection() throws SQLException {
0635: return fetchDirection;
0636: }
0637:
0638: /**
0639: * See performance issue explained in
0640: * {@link org.continuent.sequoia.controller.virtualdatabase.VirtualDatabaseWorkerThread#fetchNextResultSetRows()}
0641: *
0642: * @param rows the number of rows to fetch
0643: * @exception SQLException if a database-access error occurs, or the condition
0644: * 0 <= rows <= statement.getMaxRows() is not satisfied.
0645: * Currently ignored by this driver.
0646: * @see ResultSet#setFetchSize(int)
0647: */
0648: public void setFetchSize(int rows) throws SQLException {
0649: // This is just a hint afterall, let's not try to throw exceptions for
0650: // nothing
0651: if (rows < 0)
0652: throw new SQLException(
0653: "Value must be between 0 and getMaxRows()");
0654:
0655: fetchSize = rows;
0656: }
0657:
0658: /**
0659: * JDBC 2.0 Return the fetch size for this result set.
0660: *
0661: * @return the fetch size
0662: * @exception SQLException if a database-access error occurs
0663: */
0664: public int getFetchSize() throws SQLException {
0665: return fetchSize;
0666: }
0667:
0668: //
0669: // ---------------------------------------------------------------------
0670: // Getter's and Setter's
0671: // ---------------------------------------------------------------------
0672: //
0673:
0674: /**
0675: * Get the value of a column in the current row as a Java String
0676: *
0677: * @param columnIndex the first column is 1, the second is 2...
0678: * @return the column value, null for SQL NULL
0679: * @exception SQLException if a database access error occurs
0680: */
0681: public String getString(int columnIndex) throws SQLException {
0682: checkRowAndColPosAndSetNullFlag(columnIndex);
0683:
0684: if (wasNullFlag)
0685: return null;
0686:
0687: if (inserting || updating)
0688: return tempRow[columnIndex - 1].toString();
0689: else {
0690: Object tmpData = (((Object[]) data.get(currentRow))[columnIndex - 1]);
0691: if (tmpData instanceof byte[]) {
0692: String encoding = this .fields[columnIndex - 1]
0693: .getEncoding();
0694: if (encoding != null)
0695: try {
0696: return new String((byte[]) tmpData, encoding);
0697: } catch (UnsupportedEncodingException e) {
0698: throw (SQLException) new SQLException(
0699: "UnsupportedEncodingException (to "
0700: + encoding + ") : "
0701: + e.getMessage()).initCause(e);
0702: }
0703: else
0704: return new String((byte[]) tmpData);
0705: }
0706: return tmpData.toString();
0707: }
0708: }
0709:
0710: /**
0711: * Get the value of a column in the current row as a Java boolean
0712: *
0713: * @param columnIndex the first column is 1, the second is 2...
0714: * @return the column value, false for SQL NULL
0715: * @exception SQLException if a database access error occurs
0716: */
0717: public boolean getBoolean(int columnIndex) throws SQLException {
0718: checkRowAndColPosAndSetNullFlag(columnIndex);
0719:
0720: if (wasNullFlag)
0721: return false;
0722:
0723: Object object;
0724: if (inserting || updating)
0725: object = tempRow[columnIndex - 1];
0726: else
0727: object = (((Object[]) data.get(currentRow))[columnIndex - 1]);
0728:
0729: String stringVal = object.toString();
0730: if ((stringVal != null) && (stringVal.length() > 0)) {
0731: stringVal = stringVal.toLowerCase();
0732:
0733: if ("t".equals(stringVal)) {
0734: return true;
0735: } else if ("f".equals(stringVal)) {
0736: return false;
0737: } else if ("true".equals(stringVal)) {
0738: return true;
0739: } else if ("false".equals(stringVal)) {
0740: return false;
0741: } else if ("1".equals(stringVal)) {
0742: return true;
0743: } else if ("0".equals(stringVal)) {
0744: return false;
0745: } else if ("y".equals(stringVal)) {
0746: return true;
0747: } else if ("n".equals(stringVal)) {
0748: return false;
0749: } else if ("yes".equals(stringVal)) {
0750: return true;
0751: } else if ("no".equals(stringVal)) {
0752: return false;
0753: } else if (object instanceof Number) {
0754: int value = ((Number) object).intValue();
0755: if (value == 0)
0756: return false;
0757: else if (value == 1)
0758: return true;
0759: // else other value throw an exception
0760: }
0761:
0762: // we didn't find anything reasonable and throw an exception
0763: throw new SQLException("column value " + stringVal
0764: + " of type: " + object.getClass()
0765: + " could not be converted to boolean");
0766: } else {
0767: return false;
0768: }
0769: }
0770:
0771: /**
0772: * Get the value of a column in the current row as a Java short.
0773: *
0774: * @param columnIndex the first column is 1, the second is 2,...
0775: * @return the column value; 0 if SQL NULL
0776: * @exception SQLException if a database access error occurs
0777: */
0778: public short getShort(int columnIndex) throws SQLException {
0779: checkRowAndColPosAndSetNullFlag(columnIndex);
0780:
0781: if (wasNullFlag)
0782: return 0;
0783:
0784: Object obj;
0785: if (inserting || updating)
0786: obj = tempRow[columnIndex - 1];
0787: else
0788: obj = ((Object[]) data.get(currentRow))[columnIndex - 1];
0789:
0790: if (obj instanceof Number) {
0791: return ((Number) obj).shortValue();
0792: }
0793:
0794: // the object is not of type number we parse the string representation
0795: try {
0796: String string = obj.toString();
0797: string = string.trim();
0798: return Short.parseShort(string);
0799: } catch (NumberFormatException e) {
0800: // Try to convert a boolean
0801: String string = obj.toString().toLowerCase().trim();
0802: if ("true".equals(string))
0803: return 1;
0804: else if ("false".equals(string))
0805: return 0;
0806: throw new SQLException("the value " + obj.toString()
0807: + " is not a valid short number");
0808: }
0809: }
0810:
0811: /**
0812: * Get the value of a column in the current row as a Java int.
0813: *
0814: * @param columnIndex the first column is 1, the second is 2,...
0815: * @return the column value; 0 if SQL NULL
0816: * @exception SQLException if a database access error occurs
0817: */
0818: public int getInt(int columnIndex) throws SQLException {
0819: checkRowAndColPosAndSetNullFlag(columnIndex);
0820:
0821: if (wasNullFlag)
0822: return 0;
0823:
0824: Object obj;
0825: if (inserting || updating)
0826: obj = tempRow[columnIndex - 1];
0827: else
0828: obj = ((Object[]) data.get(currentRow))[columnIndex - 1];
0829:
0830: if (obj instanceof Number) {
0831: return ((Number) obj).intValue();
0832: }
0833:
0834: // the object is not of type number we parse the string representation
0835: try {
0836: String string = obj.toString();
0837: string = string.trim();
0838: return Integer.parseInt(string);
0839: } catch (NumberFormatException e) {
0840: // Try to convert a boolean
0841: String string = obj.toString().toLowerCase().trim();
0842: if ("true".equals(string))
0843: return 1;
0844: else if ("false".equals(string))
0845: return 0;
0846: throw new SQLException("the value " + obj.toString()
0847: + " is not a valid int number");
0848: }
0849: }
0850:
0851: /**
0852: * Get the value of a column in the current row as a Java long.
0853: *
0854: * @param columnIndex the first column is 1, the second is 2,...
0855: * @return the column value; 0 if SQL NULL
0856: * @exception SQLException if a database access error occurs
0857: */
0858: public long getLong(int columnIndex) throws SQLException {
0859: checkRowAndColPosAndSetNullFlag(columnIndex);
0860:
0861: if (wasNullFlag)
0862: return 0;
0863:
0864: Object obj;
0865: if (inserting || updating)
0866: obj = tempRow[columnIndex - 1];
0867: else
0868: obj = ((Object[]) data.get(currentRow))[columnIndex - 1];
0869:
0870: if (obj instanceof Number) {
0871: return ((Number) obj).longValue();
0872: }
0873:
0874: // the object is not of type number we parse the string representation
0875: try {
0876: String string = obj.toString();
0877: string = string.trim();
0878: return Long.parseLong(string);
0879: } catch (NumberFormatException e) {
0880: // Try to convert a boolean
0881: String string = obj.toString().toLowerCase().trim();
0882: if ("true".equals(string))
0883: return 1;
0884: else if ("false".equals(string))
0885: return 0;
0886: throw new SQLException("the value " + obj.toString()
0887: + " is not a valid long number");
0888: }
0889: }
0890:
0891: /**
0892: * Get the value of a column in the current row as a Java float.
0893: *
0894: * @param columnIndex the first column is 1, the second is 2,...
0895: * @return the column value; 0 if SQL NULL
0896: * @exception SQLException if a database access error occurs
0897: */
0898: public float getFloat(int columnIndex) throws SQLException {
0899: checkRowAndColPosAndSetNullFlag(columnIndex);
0900:
0901: if (wasNullFlag)
0902: return 0;
0903:
0904: Object obj;
0905: if (inserting || updating)
0906: obj = tempRow[columnIndex - 1];
0907: else
0908: obj = ((Object[]) data.get(currentRow))[columnIndex - 1];
0909:
0910: if (obj instanceof Number) {
0911: return ((Number) obj).floatValue();
0912: }
0913:
0914: // the object is not of type number we parse the string representation
0915: try {
0916: String string = obj.toString();
0917: string = string.trim();
0918: return Float.parseFloat(string);
0919: } catch (NumberFormatException e) {
0920: // Try to convert a boolean
0921: String string = obj.toString().toLowerCase().trim();
0922: if ("true".equals(string))
0923: return 1;
0924: else if ("false".equals(string))
0925: return 0;
0926: throw new SQLException("the value " + obj.toString()
0927: + " is not a valid float number");
0928: }
0929: }
0930:
0931: /**
0932: * Get the value of a column in the current row as a Java double.
0933: *
0934: * @param columnIndex the first column is 1, the second is 2,...
0935: * @return the column value; 0 if SQL NULL
0936: * @exception SQLException if a database access error occurs
0937: */
0938: public double getDouble(int columnIndex) throws SQLException {
0939: checkRowAndColPosAndSetNullFlag(columnIndex);
0940:
0941: if (wasNullFlag)
0942: return 0;
0943:
0944: Object obj;
0945: if (inserting || updating)
0946: obj = tempRow[columnIndex - 1];
0947: else
0948: obj = ((Object[]) data.get(currentRow))[columnIndex - 1];
0949:
0950: if (obj instanceof Number) {
0951: return ((Number) obj).doubleValue();
0952: }
0953:
0954: // the object is not of type number we parse the string representation
0955: try {
0956: String string = obj.toString();
0957: string = string.trim();
0958: return Double.parseDouble(string);
0959: } catch (NumberFormatException e) {
0960: // Try to convert a boolean
0961: String string = obj.toString().toLowerCase().trim();
0962: if ("true".equals(string))
0963: return 1;
0964: else if ("false".equals(string))
0965: return 0;
0966: throw new SQLException("the value " + obj.toString()
0967: + " is not a valid double number");
0968: }
0969: }
0970:
0971: /**
0972: * Get the value of a column in the current row as a java.lang.BigDecimal
0973: * object
0974: *
0975: * @param columnIndex the first column is 1, the second is 2...
0976: * @param scale the number of digits to the right of the decimal
0977: * @return the column value; if the value is SQL NULL, null
0978: * @exception SQLException if a database access error occurs
0979: * @deprecated
0980: */
0981: public BigDecimal getBigDecimal(int columnIndex, int scale)
0982: throws SQLException {
0983: BigDecimal bigDecimal = getBigDecimal(columnIndex);
0984: if (bigDecimal == null)
0985: return null;
0986: else
0987: return bigDecimal.setScale(scale);
0988: }
0989:
0990: /**
0991: * Get the value of a column in the current row as a Java byte array.
0992: * <p>
0993: * <b>Be warned </b> If the blob is huge, then you may run out of memory.
0994: *
0995: * @param columnIndex the first column is 1, the second is 2, ...
0996: * @return the column value; if the value is SQL NULL, the result is null
0997: * @exception SQLException if a database access error occurs
0998: */
0999: public byte[] getBytes(int columnIndex) throws SQLException {
1000: checkRowAndColPosAndSetNullFlag(columnIndex);
1001:
1002: if (wasNullFlag)
1003: return null;
1004:
1005: Object o;
1006: if (inserting || updating)
1007: o = tempRow[columnIndex - 1];
1008: else
1009: o = ((Object[]) data.get(currentRow))[columnIndex - 1];
1010:
1011: byte[] maybeEncodedBytes;
1012: if (o instanceof byte[]) {
1013: maybeEncodedBytes = (byte[]) o;
1014: } else if (o instanceof ByteArrayBlob) {
1015: ByteArrayBlob b = (ByteArrayBlob) o;
1016: // TODO: use getBinaryStream() to avoid the copy
1017: maybeEncodedBytes = b.getBytes(1, (int) b.length());
1018: } else {
1019: throw new NotImplementedException("in getBytes("
1020: + columnIndex
1021: + "), don't know how to convert type "
1022: + o.getClass().getName() + " into a byte array ");
1023: }
1024:
1025: return maybeEncodedBytes; // maybe not!
1026: }
1027:
1028: /**
1029: * Get the value of a column in the current row as a java.sql.Date object
1030: *
1031: * @param columnIndex the first column is 1, the second is 2...
1032: * @return the column value; null if SQL NULL
1033: * @exception SQLException if a database access error occurs
1034: */
1035: public java.sql.Date getDate(int columnIndex) throws SQLException {
1036: checkRowAndColPosAndSetNullFlag(columnIndex);
1037:
1038: if (wasNullFlag)
1039: return null;
1040:
1041: // we may be reading a timestamp column and have to convert it to date
1042: // the client is asking for the date field only, we have to make sure
1043: // hour,minutes,... are cleared
1044: String dateString;
1045: if (inserting || updating)
1046: dateString = tempRow[columnIndex - 1].toString();
1047: else
1048: dateString = ((Object[]) data.get(currentRow))[columnIndex - 1]
1049: .toString();
1050:
1051: if (dateString.length() == 10)
1052: return java.sql.Date.valueOf(dateString);
1053: else
1054: return java.sql.Date.valueOf(dateString.substring(0, 10));
1055: }
1056:
1057: /**
1058: * Get the value of a column in the current row as a java.sql.Time object
1059: *
1060: * @param columnIndex the first column is 1, the second is 2...
1061: * @return the column value; null if SQL NULL
1062: * @exception SQLException if a database access error occurs
1063: */
1064: public Time getTime(int columnIndex) throws SQLException {
1065: checkRowAndColPosAndSetNullFlag(columnIndex);
1066:
1067: if (wasNullFlag)
1068: return null;
1069:
1070: Object obj;
1071: if (inserting || updating)
1072: obj = tempRow[columnIndex - 1];
1073: else
1074: obj = ((Object[]) data.get(currentRow))[columnIndex - 1];
1075:
1076: if (obj instanceof java.util.Date) {
1077: java.util.Date time = (java.util.Date) obj;
1078: // the driver returns the format of the column, but we are asking for
1079: // the time values only.
1080: String timeString = time.toString();
1081: if (timeString.length() == 8) {
1082: // ok we have got a timefield of the format HH:mm:ss, exactly the way
1083: // we need it, no further processing is required
1084: return new Time(time.getTime());
1085: }
1086:
1087: // we have got the date fields too and have to clear the year, month and
1088: // date field
1089: Calendar cal = Calendar.getInstance();
1090: cal.setTime(time);
1091: cal.clear(Calendar.YEAR);
1092: cal.clear(Calendar.MONTH);
1093: cal.clear(Calendar.DATE);
1094: cal.clear(Calendar.MILLISECOND);
1095: return new Time(cal.getTimeInMillis());
1096: }
1097:
1098: // the object is not of type date we parse the string representation
1099: try {
1100: String string = obj.toString();
1101: string = string.trim();
1102: return Time.valueOf(string);
1103: } catch (IllegalArgumentException e) {
1104: throw new SQLException("the value " + obj.toString()
1105: + " is not a valid time");
1106: }
1107: }
1108:
1109: /**
1110: * Get the value of a column in the current row as a java.sql.Timestamp object
1111: *
1112: * @param columnIndex the first column is 1, the second is 2...
1113: * @return the column value; null if SQL NULL
1114: * @exception SQLException if a database access error occurs
1115: */
1116: public Timestamp getTimestamp(int columnIndex) throws SQLException {
1117: checkRowAndColPosAndSetNullFlag(columnIndex);
1118:
1119: if (wasNullFlag)
1120: return null;
1121:
1122: Object obj;
1123: if (inserting || updating)
1124: obj = tempRow[columnIndex - 1];
1125: else
1126: obj = ((Object[]) data.get(currentRow))[columnIndex - 1];
1127:
1128: if (obj instanceof java.util.Date) {
1129: return new Timestamp(((java.util.Date) obj).getTime());
1130: }
1131:
1132: // the object is not of type timestamp we parse the string representation
1133: try {
1134: String string = obj.toString();
1135: string = string.trim();
1136: return Timestamp.valueOf(string);
1137: } catch (IllegalArgumentException e) {
1138: throw new SQLException("the value " + obj.toString()
1139: + " is not a valid timestamp");
1140: }
1141: }
1142:
1143: /**
1144: * A column value can be retrieved as a stream of ASCII characters and then
1145: * read in chunks from the stream. This method is particulary suitable for
1146: * retrieving large LONGVARCHAR values. The JDBC driver will do any necessary
1147: * conversion from the database format into ASCII.
1148: * <p>
1149: * <B>Note: </B> All the data in the returned stream must be read prior to
1150: * getting the value of any other column. The next call to a get method
1151: * implicitly closes the stream. Also, a stream may return 0 for available()
1152: * whether there is data available or not.
1153: *
1154: * @param columnIndex the first column is 1, the second is 2, ...
1155: * @return a Java InputStream that delivers the database column value as a
1156: * stream of one byte ASCII characters. If the value is SQL NULL then
1157: * the result is null
1158: * @exception SQLException if a database access error occurs
1159: * @see #getBinaryStream(int)
1160: */
1161: public InputStream getAsciiStream(int columnIndex)
1162: throws SQLException {
1163: checkRowAndColPosAndSetNullFlag(columnIndex);
1164:
1165: try { // TODO: actually implement a "streaming" encoding instead of encoding
1166: // everything at once. See SEQUOIA-400
1167: currentStream = new ByteArrayInputStream(Charset.forName(
1168: "US-ASCII").newEncoder().encode(
1169: CharBuffer.wrap(getString(columnIndex))).array());
1170: } catch (CharacterCodingException e) {
1171: throw (SQLException) new SQLException(
1172: "Caught CharacterCodingException (data is probably not ASCII): "
1173: + e.getMessage()).initCause(e);
1174: }
1175: return currentStream;
1176: }
1177:
1178: /**
1179: * A column value can also be retrieved as a stream of Unicode characters. We
1180: * implement this as a binary stream.
1181: *
1182: * @param columnIndex the first column is 1, the second is 2...
1183: * @return a Java InputStream that delivers the database column value as a
1184: * stream of two byte Unicode characters. If the value is SQL NULL,
1185: * then the result is null
1186: * @exception SQLException if a database access error occurs
1187: * @deprecated
1188: * @see #getAsciiStream
1189: * @see #getBinaryStream(int)
1190: */
1191: public InputStream getUnicodeStream(int columnIndex)
1192: throws SQLException {
1193: checkRowAndColPosAndSetNullFlag(columnIndex);
1194:
1195: currentStream = new ByteArrayInputStream(getString(columnIndex)
1196: .getBytes());
1197: return currentStream;
1198: }
1199:
1200: /**
1201: * A column value can also be retrieved as a binary strea. This method is
1202: * suitable for retrieving LONGVARBINARY values.
1203: *
1204: * @param columnIndex the first column is 1, the second is 2...
1205: * @return a Java InputStream that delivers the database column value as a
1206: * stream of bytes. If the value is SQL NULL, then the result is null
1207: * @exception SQLException if a database access error occurs
1208: * @see #getAsciiStream(int)
1209: * @see #getUnicodeStream(int)
1210: */
1211:
1212: public InputStream getBinaryStream(int columnIndex)
1213: throws SQLException {
1214: checkRowAndColPosAndSetNullFlag(columnIndex);
1215:
1216: byte[] b = getBytes(columnIndex);
1217: if (b != null) {
1218: currentStream = new ByteArrayInputStream(b);
1219: return currentStream;
1220: } else
1221: return null; // SQL NULL
1222: }
1223:
1224: /**
1225: * The following routines simply convert the columnName into a columnIndex and
1226: * then call the appropriate routine above.
1227: *
1228: * @param columnName is the SQL name of the column
1229: * @return the column value
1230: * @exception SQLException if a database access error occurs
1231: */
1232: public String getString(String columnName) throws SQLException {
1233: return this .getString(findColumn(columnName));
1234: }
1235:
1236: /**
1237: * @see java.sql.ResultSet#getBoolean(java.lang.String)
1238: */
1239: public boolean getBoolean(String columnName) throws SQLException {
1240: return getBoolean(findColumn(columnName));
1241: }
1242:
1243: /**
1244: * @see java.sql.ResultSet#getByte(java.lang.String)
1245: */
1246: public byte getByte(String columnName) throws SQLException {
1247: return getByte(findColumn(columnName));
1248: }
1249:
1250: /**
1251: * @see java.sql.ResultSet#getShort(java.lang.String)
1252: */
1253: public short getShort(String columnName) throws SQLException {
1254: return getShort(findColumn(columnName));
1255: }
1256:
1257: /**
1258: * @see java.sql.ResultSet#getInt(java.lang.String)
1259: */
1260: public int getInt(String columnName) throws SQLException {
1261: return getInt(findColumn(columnName));
1262: }
1263:
1264: /**
1265: * @see java.sql.ResultSet#getLong(java.lang.String)
1266: */
1267: public long getLong(String columnName) throws SQLException {
1268: return getLong(findColumn(columnName));
1269: }
1270:
1271: /**
1272: * @see java.sql.ResultSet#getFloat(java.lang.String)
1273: */
1274: public float getFloat(String columnName) throws SQLException {
1275: return getFloat(findColumn(columnName));
1276: }
1277:
1278: /**
1279: * @see java.sql.ResultSet#getDouble(java.lang.String)
1280: */
1281: public double getDouble(String columnName) throws SQLException {
1282: return getDouble(findColumn(columnName));
1283: }
1284:
1285: /**
1286: * @see java.sql.ResultSet#getBigDecimal(String, int)
1287: * @deprecated
1288: */
1289: public BigDecimal getBigDecimal(String columnName, int scale)
1290: throws SQLException {
1291: return getBigDecimal(findColumn(columnName), scale);
1292: }
1293:
1294: /**
1295: * @see java.sql.ResultSet#getBytes(java.lang.String)
1296: */
1297: public byte[] getBytes(String columnName) throws SQLException {
1298: return getBytes(findColumn(columnName));
1299: }
1300:
1301: /**
1302: * @see java.sql.ResultSet#getDate(java.lang.String)
1303: */
1304: public java.sql.Date getDate(String columnName) throws SQLException {
1305: return getDate(findColumn(columnName));
1306: }
1307:
1308: /**
1309: * @see java.sql.ResultSet#getTime(java.lang.String)
1310: */
1311: public Time getTime(String columnName) throws SQLException {
1312: return getTime(findColumn(columnName));
1313: }
1314:
1315: /**
1316: * @see java.sql.ResultSet#getTimestamp(java.lang.String)
1317: */
1318: public Timestamp getTimestamp(String columnName)
1319: throws SQLException {
1320: return getTimestamp(findColumn(columnName));
1321: }
1322:
1323: /**
1324: * @see java.sql.ResultSet#getAsciiStream(java.lang.String)
1325: */
1326: public InputStream getAsciiStream(String columnName)
1327: throws SQLException {
1328: return getAsciiStream(findColumn(columnName));
1329: }
1330:
1331: /**
1332: * @see java.sql.ResultSet#getUnicodeStream(String)
1333: * @deprecated
1334: */
1335: public InputStream getUnicodeStream(String columnName)
1336: throws SQLException {
1337: return getUnicodeStream(findColumn(columnName));
1338: }
1339:
1340: /**
1341: * @see java.sql.ResultSet#getBinaryStream(java.lang.String)
1342: */
1343: public InputStream getBinaryStream(String columnName)
1344: throws SQLException {
1345: return getBinaryStream(findColumn(columnName));
1346: }
1347:
1348: /**
1349: * The first warning reported by calls on this ResultSet is returned.
1350: * Subsequent ResultSet warnings will be chained to this java.sql.SQLWarning.
1351: * <p>
1352: * The warning chain is automatically cleared each time a new row is read.
1353: * <p>
1354: * <B>Note: </B> This warning chain only covers warnings caused by ResultSet
1355: * methods. Any warnings caused by statement methods (such as reading OUT
1356: * parameters) will be chained on the Statement object.
1357: *
1358: * @return the first java.sql.SQLWarning or null;
1359: * @exception SQLException if a database access error occurs or this method is
1360: * called on a closed result set
1361: */
1362: public java.sql.SQLWarning getWarnings() throws SQLException {
1363: checkIfClosed();
1364: return connection.convertToSQLWarnings(warnings);
1365: }
1366:
1367: /**
1368: * After this call, getWarnings returns null until a new warning is reported
1369: * for this ResultSet
1370: *
1371: * @exception SQLException if a database access error occurs
1372: */
1373:
1374: public void clearWarnings() throws SQLException {
1375: warnings = null;
1376: }
1377:
1378: SQLWarning getStatementWarnings() {
1379: return statementWarnings;
1380: }
1381:
1382: void setStatementWarnings(SQLWarning sqlw) {
1383: statementWarnings = sqlw;
1384: }
1385:
1386: /**
1387: * @see java.sql.ResultSet#getCursorName()
1388: */
1389: public String getCursorName() throws SQLException {
1390: return cursorName;
1391: }
1392:
1393: /**
1394: * Get the value of a column in the current row as a Java object
1395: * <p>
1396: * This method will return the value of the given column as a Java object. The
1397: * type of the Java object will be the default Java Object type corresponding
1398: * to the column's SQL type, following the mapping specified in the JDBC
1399: * specification.
1400: * <p>
1401: * This method may also be used to read database specific abstract data types.
1402: *
1403: * @param columnIndex the first column is 1, the second is 2...
1404: * @return a Object holding the column value
1405: * @exception SQLException if a database access error occurs
1406: */
1407: public Object getObject(int columnIndex) throws SQLException {
1408: checkRowAndColPosAndSetNullFlag(columnIndex);
1409:
1410: if (wasNullFlag)
1411: return null;
1412:
1413: Object o;
1414: if (inserting || updating)
1415: o = tempRow[columnIndex];
1416: else
1417: o = ((Object[]) data.get(currentRow))[columnIndex - 1];
1418: return o;
1419: }
1420:
1421: /**
1422: * Get the value of a column in the current row as a Java object
1423: * <p>
1424: * This method will return the value of the given column as a Java object. The
1425: * type of the Java object will be the default Java Object type corresponding
1426: * to the column's SQL type, following the mapping specified in the JDBC
1427: * specification.
1428: * <p>
1429: * This method may also be used to read database specific abstract data types.
1430: *
1431: * @param columnName is the SQL name of the column
1432: * @return a Object holding the column value
1433: * @exception SQLException if a database access error occurs
1434: */
1435: public Object getObject(String columnName) throws SQLException {
1436: return getObject(findColumn(columnName));
1437: }
1438:
1439: // --------------------------JDBC 2.0-----------------------------------
1440:
1441: /**
1442: * @see java.sql.ResultSet#getCharacterStream(int)
1443: */
1444: public java.io.Reader getCharacterStream(int columnIndex)
1445: throws SQLException {
1446: String s = getString(columnIndex);
1447: if (s == null)
1448: return null;
1449: char[] content = s.toCharArray();
1450: return new java.io.CharArrayReader(content);
1451: }
1452:
1453: /**
1454: * @see java.sql.ResultSet#getCharacterStream(java.lang.String)
1455: */
1456: public java.io.Reader getCharacterStream(String columnName)
1457: throws SQLException {
1458: return getCharacterStream(findColumn(columnName));
1459: }
1460:
1461: /**
1462: * JDBC 2.0 Get the value of a column in the current row as a
1463: * java.math.BigDecimal object.
1464: *
1465: * @param columnIndex the first column is 1, the second is 2, ...
1466: * @return the column value (full precision); if the value is SQL NULL, the
1467: * result is null
1468: * @exception SQLException if a database-access error occurs.
1469: */
1470: public BigDecimal getBigDecimal(int columnIndex)
1471: throws SQLException {
1472: checkRowAndColPosAndSetNullFlag(columnIndex);
1473:
1474: if (wasNullFlag)
1475: return null;
1476:
1477: Object obj;
1478: if (inserting || updating)
1479: obj = tempRow[columnIndex - 1];
1480: else
1481: obj = ((Object[]) data.get(currentRow))[columnIndex - 1];
1482:
1483: if (obj instanceof BigDecimal)
1484: return (BigDecimal) obj;
1485: else if (obj instanceof Long) {
1486: return new BigDecimal(((Long) obj).longValue());
1487: } else if (obj instanceof BigInteger) {
1488: return new BigDecimal(((BigInteger) obj));
1489: } else if (obj instanceof Short) {
1490: return new BigDecimal(((Short) obj).shortValue());
1491: } else if (obj instanceof Integer) {
1492: return new BigDecimal(((Integer) obj).intValue());
1493: } else if (obj instanceof String) {
1494: return new BigDecimal((String) obj);
1495: } else if (obj instanceof Number) {
1496: // float and double have to be converted via string
1497: // othwerwise we produce errors
1498: // javadoc for BigDecimal :
1499: // Note: the results of this constructor can be somewhat unpredictable.
1500: // One might assume that new BigDecimal(.1) is exactly equal to .1, but
1501: // it is actually equal to
1502: // .1000000000000000055511151231257827021181583404541015625. This is so
1503: // because .1 cannot be represented exactly as a double (or, for that
1504: // matter, as a binary fraction of any finite length). Thus, the long
1505: // value that is being passed in to the constructor is not exactly equal
1506: // to .1, appearances nonwithstanding.
1507:
1508: // The (String) constructor, on the other hand, is perfectly
1509: // predictable: new BigDecimal(".1") is exactly equal to .1, as one
1510: // would expect. Therefore, it is generally recommended that the
1511: // (String) constructor be used in preference to this one.
1512: return new BigDecimal(obj.toString());
1513: } else if (obj instanceof Boolean) {
1514: // Try to convert a boolean
1515: String string = obj.toString().toLowerCase().trim();
1516: if ("true".equals(string))
1517: return new BigDecimal(1);
1518: else if ("false".equals(string))
1519: return new BigDecimal(0);
1520: throw new SQLException("Type " + obj.getClass().getName()
1521: + " is not compatible with BigDecimal");
1522:
1523: } else {
1524: throw new SQLException("Type " + obj.getClass().getName()
1525: + " is not compatible with BigDecimal");
1526: }
1527: }
1528:
1529: /**
1530: * @see java.sql.ResultSet#getBigDecimal(java.lang.String)
1531: */
1532: public BigDecimal getBigDecimal(String columnName)
1533: throws SQLException {
1534: return getBigDecimal(findColumn(columnName));
1535: }
1536:
1537: /**
1538: * JDBC 2.0 Returns the value of column as a Java object. Use the map to
1539: * determine the class from which to construct data of SQL structured and
1540: * distinct types.
1541: *
1542: * @param i the first column is 1, the second is 2, ...
1543: * @param map the mapping from SQL type names to Java classes
1544: * @return an object representing the SQL value
1545: * @exception SQLException if a database-access error occurs.
1546: */
1547: public Object getObject(int i, java.util.Map map)
1548: throws SQLException {
1549: throw new NotImplementedException(
1550: "getObject(int, java.util.Map)");
1551: }
1552:
1553: /**
1554: * JDBC 2.0 Get a REF(<structured-type>) column.
1555: *
1556: * @param i the first column is 1, the second is 2, ...
1557: * @return an object representing data of an SQL REF type
1558: * @exception SQLException if a database-access error occurs.
1559: */
1560: public java.sql.Ref getRef(int i) throws SQLException {
1561: checkRowAndColPosAndSetNullFlag(i);
1562:
1563: if (wasNullFlag)
1564: return null;
1565:
1566: if (inserting || updating)
1567: return (Ref) tempRow[i - 1];
1568: else
1569: return (Ref) (((Object[]) data.get(currentRow))[i - 1]);
1570: }
1571:
1572: /**
1573: * JDBC 2.0 Gets a BLOB column.
1574: *
1575: * @param columnIndex the first column is 1, the second is 2, ...
1576: * @return an object representing a BLOB
1577: * @exception SQLException if a database-access error occurs.
1578: */
1579: public java.sql.Blob getBlob(int columnIndex) throws SQLException {
1580: checkRowAndColPosAndSetNullFlag(columnIndex);
1581:
1582: if (wasNullFlag)
1583: return null;
1584:
1585: Object o;
1586: if (inserting || updating)
1587: o = tempRow[columnIndex - 1];
1588: else
1589: o = (((Object[]) data.get(currentRow))[columnIndex - 1]);
1590:
1591: // getBytes() does decode
1592: if (o instanceof ByteArrayBlob || o instanceof byte[])
1593: return new ByteArrayBlob(getBytes(columnIndex));
1594: else
1595: throw new NotImplementedException("in getBlob("
1596: + columnIndex
1597: + "), don't know how to convert type "
1598: + o.getClass().getName() + " into a Blob");
1599: }
1600:
1601: /**
1602: * JDBC 2.0 Gets a CLOB column.
1603: *
1604: * @param columnIndex the first column is 1, the second is 2, ...
1605: * @return an object representing a CLOB
1606: * @exception SQLException if a database-access error occurs.
1607: */
1608: public java.sql.Clob getClob(int columnIndex) throws SQLException {
1609: checkRowAndColPosAndSetNullFlag(columnIndex);
1610:
1611: if (wasNullFlag)
1612: return null;
1613:
1614: Object o;
1615: if (inserting || updating)
1616: o = tempRow[columnIndex - 1];
1617: else
1618: o = (((Object[]) data.get(currentRow))[columnIndex - 1]);
1619:
1620: // Test if the type of the Clob is indeed a Clob or just a String
1621: // throw new SQLException("Class:"+o.getClass());
1622: if (o instanceof String)
1623: return new StringClob((String) o);
1624: else if (o instanceof Clob)
1625: return (java.sql.Clob) o;
1626: else
1627: // FIXME: Huh? What it is the purpose of this?
1628: return new StringClob(new String(o.toString()));
1629: }
1630:
1631: /**
1632: * JDBC 2.0 Gets an array column.
1633: *
1634: * @param columnIndex the first column is 1, the second is 2, ...
1635: * @return an object representing an SQL array
1636: * @exception SQLException if a database-access error occurs.
1637: */
1638: public java.sql.Array getArray(int columnIndex) throws SQLException {
1639: checkRowAndColPosAndSetNullFlag(columnIndex);
1640:
1641: if (wasNullFlag)
1642: return null;
1643:
1644: if (inserting || updating)
1645: return (java.sql.Array) tempRow[columnIndex - 1];
1646: else
1647: return (java.sql.Array) (((Object[]) data.get(currentRow))[columnIndex - 1]);
1648: }
1649:
1650: /**
1651: * JDBC 2.0 Returns the value of column as a Java object. Use the map to
1652: * determine the class from which to construct data of SQL structured and
1653: * distinct types.
1654: *
1655: * @param colName the column name
1656: * @param map the mapping from SQL type names to Java classes
1657: * @return an object representing the SQL value
1658: * @exception SQLException if a database-access error occurs.
1659: */
1660: public Object getObject(String colName, java.util.Map map)
1661: throws SQLException {
1662: return getObject(findColumn(colName), map);
1663: }
1664:
1665: /**
1666: * JDBC 2.0 Get a REF(<structured-type>) column.
1667: *
1668: * @param colName the column name
1669: * @return an object representing data of an SQL REF type
1670: * @exception SQLException if a database-access error occurs.
1671: */
1672: public java.sql.Ref getRef(String colName) throws SQLException {
1673: return getRef(findColumn(colName));
1674: }
1675:
1676: /**
1677: * JDBC 2.0 Get a BLOB column.
1678: *
1679: * @param colName the column name
1680: * @return an object representing a BLOB
1681: * @exception SQLException if a database-access error occurs.
1682: */
1683: public java.sql.Blob getBlob(String colName) throws SQLException {
1684: return getBlob(findColumn(colName));
1685: }
1686:
1687: /**
1688: * JDBC 2.0 Get a CLOB column.
1689: *
1690: * @param colName the column name
1691: * @return an object representing a CLOB
1692: * @exception SQLException if a database-access error occurs.
1693: */
1694: public java.sql.Clob getClob(String colName) throws SQLException {
1695: return getClob(findColumn(colName));
1696: }
1697:
1698: /**
1699: * JDBC 2.0 Get an array column.
1700: *
1701: * @param colName the column name
1702: * @return an object representing an SQL array
1703: * @exception SQLException if a database-access error occurs.
1704: */
1705: public java.sql.Array getArray(String colName) throws SQLException {
1706: return getArray(findColumn(colName));
1707: }
1708:
1709: /**
1710: * JDBC 2.0 Get the value of a column in the current row as a java.sql.Date
1711: * object. Use the calendar to construct an appropriate millisecond value for
1712: * the Date, if the underlying database doesn't store timezone information.
1713: *
1714: * @param columnIndex the first column is 1, the second is 2, ...
1715: * @param cal the calendar to use in constructing the date (ignored)
1716: * @return the column value; if the value is SQL NULL, the result is null
1717: * @exception SQLException if a database-access error occurs.
1718: */
1719: public java.sql.Date getDate(int columnIndex, Calendar cal)
1720: throws SQLException {
1721: return getDate(columnIndex);
1722: }
1723:
1724: /**
1725: * Get the value of a column in the current row as a java.sql.Date object. Use
1726: * the calendar to construct an appropriate millisecond value for the Date, if
1727: * the underlying database doesn't store timezone information.
1728: *
1729: * @param columnName is the SQL name of the column
1730: * @param cal the calendar to use in constructing the date
1731: * @return the column value; if the value is SQL NULL, the result is null
1732: * @exception SQLException if a database-access error occurs.
1733: */
1734: public java.sql.Date getDate(String columnName, Calendar cal)
1735: throws SQLException {
1736: return getDate(findColumn(columnName), cal);
1737: }
1738:
1739: /**
1740: * Get the value of a column in the current row as a java.sql.Time object. Use
1741: * the calendar to construct an appropriate millisecond value for the Time, if
1742: * the underlying database doesn't store timezone information.
1743: *
1744: * @param columnIndex the first column is 1, the second is 2, ...
1745: * @param cal the calendar to use in constructing the time
1746: * @return the column value; if the value is SQL NULL, the result is null
1747: * @exception SQLException if a database-access error occurs.
1748: */
1749: public java.sql.Time getTime(int columnIndex, Calendar cal)
1750: throws SQLException {
1751: return getTime(columnIndex);
1752: }
1753:
1754: /**
1755: * Get the value of a column in the current row as a java.sql.Time object. Use
1756: * the calendar to construct an appropriate millisecond value for the Time, if
1757: * the underlying database doesn't store timezone information.
1758: *
1759: * @param columnName is the SQL name of the column
1760: * @param cal the calendar to use in constructing the time
1761: * @return the column value; if the value is SQL NULL, the result is null
1762: * @exception SQLException if a database-access error occurs.
1763: */
1764: public java.sql.Time getTime(String columnName, Calendar cal)
1765: throws SQLException {
1766: return getTime(findColumn(columnName), cal);
1767: }
1768:
1769: /**
1770: * Get the value of a column in the current row as a java.sql.Timestamp
1771: * object. Use the calendar to construct an appropriate millisecond value for
1772: * the Timestamp, if the underlying database doesn't store timezone
1773: * information.
1774: *
1775: * @param columnIndex the first column is 1, the second is 2, ...
1776: * @param cal the calendar to use in constructing the timestamp (ignored)
1777: * @return the column value; if the value is SQL NULL, the result is null
1778: * @exception SQLException if a database-access error occurs.
1779: */
1780: public java.sql.Timestamp getTimestamp(int columnIndex, Calendar cal)
1781: throws SQLException {
1782: return getTimestamp(columnIndex);
1783: }
1784:
1785: /**
1786: * Get the value of a column in the current row as a java.sql.Timestamp
1787: * object. Use the calendar to construct an appropriate millisecond value for
1788: * the Timestamp, if the underlying database doesn't store timezone
1789: * information.
1790: *
1791: * @param columnName is the SQL name of the column
1792: * @param cal the calendar to use in constructing the timestamp
1793: * @return the column value; if the value is SQL NULL, the result is null
1794: * @exception SQLException if a database-access error occurs.
1795: */
1796: public java.sql.Timestamp getTimestamp(String columnName,
1797: Calendar cal) throws SQLException {
1798: return getTimestamp(findColumn(columnName), cal);
1799: }
1800:
1801: // ---------------------------------------------------------------------
1802: // Updates
1803: // ---------------------------------------------------------------------
1804:
1805: /**
1806: * JDBC 2.0 Determine if the current row has been updated. The value returned
1807: * depends on whether or not the result set can detect updates.
1808: *
1809: * @return <code>true</code> if the row has been visibly updated by the
1810: * owner or another, and updates are detected
1811: * @exception SQLException if a database-access error occurs
1812: * @see DatabaseMetaData#updatesAreDetected
1813: */
1814: public boolean rowUpdated() throws SQLException {
1815: throw new NotImplementedException("rowUpdated");
1816: }
1817:
1818: /**
1819: * JDBC 2.0 Determine if the current row has been inserted. The value returned
1820: * depends on whether or not the result set can detect visible inserts.
1821: *
1822: * @return <code>true</code> if inserted and inserts are detected
1823: * @exception SQLException if a database-access error occurs
1824: * @see DatabaseMetaData#insertsAreDetected
1825: */
1826: public boolean rowInserted() throws SQLException {
1827: throw new NotImplementedException("rowInserted");
1828: }
1829:
1830: /**
1831: * JDBC 2.0 Determine if this row has been deleted. A deleted row may leave a
1832: * visible "hole" in a result set. This method can be used to detect holes in
1833: * a result set. The value returned depends on whether or not the result set
1834: * can detect deletions.
1835: *
1836: * @return <code>true</code> if deleted and deletes are detected
1837: * @exception SQLException if a database-access error occurs
1838: * @see DatabaseMetaData#deletesAreDetected
1839: */
1840: public boolean rowDeleted() throws SQLException {
1841: throw new NotImplementedException("rowDeleted");
1842: }
1843:
1844: /**
1845: * JDBC 2.0 Give a nullable column a null value. The updateXXX() methods are
1846: * used to update column values in the current row, or the insert row. The
1847: * updateXXX() methods do not update the underlying database, instead the
1848: * updateRow() or insertRow() methods are called to update the database.
1849: *
1850: * @param columnIndex the first column is 1, the second is 2, ...
1851: * @exception SQLException if a database-access error occurs
1852: */
1853: public void updateNull(int columnIndex) throws SQLException {
1854: checkIfClosed();
1855:
1856: if (inserting)
1857: insertStatement.setNull(columnIndex,
1858: fields[columnIndex - 1].getSqlType());
1859: else {
1860: checkUpdateFlagAndPrepareUpdateIfNeeded();
1861: updateStatement.setNull(columnIndex,
1862: fields[columnIndex - 1].getSqlType());
1863: }
1864:
1865: tempRow[columnIndex - 1] = null;
1866: }
1867:
1868: /**
1869: * JDBC 2.0 Update a column with a boolean value. The updateXXX() methods are
1870: * used to update column values in the current row, or the insert row. The
1871: * updateXXX() methods do not update the underlying database, instead the
1872: * updateRow() or insertRow() methods are called to update the database.
1873: *
1874: * @param columnIndex the first column is 1, the second is 2, ...
1875: * @param x the new column value
1876: * @exception SQLException if a database-access error occurs
1877: */
1878:
1879: public void updateBoolean(int columnIndex, boolean x)
1880: throws SQLException {
1881: checkIfClosed();
1882:
1883: if (inserting)
1884: insertStatement.setBoolean(columnIndex, x);
1885: else {
1886: checkUpdateFlagAndPrepareUpdateIfNeeded();
1887: updateStatement.setBoolean(columnIndex, x);
1888: }
1889:
1890: tempRow[columnIndex - 1] = Boolean.valueOf(x);
1891: }
1892:
1893: /**
1894: * JDBC 2.0 Update a column with a byte value. The updateXXX() methods are
1895: * used to update column values in the current row, or the insert row. The
1896: * updateXXX() methods do not update the underlying database, instead the
1897: * updateRow() or insertRow() methods are called to update the database.
1898: *
1899: * @param columnIndex the first column is 1, the second is 2, ...
1900: * @param x the new column value
1901: * @exception SQLException if a database-access error occurs
1902: */
1903: public void updateByte(int columnIndex, byte x) throws SQLException {
1904: checkIfClosed();
1905:
1906: if (inserting)
1907: insertStatement.setByte(columnIndex, x);
1908: else {
1909: checkUpdateFlagAndPrepareUpdateIfNeeded();
1910: updateStatement.setByte(columnIndex, x);
1911: }
1912:
1913: tempRow[columnIndex - 1] = new Byte(x);
1914: }
1915:
1916: /**
1917: * JDBC 2.0 Update a column with a short value. The updateXXX() methods are
1918: * used to update column values in the current row, or the insert row. The
1919: * updateXXX() methods do not update the underlying database, instead the
1920: * updateRow() or insertRow() methods are called to update the database.
1921: *
1922: * @param columnIndex the first column is 1, the second is 2, ...
1923: * @param x the new column value
1924: * @exception SQLException if a database-access error occurs
1925: */
1926: public void updateShort(int columnIndex, short x)
1927: throws SQLException {
1928: checkIfClosed();
1929:
1930: if (inserting)
1931: insertStatement.setShort(columnIndex, x);
1932: else {
1933: checkUpdateFlagAndPrepareUpdateIfNeeded();
1934: updateStatement.setShort(columnIndex, x);
1935: }
1936:
1937: tempRow[columnIndex - 1] = new Short(x);
1938: }
1939:
1940: /**
1941: * JDBC 2.0 Update a column with an integer value. The updateXXX() methods are
1942: * used to update column values in the current row, or the insert row. The
1943: * updateXXX() methods do not update the underlying database, instead the
1944: * updateRow() or insertRow() methods are called to update the database.
1945: *
1946: * @param columnIndex the first column is 1, the second is 2, ...
1947: * @param x the new column value
1948: * @exception SQLException if a database-access error occurs
1949: */
1950: public void updateInt(int columnIndex, int x) throws SQLException {
1951: checkIfClosed();
1952:
1953: if (inserting)
1954: insertStatement.setInt(columnIndex, x);
1955: else {
1956: checkUpdateFlagAndPrepareUpdateIfNeeded();
1957: updateStatement.setInt(columnIndex, x);
1958: }
1959:
1960: tempRow[columnIndex - 1] = new Integer(x);
1961: }
1962:
1963: /**
1964: * JDBC 2.0 Update a column with a long value. The updateXXX() methods are
1965: * used to update column values in the current row, or the insert row. The
1966: * updateXXX() methods do not update the underlying database, instead the
1967: * updateRow() or insertRow() methods are called to update the database.
1968: *
1969: * @param columnIndex the first column is 1, the second is 2, ...
1970: * @param x the new column value
1971: * @exception SQLException if a database-access error occurs
1972: */
1973: public void updateLong(int columnIndex, long x) throws SQLException {
1974: checkIfClosed();
1975:
1976: if (inserting)
1977: insertStatement.setLong(columnIndex, x);
1978: else {
1979: checkUpdateFlagAndPrepareUpdateIfNeeded();
1980: updateStatement.setLong(columnIndex, x);
1981: }
1982:
1983: tempRow[columnIndex - 1] = new Long(x);
1984: }
1985:
1986: /**
1987: * JDBC 2.0 Update a column with a float value. The updateXXX() methods are
1988: * used to update column values in the current row, or the insert row. The
1989: * updateXXX() methods do not update the underlying database, instead the
1990: * updateRow() or insertRow() methods are called to update the database.
1991: *
1992: * @param columnIndex the first column is 1, the second is 2, ...
1993: * @param x the new column value
1994: * @exception SQLException if a database-access error occurs
1995: */
1996: public void updateFloat(int columnIndex, float x)
1997: throws SQLException {
1998: checkIfClosed();
1999:
2000: if (inserting)
2001: insertStatement.setFloat(columnIndex, x);
2002: else {
2003: checkUpdateFlagAndPrepareUpdateIfNeeded();
2004: updateStatement.setFloat(columnIndex, x);
2005: }
2006:
2007: tempRow[columnIndex - 1] = new Float(x);
2008: }
2009:
2010: /**
2011: * JDBC 2.0 Update a column with a Double value. The updateXXX() methods are
2012: * used to update column values in the current row, or the insert row. The
2013: * updateXXX() methods do not update the underlying database, instead the
2014: * updateRow() or insertRow() methods are called to update the database.
2015: *
2016: * @param columnIndex the first column is 1, the second is 2, ...
2017: * @param x the new column value
2018: * @exception SQLException if a database-access error occurs
2019: */
2020: public void updateDouble(int columnIndex, double x)
2021: throws SQLException {
2022: checkIfClosed();
2023:
2024: if (inserting)
2025: insertStatement.setDouble(columnIndex, x);
2026: else {
2027: checkUpdateFlagAndPrepareUpdateIfNeeded();
2028: updateStatement.setDouble(columnIndex, x);
2029: }
2030:
2031: tempRow[columnIndex - 1] = new Double(x);
2032: }
2033:
2034: /**
2035: * JDBC 2.0 Update a column with a BigDecimal value. The updateXXX() methods
2036: * are used to update column values in the current row, or the insert row. The
2037: * updateXXX() methods do not update the underlying database, instead the
2038: * updateRow() or insertRow() methods are called to update the database.
2039: *
2040: * @param columnIndex the first column is 1, the second is 2, ...
2041: * @param x the new column value
2042: * @exception SQLException if a database-access error occurs
2043: */
2044: public void updateBigDecimal(int columnIndex, BigDecimal x)
2045: throws SQLException {
2046: checkIfClosed();
2047:
2048: if (inserting)
2049: insertStatement.setBigDecimal(columnIndex, x);
2050: else {
2051: checkUpdateFlagAndPrepareUpdateIfNeeded();
2052: updateStatement.setBigDecimal(columnIndex, x);
2053: }
2054:
2055: tempRow[columnIndex - 1] = x;
2056: }
2057:
2058: /**
2059: * JDBC 2.0 Update a column with a String value. The updateXXX() methods are
2060: * used to update column values in the current row, or the insert row. The
2061: * updateXXX() methods do not update the underlying database, instead the
2062: * updateRow() or insertRow() methods are called to update the database.
2063: *
2064: * @param columnIndex the first column is 1, the second is 2, ...
2065: * @param x the new column value
2066: * @exception SQLException if a database-access error occurs
2067: */
2068: public void updateString(int columnIndex, String x)
2069: throws SQLException {
2070: checkIfClosed();
2071:
2072: if (inserting)
2073: insertStatement.setString(columnIndex, x);
2074: else {
2075: checkUpdateFlagAndPrepareUpdateIfNeeded();
2076: updateStatement.setString(columnIndex, x);
2077: }
2078:
2079: tempRow[columnIndex - 1] = x;
2080: }
2081:
2082: /**
2083: * JDBC 2.0 Update a column with a byte array value. The updateXXX() methods
2084: * are used to update column values in the current row, or the insert row. The
2085: * updateXXX() methods do not update the underlying database, instead the
2086: * updateRow() or insertRow() methods are called to update the database.
2087: *
2088: * @param columnIndex the first column is 1, the second is 2, ...
2089: * @param x the new column value
2090: * @exception SQLException if a database-access error occurs
2091: */
2092: public void updateBytes(int columnIndex, byte[] x)
2093: throws SQLException {
2094: checkIfClosed();
2095:
2096: if (inserting)
2097: insertStatement.setBytes(columnIndex, x);
2098: else {
2099: checkUpdateFlagAndPrepareUpdateIfNeeded();
2100: updateStatement.setBytes(columnIndex, x);
2101: }
2102:
2103: tempRow[columnIndex - 1] = x;
2104: }
2105:
2106: /**
2107: * JDBC 2.0 Update a column with a Date value. The updateXXX() methods are
2108: * used to update column values in the current row, or the insert row. The
2109: * updateXXX() methods do not update the underlying database, instead the
2110: * updateRow() or insertRow() methods are called to update the database.
2111: *
2112: * @param columnIndex the first column is 1, the second is 2, ...
2113: * @param x the new column value
2114: * @exception SQLException if a database-access error occurs
2115: */
2116: public void updateDate(int columnIndex, java.sql.Date x)
2117: throws SQLException {
2118: checkIfClosed();
2119:
2120: if (inserting)
2121: insertStatement.setDate(columnIndex, x);
2122: else {
2123: checkUpdateFlagAndPrepareUpdateIfNeeded();
2124: updateStatement.setDate(columnIndex, x);
2125: }
2126:
2127: tempRow[columnIndex - 1] = x;
2128: }
2129:
2130: /**
2131: * JDBC 2.0 Update a column with a Time value. The updateXXX() methods are
2132: * used to update column values in the current row, or the insert row. The
2133: * updateXXX() methods do not update the underlying database, instead the
2134: * updateRow() or insertRow() methods are called to update the database.
2135: *
2136: * @param columnIndex the first column is 1, the second is 2, ...
2137: * @param x the new column value
2138: * @exception SQLException if a database-access error occurs
2139: */
2140: public void updateTime(int columnIndex, java.sql.Time x)
2141: throws SQLException {
2142: checkIfClosed();
2143:
2144: if (inserting)
2145: insertStatement.setTime(columnIndex, x);
2146: else {
2147: checkUpdateFlagAndPrepareUpdateIfNeeded();
2148: updateStatement.setTime(columnIndex, x);
2149: }
2150:
2151: tempRow[columnIndex - 1] = x;
2152: }
2153:
2154: /**
2155: * JDBC 2.0 Update a column with a Timestamp value. The updateXXX() methods
2156: * are used to update column values in the current row, or the insert row. The
2157: * updateXXX() methods do not update the underlying database, instead the
2158: * updateRow() or insertRow() methods are called to update the database.
2159: *
2160: * @param columnIndex the first column is 1, the second is 2, ...
2161: * @param x the new column value
2162: * @exception SQLException if a database-access error occurs
2163: */
2164: public void updateTimestamp(int columnIndex, java.sql.Timestamp x)
2165: throws SQLException {
2166: checkIfClosed();
2167:
2168: if (inserting)
2169: insertStatement.setTimestamp(columnIndex, x);
2170: else {
2171: checkUpdateFlagAndPrepareUpdateIfNeeded();
2172: updateStatement.setTimestamp(columnIndex, x);
2173: }
2174:
2175: tempRow[columnIndex - 1] = x;
2176: }
2177:
2178: /**
2179: * JDBC 2.0 Update a column with an ascii stream value. The updateXXX()
2180: * methods are used to update column values in the current row, or the insert
2181: * row. The updateXXX() methods do not update the underlying database, instead
2182: * the updateRow() or insertRow() methods are called to update the database.
2183: *
2184: * @param columnIndex the first column is 1, the second is 2, ...
2185: * @param x the new column value
2186: * @param length the length of the stream
2187: * @exception SQLException if a database-access error occurs
2188: */
2189: public void updateAsciiStream(int columnIndex,
2190: java.io.InputStream x, int length) throws SQLException {
2191: this .updateBinaryStream(columnIndex, x, length);
2192: }
2193:
2194: /**
2195: * JDBC 2.0 Update a column with a binary stream value. The updateXXX()
2196: * methods are used to update column values in the current row, or the insert
2197: * row. The updateXXX() methods do not update the underlying database, instead
2198: * the updateRow() or insertRow() methods are called to update the database.
2199: *
2200: * @param columnIndex the first column is 1, the second is 2, ...
2201: * @param x the new column value
2202: * @param length the length of the stream
2203: * @exception SQLException if a database-access error occurs
2204: */
2205: public void updateBinaryStream(int columnIndex,
2206: java.io.InputStream x, int length) throws SQLException {
2207: checkIfClosed();
2208:
2209: byte[] content = new byte[length];
2210: try {
2211: x.read(content, 0, length);
2212: } catch (Exception ioe) {
2213: throw new SQLException("Problem with streaming of data");
2214: }
2215:
2216: this .updateBytes(columnIndex, content);
2217: }
2218:
2219: /**
2220: * JDBC 2.0 Update a column with a character stream value. The updateXXX()
2221: * methods are used to update column values in the current row, or the insert
2222: * row. The updateXXX() methods do not update the underlying database, instead
2223: * the updateRow() or insertRow() methods are called to update the database.
2224: *
2225: * @param columnIndex the first column is 1, the second is 2, ...
2226: * @param x the new column value
2227: * @param length the length of the stream
2228: * @exception SQLException if a database-access error occurs
2229: */
2230: public void updateCharacterStream(int columnIndex,
2231: java.io.Reader x, int length) throws SQLException {
2232: checkIfClosed();
2233:
2234: char[] content = new char[length];
2235: try {
2236: x.read(content, 0, length);
2237: } catch (Exception ioe) {
2238: throw new SQLException("Problem with streaming of data");
2239: }
2240:
2241: this .updateString(columnIndex, new String(content));
2242: }
2243:
2244: /**
2245: * JDBC 2.0 Update a column with an Object value. The updateXXX() methods are
2246: * used to update column values in the current row, or the insert row. The
2247: * updateXXX() methods do not update the underlying database, instead the
2248: * updateRow() or insertRow() methods are called to update the database.
2249: *
2250: * @param columnIndex the first column is 1, the second is 2, ...
2251: * @param x the new column value
2252: * @param scale For java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types
2253: * this is the number of digits after the decimal. For all other
2254: * types this value will be ignored.
2255: * @exception SQLException if a database-access error occurs
2256: */
2257: public void updateObject(int columnIndex, Object x, int scale)
2258: throws SQLException {
2259: checkIfClosed();
2260:
2261: if (inserting)
2262: insertStatement.setObject(columnIndex, x, scale);
2263: else {
2264: checkUpdateFlagAndPrepareUpdateIfNeeded();
2265: updateStatement.setObject(columnIndex, x, scale);
2266: }
2267:
2268: tempRow[columnIndex - 1] = x;
2269: }
2270:
2271: /**
2272: * JDBC 2.0 Update a column with an Object value. The updateXXX() methods are
2273: * used to update column values in the current row, or the insert row. The
2274: * updateXXX() methods do not update the underlying database, instead the
2275: * updateRow() or insertRow() methods are called to update the database.
2276: *
2277: * @param columnIndex the first column is 1, the second is 2, ...
2278: * @param x the new column value
2279: * @exception SQLException if a database-access error occurs
2280: */
2281: public void updateObject(int columnIndex, Object x)
2282: throws SQLException {
2283: checkIfClosed();
2284:
2285: if (inserting)
2286: insertStatement.setObject(columnIndex, x);
2287: else {
2288: checkUpdateFlagAndPrepareUpdateIfNeeded();
2289: updateStatement.setObject(columnIndex, x);
2290: }
2291:
2292: tempRow[columnIndex - 1] = x;
2293: }
2294:
2295: /**
2296: * JDBC 2.0 Update a column with a null value. The updateXXX() methods are
2297: * used to update column values in the current row, or the insert row. The
2298: * updateXXX() methods do not update the underlying database, instead the
2299: * updateRow() or insertRow() methods are called to update the database.
2300: *
2301: * @param columnName the name of the column
2302: * @exception SQLException if a database-access error occurs
2303: */
2304:
2305: public void updateNull(String columnName) throws SQLException {
2306: this .updateNull(findColumn(columnName));
2307: }
2308:
2309: /**
2310: * JDBC 2.0 Update a column with a boolean value. The updateXXX() methods are
2311: * used to update column values in the current row, or the insert row. The
2312: * updateXXX() methods do not update the underlying database, instead the
2313: * updateRow() or insertRow() methods are called to update the database.
2314: *
2315: * @param columnName the name of the column
2316: * @param x the new column value
2317: * @exception SQLException if a database-access error occurs
2318: */
2319: public void updateBoolean(String columnName, boolean x)
2320: throws SQLException {
2321: this .updateBoolean(findColumn(columnName), x);
2322: }
2323:
2324: /**
2325: * JDBC 2.0 Update a column with a byte value. The updateXXX() methods are
2326: * used to update column values in the current row, or the insert row. The
2327: * updateXXX() methods do not update the underlying database, instead the
2328: * updateRow() or insertRow() methods are called to update the database.
2329: *
2330: * @param columnName the name of the column
2331: * @param x the new column value
2332: * @exception SQLException if a database-access error occurs
2333: */
2334: public void updateByte(String columnName, byte x)
2335: throws SQLException {
2336: this .updateByte(findColumn(columnName), x);
2337: }
2338:
2339: /**
2340: * JDBC 2.0 Update a column with a short value. The updateXXX() methods are
2341: * used to update column values in the current row, or the insert row. The
2342: * updateXXX() methods do not update the underlying database, instead the
2343: * updateRow() or insertRow() methods are called to update the database.
2344: *
2345: * @param columnName the name of the column
2346: * @param x the new column value
2347: * @exception SQLException if a database-access error occurs
2348: */
2349: public void updateShort(String columnName, short x)
2350: throws SQLException {
2351: this .updateShort(findColumn(columnName), x);
2352: }
2353:
2354: /**
2355: * JDBC 2.0 Update a column with an integer value. The updateXXX() methods are
2356: * used to update column values in the current row, or the insert row. The
2357: * updateXXX() methods do not update the underlying database, instead the
2358: * updateRow() or insertRow() methods are called to update the database.
2359: *
2360: * @param columnName the name of the column
2361: * @param x the new column value
2362: * @exception SQLException if a database-access error occurs
2363: */
2364: public void updateInt(String columnName, int x) throws SQLException {
2365: this .updateInt(findColumn(columnName), x);
2366: }
2367:
2368: /**
2369: * JDBC 2.0 Update a column with a long value. The updateXXX() methods are
2370: * used to update column values in the current row, or the insert row. The
2371: * updateXXX() methods do not update the underlying database, instead the
2372: * updateRow() or insertRow() methods are called to update the database.
2373: *
2374: * @param columnName the name of the column
2375: * @param x the new column value
2376: * @exception SQLException if a database-access error occurs
2377: */
2378: public void updateLong(String columnName, long x)
2379: throws SQLException {
2380: this .updateLong(findColumn(columnName), x);
2381: }
2382:
2383: /**
2384: * JDBC 2.0 Update a column with a float value. The updateXXX() methods are
2385: * used to update column values in the current row, or the insert row. The
2386: * updateXXX() methods do not update the underlying database, instead the
2387: * updateRow() or insertRow() methods are called to update the database.
2388: *
2389: * @param columnName the name of the column
2390: * @param x the new column value
2391: * @exception SQLException if a database-access error occurs
2392: */
2393: public void updateFloat(String columnName, float x)
2394: throws SQLException {
2395: this .updateFloat(findColumn(columnName), x);
2396: }
2397:
2398: /**
2399: * JDBC 2.0 Update a column with a double value. The updateXXX() methods are
2400: * used to update column values in the current row, or the insert row. The
2401: * updateXXX() methods do not update the underlying database, instead the
2402: * updateRow() or insertRow() methods are called to update the database.
2403: *
2404: * @param columnName the name of the column
2405: * @param x the new column value
2406: * @exception SQLException if a database-access error occurs
2407: */
2408: public void updateDouble(String columnName, double x)
2409: throws SQLException {
2410: this .updateDouble(findColumn(columnName), x);
2411: }
2412:
2413: /**
2414: * JDBC 2.0 Update a column with a BigDecimal value. The updateXXX() methods
2415: * are used to update column values in the current row, or the insert row. The
2416: * updateXXX() methods do not update the underlying database, instead the
2417: * updateRow() or insertRow() methods are called to update the database.
2418: *
2419: * @param columnName the name of the column
2420: * @param x the new column value
2421: * @exception SQLException if a database-access error occurs
2422: */
2423: public void updateBigDecimal(String columnName, BigDecimal x)
2424: throws SQLException {
2425: this .updateBigDecimal(findColumn(columnName), x);
2426: }
2427:
2428: /**
2429: * JDBC 2.0 Update a column with a String value. The updateXXX() methods are
2430: * used to update column values in the current row, or the insert row. The
2431: * updateXXX() methods do not update the underlying database, instead the
2432: * updateRow() or insertRow() methods are called to update the database.
2433: *
2434: * @param columnName the name of the column
2435: * @param x the new column value
2436: * @exception SQLException if a database-access error occurs
2437: */
2438: public void updateString(String columnName, String x)
2439: throws SQLException {
2440: this .updateString(findColumn(columnName), x);
2441: }
2442:
2443: /**
2444: * JDBC 2.0 Update a column with a byte array value. The updateXXX() methods
2445: * are used to update column values in the current row, or the insert row. The
2446: * updateXXX() methods do not update the underlying database, instead the
2447: * updateRow() or insertRow() methods are called to update the database.
2448: *
2449: * @param columnName the name of the column
2450: * @param x the new column value
2451: * @exception SQLException if a database-access error occurs
2452: */
2453: public void updateBytes(String columnName, byte[] x)
2454: throws SQLException {
2455: this .updateBytes(findColumn(columnName), x);
2456: }
2457:
2458: /**
2459: * JDBC 2.0 Update a column with a Date value. The updateXXX() methods are
2460: * used to update column values in the current row, or the insert row. The
2461: * updateXXX() methods do not update the underlying database, instead the
2462: * updateRow() or insertRow() methods are called to update the database.
2463: *
2464: * @param columnName the name of the column
2465: * @param x the new column value
2466: * @exception SQLException if a database-access error occurs
2467: */
2468: public void updateDate(String columnName, java.sql.Date x)
2469: throws SQLException {
2470: this .updateDate(findColumn(columnName), x);
2471: }
2472:
2473: /**
2474: * JDBC 2.0 Update a column with a Time value. The updateXXX() methods are
2475: * used to update column values in the current row, or the insert row. The
2476: * updateXXX() methods do not update the underlying database, instead the
2477: * updateRow() or insertRow() methods are called to update the database.
2478: *
2479: * @param columnName the name of the column
2480: * @param x the new column value
2481: * @exception SQLException if a database-access error occurs
2482: */
2483: public void updateTime(String columnName, java.sql.Time x)
2484: throws SQLException {
2485: this .updateTime(findColumn(columnName), x);
2486: }
2487:
2488: /**
2489: * JDBC 2.0 Update a column with a Timestamp value. The updateXXX() methods
2490: * are used to update column values in the current row, or the insert row. The
2491: * updateXXX() methods do not update the underlying database, instead the
2492: * updateRow() or insertRow() methods are called to update the database.
2493: *
2494: * @param columnName the name of the column
2495: * @param x the new column value
2496: * @exception SQLException if a database-access error occurs
2497: */
2498: public void updateTimestamp(String columnName, java.sql.Timestamp x)
2499: throws SQLException {
2500: this .updateTimestamp(findColumn(columnName), x);
2501: }
2502:
2503: /**
2504: * JDBC 2.0 Update a column with an ascii stream value. The updateXXX()
2505: * methods are used to update column values in the current row, or the insert
2506: * row. The updateXXX() methods do not update the underlying database, instead
2507: * the updateRow() or insertRow() methods are called to update the database.
2508: *
2509: * @param columnName the name of the column
2510: * @param x the new column value
2511: * @param length of the stream
2512: * @exception SQLException if a database-access error occurs
2513: */
2514: public void updateAsciiStream(String columnName,
2515: java.io.InputStream x, int length) throws SQLException {
2516: this .updateAsciiStream(findColumn(columnName), x, length);
2517: }
2518:
2519: /**
2520: * JDBC 2.0 Update a column with a binary stream value. The updateXXX()
2521: * methods are used to update column values in the current row, or the insert
2522: * row. The updateXXX() methods do not update the underlying database, instead
2523: * the updateRow() or insertRow() methods are called to update the database.
2524: *
2525: * @param columnName the name of the column
2526: * @param x the new column value
2527: * @param length of the stream
2528: * @exception SQLException if a database-access error occurs
2529: */
2530: public void updateBinaryStream(String columnName,
2531: java.io.InputStream x, int length) throws SQLException {
2532: this .updateBinaryStream(findColumn(columnName), x, length);
2533: }
2534:
2535: /**
2536: * JDBC 2.0 Update a column with a character stream value. The updateXXX()
2537: * methods are used to update column values in the current row, or the insert
2538: * row. The updateXXX() methods do not update the underlying database, instead
2539: * the updateRow() or insertRow() methods are called to update the database.
2540: *
2541: * @param columnName the name of the column
2542: * @param reader the stream
2543: * @param length of the stream
2544: * @exception SQLException if a database-access error occurs
2545: */
2546: public void updateCharacterStream(String columnName,
2547: java.io.Reader reader, int length) throws SQLException {
2548: this .updateCharacterStream(findColumn(columnName), reader,
2549: length);
2550: }
2551:
2552: /**
2553: * JDBC 2.0 Update a column with an Object value. The updateXXX() methods are
2554: * used to update column values in the current row, or the insert row. The
2555: * updateXXX() methods do not update the underlying database, instead the
2556: * updateRow() or insertRow() methods are called to update the database.
2557: *
2558: * @param columnName the name of the column
2559: * @param x the new column value
2560: * @param scale For java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types
2561: * this is the number of digits after the decimal. For all other
2562: * types this value will be ignored.
2563: * @exception SQLException if a database-access error occurs
2564: */
2565: public void updateObject(String columnName, Object x, int scale)
2566: throws SQLException {
2567: this .updateObject(findColumn(columnName), x, scale);
2568: }
2569:
2570: /**
2571: * JDBC 2.0 Update a column with an Object value. The updateXXX() methods are
2572: * used to update column values in the current row, or the insert row. The
2573: * updateXXX() methods do not update the underlying database, instead the
2574: * updateRow() or insertRow() methods are called to update the database.
2575: *
2576: * @param columnName the name of the column
2577: * @param x the new column value
2578: * @exception SQLException if a database-access error occurs
2579: */
2580: public void updateObject(String columnName, Object x)
2581: throws SQLException {
2582: this .updateObject(findColumn(columnName), x);
2583: }
2584:
2585: /**
2586: * JDBC 2.0 Insert the contents of the insert row into the result set and the
2587: * database. Must be on the insert row when this method is called.
2588: *
2589: * @exception SQLException if a database-access error occurs, if called when
2590: * not on the insert row, or if all non-nullable columns in the
2591: * insert row have not been given a value
2592: */
2593: public void insertRow() throws SQLException {
2594: checkIfClosed();
2595:
2596: if (!inserting)
2597: throw new SQLException("insertRow cannot be called "
2598: + "when the cursor is not on the insert row");
2599:
2600: // Insert row in underlying database
2601: try {
2602: insertStatement.executeUpdate();
2603: } finally {
2604: // Clean up
2605: insertStatement.clearParameters();
2606: }
2607:
2608: // Insert row in this ResultSet
2609: if (data == null)
2610: data = new ArrayList();
2611: data.add(tempRow);
2612: nbOfRows++;
2613:
2614: // Prepare for a new insert
2615: tempRow = new Object[nbOfColumns];
2616: }
2617:
2618: /**
2619: * JDBC 2.0 Update the underlying database with the new contents of the
2620: * current row. Cannot be called when on the insert row.
2621: *
2622: * @exception SQLException if a database-access error occurs, or if called
2623: * when on the insert row
2624: */
2625: public void updateRow() throws SQLException {
2626: checkIfClosed();
2627:
2628: if (inserting)
2629: throw new SQLException("updateRow cannot be called "
2630: + "when the cursor is on the insert row");
2631:
2632: if (!updating)
2633: return;
2634:
2635: // Add primary key info from current row
2636: for (int i = 0; i < primaryKeyColumns.length; ++i)
2637: updateStatement
2638: .setObject(
2639: nbOfColumns + i + 1,
2640: ((Object[]) data.get(currentRow))[findColumn(primaryKeyColumns[i]) - 1]);
2641:
2642: // Update row in underlying database
2643: try {
2644: updateStatement.executeUpdate();
2645: } finally {
2646: // Clean up
2647: updateStatement.clearParameters();
2648: }
2649:
2650: // Update row in this ResultSet
2651: data.set(currentRow, tempRow);
2652:
2653: // Clean up
2654: tempRow = null;
2655: updating = false;
2656: }
2657:
2658: /**
2659: * JDBC 2.0 Delete the current row from the result set and the underlying
2660: * database. Cannot be called when on the insert row.
2661: *
2662: * @exception SQLException if a database-access error occurs, or if called
2663: * when on the insert row.
2664: */
2665: public void deleteRow() throws SQLException {
2666: checkIfClosed();
2667:
2668: if (inserting)
2669: throw new SQLException("deleteRow cannot be called "
2670: + "when the cursor is on the insert row");
2671:
2672: this .checkRowPos();
2673:
2674: if (deleteStatement == null)
2675: this .buildDeleteStatement();
2676:
2677: // Add primary key info from current row
2678: for (int i = 0; i < primaryKeyColumns.length; ++i)
2679: deleteStatement
2680: .setObject(
2681: i + 1,
2682: ((Object[]) data.get(currentRow))[findColumn(primaryKeyColumns[i]) - 1]);
2683:
2684: // Delete row from underlying database
2685: try {
2686: deleteStatement.executeUpdate();
2687: } finally {
2688: // Clean up
2689: deleteStatement.clearParameters();
2690: }
2691:
2692: // Delete row from this ResultSet
2693: data.remove(currentRow);
2694: nbOfRows--;
2695:
2696: // Deleting cancels all updates on the row
2697: if (updating)
2698: this .cancelRowUpdates();
2699: }
2700:
2701: /**
2702: * JDBC 2.0 Refresh the value of the current row with its current value in the
2703: * database. Cannot be called when on the insert row. The refreshRow() method
2704: * provides a way for an application to explicitly tell the JDBC driver to
2705: * refetch a row(s) from the database. An application may want to call
2706: * refreshRow() when caching or prefetching is being done by the JDBC driver
2707: * to fetch the latest value of a row from the database. The JDBC driver may
2708: * actually refresh multiple rows at once if the fetch size is greater than
2709: * one. All values are refetched subject to the transaction isolation level
2710: * and cursor sensitivity. If refreshRow() is called after calling
2711: * updateXXX(), but before calling updateRow() then the updates made to the
2712: * row are lost. Calling refreshRow() frequently will likely slow performance.
2713: *
2714: * @exception SQLException if a database-access error occurs, or if called
2715: * when on the insert row.
2716: */
2717: public void refreshRow() throws SQLException {
2718: checkIfClosed();
2719:
2720: if (inserting)
2721: throw new SQLException("refreshRow cannot be called "
2722: + "when the cursor is on the insert row");
2723:
2724: this .checkRowPos();
2725:
2726: if (refreshStatement == null)
2727: this .buildRefreshStatement();
2728:
2729: // Add primary key info from current row
2730: for (int i = 0; i < primaryKeyColumns.length; ++i)
2731: refreshStatement
2732: .setObject(
2733: i + 1,
2734: ((Object[]) data.get(currentRow))[findColumn(primaryKeyColumns[i]) - 1]);
2735:
2736: // Retrieve row from underlying database
2737: DriverResultSet res;
2738: try {
2739: res = (DriverResultSet) refreshStatement.executeQuery();
2740: } finally {
2741: // Clean up
2742: refreshStatement.clearParameters();
2743: }
2744:
2745: // Refresh row in this ResultSet
2746: try {
2747: data.set(currentRow, res.data.get(0));
2748: } catch (NullPointerException e) {
2749: throw new SQLException("The current row has been "
2750: + "removed from the database");
2751: } finally {
2752: // Clean up
2753: res.close();
2754: }
2755:
2756: // Refreshing cancels all updates on the row
2757: if (updating)
2758: this .cancelRowUpdates();
2759: }
2760:
2761: /**
2762: * JDBC 2.0 The cancelRowUpdates() method may be called after calling an
2763: * updateXXX() method(s) and before calling updateRow() to rollback the
2764: * updates made to a row. If no updates have been made or updateRow() has
2765: * already been called, then this method has no effect.
2766: *
2767: * @exception SQLException if a database-access error occurs, or if called
2768: * when on the insert row.
2769: */
2770: public void cancelRowUpdates() throws SQLException {
2771: checkIfClosed();
2772:
2773: if (inserting)
2774: throw new SQLException("cancelRowUpdates cannot be "
2775: + "called when the cursor is on the insert row");
2776:
2777: if (!updating)
2778: return;
2779:
2780: updateStatement.clearParameters();
2781: tempRow = null;
2782: updating = false;
2783: }
2784:
2785: /**
2786: * JDBC 2.0 Move to the insert row. The current cursor position is remembered
2787: * while the cursor is positioned on the insert row. The insert row is a
2788: * special row associated with an updatable result set. It is essentially a
2789: * buffer where a new row may be constructed by calling the updateXXX()
2790: * methods prior to inserting the row into the result set. Only the
2791: * updateXXX(), getXXX(), and insertRow() methods may be called when the
2792: * cursor is on the insert row. All of the columns in a result set must be
2793: * given a value each time this method is called before calling insertRow().
2794: * UpdateXXX()must be called before getXXX() on a column.
2795: *
2796: * @exception SQLException if a database-access error occurs, or the result
2797: * set is not updatable
2798: */
2799: public void moveToInsertRow() throws SQLException {
2800: checkIfClosed();
2801:
2802: if (inserting)
2803: return;
2804:
2805: if (insertStatement == null)
2806: this .buildInsertStatement();
2807:
2808: tempRow = new Object[nbOfColumns];
2809: inserting = true;
2810: }
2811:
2812: /**
2813: * JDBC 2.0 Move the cursor to the remembered cursor position, usually the
2814: * current row. Has no effect unless the cursor is on the insert row.
2815: *
2816: * @exception SQLException if a database-access error occurs, or the result
2817: * set is not updatable
2818: */
2819: public void moveToCurrentRow() throws SQLException {
2820: checkIfClosed();
2821:
2822: if (!inserting)
2823: return;
2824:
2825: insertStatement.clearParameters();
2826: tempRow = null;
2827: inserting = false;
2828: }
2829:
2830: //
2831: // ------------------------------------------
2832: // ResultSet meta-data related functions
2833: // ------------------------------------------
2834: //
2835:
2836: /**
2837: * JDBC 2.0 Return the type of this result set. The type is determined based
2838: * on the statement that created the result set.
2839: *
2840: * @return TYPE_FORWARD_ONLY, TYPE_SCROLL_INSENSITIVE, or
2841: * TYPE_SCROLL_SENSITIVE
2842: * @exception SQLException if a database-access error occurs
2843: */
2844: public int getType() throws SQLException {
2845: return resultSetType;
2846: }
2847:
2848: /**
2849: * JDBC 2.0 Return the concurrency of this result set. The concurrency used is
2850: * determined by the statement that created the result set.
2851: *
2852: * @return CONCUR_READ_ONLY or CONCUR_UPDATABLE
2853: * @exception SQLException if a database-access error occurs
2854: */
2855:
2856: public int getConcurrency() throws SQLException {
2857: return resultSetConcurrency;
2858: }
2859:
2860: /**
2861: * Closes the remote ResultSet if the ResultSet was streamed else just closes
2862: * the ResultSet locally.
2863: *
2864: * @exception SQLException if a database access error occurs
2865: */
2866: public void close() throws SQLException {
2867: if (isClosed)
2868: return;
2869:
2870: closeCurrentStreamIfExists();
2871:
2872: if (hasMoreData)
2873: this .connection.closeRemoteResultSet(cursorName);
2874: isClosed = true;
2875: // garbage collect some data
2876: this .data = null;
2877: this .fields = null;
2878: this .owningStatement = null;
2879: this .warnings = null;
2880: }
2881:
2882: /**
2883: * A column may have the value of SQL NULL; wasNull() reports whether the last
2884: * column read had this special value. Note that you must first call getXXX on
2885: * a column to try to read its value and then call wasNull() to find if the
2886: * value was SQL NULL
2887: *
2888: * @return <code>true</code> if the last column read was SQL NULL
2889: * @exception SQLException if a database access error occurred
2890: */
2891:
2892: public boolean wasNull() throws SQLException {
2893: return wasNullFlag;
2894: }
2895:
2896: /**
2897: * JDBC 2.0 Return the <code>Statement</code> that produced the
2898: * <code>ResultSet</code>.
2899: *
2900: * @return the <code>Statement</code> that produced the
2901: * <code>ResultSet</code>, or null if the result was produced some
2902: * other way.
2903: * @exception SQLException if a database-access error occurs
2904: */
2905: public java.sql.Statement getStatement() throws SQLException {
2906: return owningStatement;
2907: }
2908:
2909: /**
2910: * Set the hasMoreData boolean (is there more data to fetch from the
2911: * controller). This function is used by the ResultSet streaming feature.
2912: *
2913: * @param hasMore new value for hasMoreData
2914: */
2915: public void setHasMoreData(boolean hasMore) {
2916: hasMoreData = hasMore;
2917: }
2918:
2919: /**
2920: * The numbers, types and properties of a <code>ResultSet</code>'s columns
2921: * are provided by the <code>getMetaData</code> method
2922: *
2923: * @return a description of the <code>ResultSet</code>'s columns
2924: * @exception SQLException if a database access error occurs
2925: */
2926: public java.sql.ResultSetMetaData getMetaData() throws SQLException {
2927: return new ResultSetMetaData(this );
2928: }
2929:
2930: /**
2931: * Map a <code>ResultSet</code> column name to a <code>ResultSet</code>
2932: * column index
2933: *
2934: * @param columnName the name of the column
2935: * @return the column index
2936: * @exception SQLException if a database access error occurs
2937: */
2938: public int findColumn(String columnName) throws SQLException {
2939: if (columnName == null)
2940: throw new java.sql.SQLException("Invalid null column name");
2941:
2942: checkIfClosed();
2943:
2944: Integer index;
2945:
2946: // Try to match the exact case (not per the spec!)
2947: if (sensitiveNameToIndex == null) {
2948: sensitiveNameToIndex = new Hashtable();
2949: buildIndexMapping(sensitiveNameToIndex, true);
2950: }
2951: index = (Integer) sensitiveNameToIndex.get(columnName);
2952: if (index != null)
2953: return index.intValue() + 1;
2954:
2955: // Try to be case-insensitive (according to the spec)
2956: if (lowerNameToIndex == null) {
2957: lowerNameToIndex = new Hashtable();
2958: buildIndexMapping(lowerNameToIndex, false);
2959: }
2960: index = (Integer) lowerNameToIndex
2961: .get(columnName.toLowerCase());
2962: if (index != null)
2963: return index.intValue() + 1;
2964:
2965: // nothing found
2966: throw new java.sql.SQLException("Column '" + columnName
2967: + "' not found.");
2968: }
2969:
2970: // ****************************************************************
2971: //
2972: // END OF PUBLIC INTERFACE
2973: //
2974: // ****************************************************************
2975:
2976: /**
2977: * Creates a new <code>DriverResultSet</code> object, deserializing it from
2978: * an input stream. MUST mirror the following serialization method
2979: * {@link org.continuent.sequoia.controller.backend.result.ControllerResultSet#sendToStream(org.continuent.sequoia.common.stream.DriverBufferedOutputStream)}
2980: *
2981: * @param conn the connection we read from and belong to
2982: * @throws IOException if a network problem occurs
2983: * @throws ProtocolException if a protocol error occurs
2984: */
2985:
2986: public DriverResultSet(Connection conn) throws IOException,
2987: ProtocolException {
2988: this .connection = conn;
2989: DriverBufferedInputStream input = this .connection.socketInput;
2990: // Get the warning chain
2991: if (input.readBoolean()) {
2992: warnings = new BackendDriverException(input);
2993: } else
2994: warnings = null;
2995: // Get the ResultSet metadata, deserialize columns information
2996: this .nbOfColumns = input.readInt();
2997: this .fields = new Field[nbOfColumns];
2998: for (int f = 0; f < this .nbOfColumns; f++)
2999: this .fields[f] = new Field(input);
3000:
3001: if (!TypeTag.COL_TYPES.equals(new TypeTag(input)))
3002: throw new ProtocolException("Column types were expected");
3003:
3004: // This could be just a boolean, see next line. But there is no real need
3005: // for change.
3006: this .nbOfRows = input.readInt();
3007:
3008: // Receive java types
3009: if (this .nbOfRows > 0) {
3010: this .serializers = new SQLDataSerialization.Serializer[nbOfColumns];
3011: for (int col = 0; col < this .nbOfColumns; col++) {
3012: TypeTag tag = new TypeTag(input);
3013: try {
3014: serializers[col] = SQLDataSerialization
3015: .getSerializer(tag);
3016: } catch (IllegalArgumentException iae) {
3017: ProtocolException pe = new ProtocolException(
3018: "Protocol corruption: received unknown TypeTag "
3019: + tag + " for column " + col);
3020: pe.initCause(iae);
3021: throw pe;
3022: }
3023: }
3024: }
3025:
3026: receiveRows();
3027:
3028: if (this .hasMoreData)
3029: this .cursorName = input.readLongUTF();
3030:
3031: this .isClosed = false;
3032:
3033: }
3034:
3035: /**
3036: * Creates a new empty <code>DriverResultSet</code> object
3037: *
3038: * @param empty MUST be true
3039: */
3040: DriverResultSet(Connection conn, boolean empty) {
3041: if (!empty)
3042: throw new IllegalArgumentException(
3043: "empty flag must be true in DriverResultSet constructor");
3044:
3045: connection = conn;
3046: inserting = false;
3047: updating = false;
3048: nbOfRows = 0;
3049: nbOfColumns = 0;
3050: hasMoreData = false;
3051: isClosed = false;
3052: }
3053:
3054: /**
3055: * Tells the controller we don't need this ResultSet anymore (ie. closes the
3056: * remote ResultSet)
3057: *
3058: * @see #close()
3059: */
3060: protected void finalize() throws Throwable {
3061: this .close();
3062: super .finalize();
3063: }
3064:
3065: /**
3066: * Creates a new <code>DriverResultSet</code> object with given data
3067: * (currently only supports one column, because it is used only to support
3068: * generated keys on batch update, when alwaysGetGeneratedKeys is set to true)
3069: *
3070: * @param conn
3071: * @param fromData List of objects to be inserted in this resultset
3072: * @param fromField Metadata for this colum
3073: */
3074: public DriverResultSet(Connection conn, ArrayList fromData,
3075: Field fromField) {
3076: this (conn, true);
3077: if (fromData != null && fromData.size() > 0) {
3078: nbOfRows = fromData.size();
3079: nbOfColumns = 1;
3080: hasMoreData = false;
3081: this .data = new ArrayList(this .nbOfRows);
3082: for (int i = 0; i < nbOfRows; i++) {
3083: Object[] row = new Object[nbOfColumns];
3084: row[0] = fromData.get(i);
3085: this .data.add(row);
3086: }
3087: this .fields = new Field[1];
3088: this .fields[0] = fromField;
3089: }
3090: }
3091:
3092: /**
3093: * De-serialize only data rows, not any metadata. Useful for streaming. This
3094: * method MUST mirror the following serialization method:
3095: * {@link org.continuent.sequoia.controller.backend.result.ControllerResultSet#sendRowsToStream(org.continuent.sequoia.common.stream.DriverBufferedOutputStream)}
3096: *
3097: * @throws IOException stream error
3098: * @throws ProtocolException protocol corruption
3099: */
3100: private void receiveRows() throws IOException, ProtocolException {
3101:
3102: DriverBufferedInputStream input = connection.socketInput;
3103: this .nbOfRows = input.readInt();
3104:
3105: boolean[] nulls = new boolean[this .nbOfColumns];
3106:
3107: // Receive the actual data
3108: this .data = new ArrayList(this .nbOfRows);
3109:
3110: for (int r = 0; r < this .nbOfRows; r++) {
3111: if (!TypeTag.ROW.equals(new TypeTag(input)))
3112: throw new ProtocolException("A row was expected");
3113:
3114: // First let's flag null values using a burst of booleans
3115: // TODO: we should compress this
3116: for (int col = 0; col < nbOfColumns; col++)
3117: nulls[col] = input.readBoolean();
3118:
3119: Object[] row = new Object[this .nbOfColumns];
3120:
3121: /**
3122: * Here we are sure that serializers are initialized because:
3123: * <p>
3124: * (1) we went through {@link #DriverResultSet(Connection)} at least once
3125: * before
3126: * <p>
3127: * (2) and there was a non-zero ResultSet transfered, else we would not
3128: * come here again.
3129: */
3130: for (int col = 0; col < this .nbOfColumns; col++)
3131: if (nulls[col])
3132: row[col] = null;
3133: else
3134: row[col] = serializers[col]
3135: .receiveFromStream(input);
3136:
3137: this .data.add(row);
3138: }
3139:
3140: this .hasMoreData = input.readBoolean();
3141: }
3142:
3143: /**
3144: * Set the statement.
3145: *
3146: * @param stmt The statement to set
3147: * @throws SQLException if an error occurs
3148: */
3149: protected void setStatement(Statement stmt) throws SQLException {
3150: owningStatement = stmt;
3151: fetchSize = stmt.getFetchSize();
3152: resultSetConcurrency = stmt.getResultSetConcurrency();
3153: resultSetType = stmt.getResultSetType();
3154: }
3155:
3156: /**
3157: * Builds a hash between column names and their indices for fast retrieval. An
3158: * earlier name or label currently preempts any later name or label. This
3159: * looks compliant with the 3.0 spec and 4.0 draft.
3160: */
3161: private void buildIndexMapping(Hashtable table, boolean sensitive) {
3162: int numFields = nbOfColumns;
3163:
3164: for (int i = 0; i < numFields; i++) {
3165: // pgjdbc and MySQL connector/J < 5 make no difference between name and
3166: // label. See SEQUOIA-746 and SEQUOIA-218
3167: putFieldNameInIndexMapping(fields[i].getFieldLabel(), i,
3168: sensitive, table);
3169: putFieldNameInIndexMapping(fields[i].getFieldName(), i,
3170: sensitive, table);
3171:
3172: /*
3173: * Add the fully qualified name in any case. It is fully qualified and
3174: * guaranteed, therefore, not to be a duplicate unless it really is the
3175: * same column in the same table ...
3176: */
3177: putFieldNameInIndexMapping(fields[i].getFullName(), i,
3178: sensitive, table);
3179: }
3180: }
3181:
3182: private void putFieldNameInIndexMapping(String name, int i,
3183: boolean sensitive, Hashtable table) {
3184: if ((name == null) || "".equals(name))
3185: return;
3186:
3187: Integer index = new Integer(i);
3188:
3189: String key = sensitive ? name : name.toLowerCase();
3190:
3191: if (!table.containsKey(key))
3192: table.put(key, index);
3193: }
3194:
3195: /**
3196: * Builds a delete statement for deleting rows with Updatable ResultSets
3197: *
3198: * @throws SQLException
3199: */
3200: private void buildDeleteStatement() throws SQLException {
3201: // Check that ResultSet can be updated
3202: this .checkUpdatability();
3203:
3204: // Build delete statement for this ResultSet
3205: StringBuffer sb = new StringBuffer();
3206: sb.append("DELETE FROM ");
3207: sb.append(fields[0].getTableName());
3208: sb.append(" WHERE ");
3209: for (int i = 0; i < primaryKeyColumns.length; ++i) {
3210: if (i > 0)
3211: sb.append(" AND ");
3212: sb.append(primaryKeyColumns[i]);
3213: sb.append(" = ?");
3214: }
3215:
3216: // set delete statement
3217: deleteStatement = this .connection.prepareStatement(sb
3218: .toString());
3219: }
3220:
3221: /**
3222: * Builds a insert statement for inserting rows with Updatable ResultSets
3223: *
3224: * @throws SQLException
3225: */
3226: private void buildInsertStatement() throws SQLException {
3227: // Check that ResultSet can be updated
3228: this .checkUpdatability();
3229:
3230: // Build insert statement for this ResultSet
3231: StringBuffer sb = new StringBuffer();
3232: sb.append("INSERT INTO ");
3233: sb.append(fields[0].getTableName());
3234: sb.append(" (");
3235: for (int i = 0; i < fields.length; ++i) {
3236: if (i > 0)
3237: sb.append(", ");
3238: sb.append(fields[i].getFieldName());
3239: }
3240: sb.append(") VALUES (");
3241: for (int i = 0; i < fields.length; ++i) {
3242: if (i > 0)
3243: sb.append(", ");
3244: sb.append("?");
3245: }
3246: sb.append(")");
3247:
3248: // set insert statement
3249: insertStatement = this .connection.prepareStatement(sb
3250: .toString());
3251: }
3252:
3253: /**
3254: * Builds a select statement for refreshing rows in Updatable ResultSets
3255: *
3256: * @throws SQLException
3257: */
3258: private void buildRefreshStatement() throws SQLException {
3259: // Check that ResultSet can be updated
3260: this .checkUpdatability();
3261:
3262: // Build refresh statement for this ResultSet
3263: StringBuffer sb = new StringBuffer();
3264: sb.append("SELECT ");
3265: for (int i = 0; i < fields.length; ++i) {
3266: if (i > 0)
3267: sb.append(", ");
3268: sb.append(fields[i].getFieldName());
3269: }
3270: sb.append(" FROM ");
3271: sb.append(fields[0].getTableName());
3272: sb.append(" WHERE ");
3273: for (int i = 0; i < primaryKeyColumns.length; ++i) {
3274: if (i > 0)
3275: sb.append(" AND ");
3276: sb.append(primaryKeyColumns[i]);
3277: sb.append(" = ?");
3278: }
3279:
3280: // set refresh statement
3281: refreshStatement = this .connection.prepareStatement(sb
3282: .toString());
3283: }
3284:
3285: /**
3286: * Builds an update statement for updating rows with Updatable ResultSets
3287: *
3288: * @throws SQLException
3289: */
3290: private void buildUpdateStatement() throws SQLException {
3291: // Check that ResultSet can be updated
3292: this .checkUpdatability();
3293:
3294: // Build update statement for this ResultSet
3295: StringBuffer sb = new StringBuffer();
3296: sb.append("UPDATE ");
3297: sb.append(fields[0].getTableName());
3298: sb.append(" SET ");
3299: for (int i = 0; i < fields.length; ++i) {
3300: if (i > 0)
3301: sb.append(", ");
3302: sb.append(fields[i].getFieldName());
3303: sb.append(" = ?");
3304: }
3305: sb.append(" WHERE ");
3306: for (int i = 0; i < primaryKeyColumns.length; ++i) {
3307: if (i > 0)
3308: sb.append(" AND ");
3309: sb.append(primaryKeyColumns[i]);
3310: sb.append(" = ?");
3311: }
3312:
3313: // set update statement
3314: updateStatement = this .connection.prepareStatement(sb
3315: .toString());
3316: }
3317:
3318: /**
3319: * Retrieves the primary key for the table referenced by this ResultSet
3320: *
3321: * @throws SQLException
3322: */
3323: private void extractPrimaryKey() throws SQLException {
3324: // sanity check
3325: if (fields[0].getTableName() == null
3326: || fields[0].getTableName().length() == 0)
3327: throw new SQLException(
3328: "Could not extractPrimaryKeys: empty tablename");
3329:
3330: ResultSet res = this .connection.getPrimaryKeys(null, null,
3331: fields[0].getTableName());
3332:
3333: try {
3334: primaryKeyColumns = new String[((DriverResultSet) res).nbOfRows];
3335: while (res.next())
3336: primaryKeyColumns[res.getRow() - 1] = res.getString(4);
3337: } finally {
3338: // Clean up
3339: res.close();
3340: }
3341: }
3342:
3343: /**
3344: * Basic checks for Updatable ResultSets
3345: *
3346: * @throws SQLException
3347: */
3348: private void checkUpdatability() throws SQLException {
3349: // Check ResultSet Concurrency type
3350: switch (resultSetConcurrency) {
3351: case ResultSet.CONCUR_READ_ONLY:
3352: throw new SQLException("Cannot update ResultSet with "
3353: + "concurrency mode CONCUR_READ_ONLY");
3354: case ResultSet.CONCUR_UPDATABLE:
3355: break;
3356: default:
3357: throw new SQLException(
3358: "Invalid ResultSet concurrency mode: "
3359: + resultSetConcurrency);
3360: }
3361:
3362: // Check that the query selects only one table
3363: String tableName = fields[0].getTableName();
3364: for (int i = 1; i < nbOfColumns; ++i)
3365: if (!tableName.equals(fields[i].getTableName()))
3366: throw new SQLException(UPDATEABLE_MESSAGE);
3367:
3368: // Check if need to get primary keys
3369: if (primaryKeyColumns == null)
3370: this .extractPrimaryKey();
3371:
3372: // Check that the query selects the full primary key
3373: for (int i = 0; i < primaryKeyColumns.length; ++i)
3374: try {
3375: findColumn(primaryKeyColumns[i]);
3376: } catch (SQLException e) {
3377: throw new SQLException(UPDATEABLE_MESSAGE);
3378: }
3379: }
3380:
3381: /**
3382: * Sanity checks for result parsing
3383: *
3384: * @param columnIndex the column to check
3385: * @throws SQLException if an error occurs
3386: */
3387: private void checkRowAndColPosAndSetNullFlag(int columnIndex)
3388: throws SQLException {
3389: checkIfClosed();
3390:
3391: closeCurrentStreamIfExists();
3392:
3393: if (!inserting)
3394: checkRowPos();
3395:
3396: if (fields == null)
3397: throw new java.sql.SQLException(
3398: "Query generated no fields for ResultSet");
3399:
3400: if (columnIndex < 1 || columnIndex > nbOfColumns)
3401: throw new java.sql.SQLException(
3402: "Column Index out of range ( " + columnIndex
3403: + " > " + nbOfColumns + ").");
3404:
3405: try {
3406: Object obj;
3407: if (inserting || updating)
3408: obj = tempRow[columnIndex - 1];
3409: else
3410: obj = ((Object[]) data.get(currentRow))[columnIndex - 1];
3411:
3412: if (obj == null)
3413: wasNullFlag = true;
3414: else
3415: wasNullFlag = false;
3416: } catch (NullPointerException e) {
3417: wasNullFlag = true;
3418: }
3419: }
3420:
3421: /**
3422: * Checks that the cursor is on row in the ResultSet
3423: *
3424: * @throws SQLException
3425: */
3426: private void checkRowPos() throws SQLException {
3427: if (currentRow < 0)
3428: throw new SQLException("Before start of result set");
3429:
3430: if (currentRow == nbOfRows)
3431: throw new SQLException("After end of result set");
3432: }
3433:
3434: /**
3435: * Checks that the update flag is set when updating a row. The first time an
3436: * update is done on a row this method will prepare the ResultSet for update
3437: *
3438: * @throws SQLException
3439: */
3440: private void checkUpdateFlagAndPrepareUpdateIfNeeded()
3441: throws SQLException {
3442: if (updating)
3443: return;
3444:
3445: this .checkRowPos();
3446:
3447: if (updateStatement == null)
3448: this .buildUpdateStatement();
3449:
3450: tempRow = (Object[]) ((Object[]) data.get(currentRow)).clone();
3451:
3452: for (int i = 0; i < nbOfColumns; ++i)
3453: updateStatement.setObject(i + 1, tempRow[i]);
3454:
3455: updating = true;
3456: }
3457:
3458: /**
3459: * Check if the ResultSet if closed and throws a SQLException if so.
3460: *
3461: * @throws SQLException if the ResultSet is closed
3462: */
3463: private void checkIfClosed() throws SQLException {
3464: if (isClosed)
3465: throw new SQLException(
3466: "Trying to access a closed ResultSet");
3467: }
3468:
3469: /**
3470: * Check if the ResultSet can be scrolled.
3471: *
3472: * @throws SQLException if the ResultSet is closed or if its type is
3473: * TYPE_FORWARD_ONLY.
3474: */
3475: private void checkIfScrollable() throws SQLException {
3476: checkIfClosed();
3477: if (resultSetType == ResultSet.TYPE_FORWARD_ONLY) {
3478: throw new SQLException(
3479: "Operation requires a scrollable ResultSet, but this ResultSet is FORWARD_ONLY");
3480: }
3481: }
3482:
3483: /**
3484: * Close a previously created input stream if needed.
3485: */
3486: private void closeCurrentStreamIfExists() {
3487: if (currentStream != null) {
3488: try {
3489: // since we use only ByteArrayInputStreams for now, this is a no-op.
3490: currentStream.close();
3491: } catch (IOException ignore) {
3492: } finally {
3493: currentStream = null;
3494: }
3495: }
3496: }
3497:
3498: // -------------------------- JDBC 3.0
3499: // ----------------------------------------
3500:
3501: /**
3502: * Retrieves the value of the designated column in the current row of this
3503: * <code>ResultSet</code> object as a <code>java.net.URL</code> object in
3504: * the Java programming language.
3505: *
3506: * @param columnIndex the index of the column 1 is the first, 2 is the
3507: * second,...
3508: * @return the column value as a <code>java.net.URL</code> object; if the
3509: * value is SQL <code>NULL</code>, the value returned is
3510: * <code>null</code> in the Java programming language
3511: * @exception SQLException if a database access error occurs, or if a URL is
3512: * malformed
3513: * @since JDK 1.4
3514: */
3515: public java.net.URL getURL(int columnIndex) throws SQLException {
3516: checkRowAndColPosAndSetNullFlag(columnIndex);
3517:
3518: if (wasNullFlag)
3519: return null;
3520:
3521: if (inserting || updating)
3522: return (URL) tempRow[columnIndex - 1];
3523: else
3524: return (URL) (((Object[]) data.get(currentRow))[columnIndex - 1]);
3525: }
3526:
3527: /**
3528: * Retrieves the value of the designated column in the current row of this
3529: * <code>ResultSet</code> object as a <code>java.net.URL</code> object in
3530: * the Java programming language.
3531: *
3532: * @param columnName the SQL name of the column
3533: * @return the column value as a <code>java.net.URL</code> object; if the
3534: * value is SQL <code>NULL</code>, the value returned is
3535: * <code>null</code> in the Java programming language
3536: * @exception SQLException if a database access error occurs or if a URL is
3537: * malformed
3538: * @since JDK 1.4
3539: */
3540: public java.net.URL getURL(String columnName) throws SQLException {
3541: return getURL(findColumn(columnName));
3542: }
3543:
3544: /**
3545: * Updates the designated column with a <code>java.sql.Ref</code> value. The
3546: * updater methods are used to update column values in the current row or the
3547: * insert row. The updater methods do not update the underlying database;
3548: * instead the <code>updateRow</code> or <code>insertRow</code> methods
3549: * are called to update the database.
3550: *
3551: * @param columnIndex the first column is 1, the second is 2, ...
3552: * @param x the new column value
3553: * @exception SQLException if a database access error occurs
3554: * @since JDK 1.4
3555: */
3556: public void updateRef(int columnIndex, java.sql.Ref x)
3557: throws SQLException {
3558: throw new NotImplementedException("updateRef");
3559: }
3560:
3561: /**
3562: * Updates the designated column with a <code>java.sql.Ref</code> value. The
3563: * updater methods are used to update column values in the current row or the
3564: * insert row. The updater methods do not update the underlying database;
3565: * instead the <code>updateRow</code> or <code>insertRow</code> methods
3566: * are called to update the database.
3567: *
3568: * @param columnName the name of the column
3569: * @param x the new column value
3570: * @exception SQLException if a database access error occurs
3571: * @since JDK 1.4
3572: */
3573: public void updateRef(String columnName, java.sql.Ref x)
3574: throws SQLException {
3575: updateRef(findColumn(columnName), x);
3576: }
3577:
3578: /**
3579: * Updates the designated column with a <code>java.sql.Blob</code> value.
3580: * The updater methods are used to update column values in the current row or
3581: * the insert row. The updater methods do not update the underlying database;
3582: * instead the <code>updateRow</code> or <code>insertRow</code> methods
3583: * are called to update the database.
3584: *
3585: * @param columnIndex the first column is 1, the second is 2, ...
3586: * @param x the new column value
3587: * @exception SQLException if a database access error occurs
3588: * @since JDK 1.4
3589: */
3590: public void updateBlob(int columnIndex, java.sql.Blob x)
3591: throws SQLException {
3592: throw new NotImplementedException("updateBlob");
3593: }
3594:
3595: /**
3596: * Updates the designated column with a <code>java.sql.Blob</code> value.
3597: * The updater methods are used to update column values in the current row or
3598: * the insert row. The updater methods do not update the underlying database;
3599: * instead the <code>updateRow</code> or <code>insertRow</code> methods
3600: * are called to update the database.
3601: *
3602: * @param columnName the name of the column
3603: * @param x the new column value
3604: * @exception SQLException if a database access error occurs
3605: * @since JDK 1.4
3606: */
3607: public void updateBlob(String columnName, java.sql.Blob x)
3608: throws SQLException {
3609: updateBlob(findColumn(columnName), x);
3610: }
3611:
3612: /**
3613: * Updates the designated column with a <code>java.sql.Clob</code> value.
3614: * The updater methods are used to update column values in the current row or
3615: * the insert row. The updater methods do not update the underlying database;
3616: * instead the <code>updateRow</code> or <code>insertRow</code> methods
3617: * are called to update the database.
3618: *
3619: * @param columnIndex the first column is 1, the second is 2, ...
3620: * @param x the new column value
3621: * @exception SQLException if a database access error occurs
3622: * @since JDK 1.4
3623: */
3624: public void updateClob(int columnIndex, java.sql.Clob x)
3625: throws SQLException {
3626: throw new NotImplementedException("updateClob");
3627: }
3628:
3629: /**
3630: * Updates the designated column with a <code>java.sql.Clob</code> value.
3631: * The updater methods are used to update column values in the current row or
3632: * the insert row. The updater methods do not update the underlying database;
3633: * instead the <code>updateRow</code> or <code>insertRow</code> methods
3634: * are called to update the database.
3635: *
3636: * @param columnName the name of the column
3637: * @param x the new column value
3638: * @exception SQLException if a database access error occurs
3639: * @since JDK 1.4
3640: */
3641: public void updateClob(String columnName, java.sql.Clob x)
3642: throws SQLException {
3643: updateClob(findColumn(columnName), x);
3644: }
3645:
3646: /**
3647: * Updates the designated column with a <code>java.sql.Array</code> value.
3648: * The updater methods are used to update column values in the current row or
3649: * the insert row. The updater methods do not update the underlying database;
3650: * instead the <code>updateRow</code> or <code>insertRow</code> methods
3651: * are called to update the database.
3652: *
3653: * @param columnIndex the first column is 1, the second is 2, ...
3654: * @param x the new column value
3655: * @exception SQLException if a database access error occurs
3656: * @since JDK 1.4
3657: */
3658: public void updateArray(int columnIndex, java.sql.Array x)
3659: throws SQLException {
3660: throw new NotImplementedException("updateArray");
3661: }
3662:
3663: /**
3664: * Updates the designated column with a <code>java.sql.Array</code> value.
3665: * The updater methods are used to update column values in the current row or
3666: * the insert row. The updater methods do not update the underlying database;
3667: * instead the <code>updateRow</code> or <code>insertRow</code> methods
3668: * are called to update the database.
3669: *
3670: * @param columnName the name of the column
3671: * @param x the new column value
3672: * @exception SQLException if a database access error occurs
3673: * @since JDK 1.4
3674: */
3675: public void updateArray(String columnName, java.sql.Array x)
3676: throws SQLException {
3677: updateArray(findColumn(columnName), x);
3678: }
3679:
3680: /**
3681: * Get the value of a column in the current row as a Java byte.
3682: *
3683: * @param columnIndex the first column is 1, the second is 2,...
3684: * @return the column value; 0 if SQL NULL
3685: * @exception SQLException if a database access error occurs
3686: */
3687: public byte getByte(int columnIndex) throws SQLException {
3688: checkRowAndColPosAndSetNullFlag(columnIndex);
3689:
3690: if (wasNullFlag)
3691: return 0;
3692:
3693: Object obj;
3694: if (inserting || updating)
3695: obj = tempRow[columnIndex - 1];
3696: else
3697: obj = ((Object[]) data.get(currentRow))[columnIndex - 1];
3698:
3699: if (obj instanceof Number) {
3700: return ((Number) obj).byteValue();
3701: }
3702:
3703: // the object is not of type number we parse the string representation
3704: try {
3705: String string = obj.toString();
3706: string = string.trim();
3707: return Byte.parseByte(string);
3708: } catch (NumberFormatException e) {
3709: throw new SQLException("the value " + obj.toString()
3710: + " is not a valid byte");
3711: }
3712: }
3713:
3714: /**
3715: * @see java.lang.Object#toString()
3716: */
3717: public String toString() {
3718: return nbOfRows + " rows - " + nbOfColumns
3719: + " columns - current row:" + currentRow
3720: + " - hasMoreData:" + hasMoreData + " - isClosed:"
3721: + isClosed;
3722: }
3723: }
|