0001: // jTDS JDBC Driver for Microsoft SQL Server and Sybase
0002: // Copyright (C) 2004 The jTDS Project
0003: //
0004: // This library is free software; you can redistribute it and/or
0005: // modify it under the terms of the GNU Lesser General Public
0006: // License as published by the Free Software Foundation; either
0007: // version 2.1 of the License, or (at your option) any later version.
0008: //
0009: // This library is distributed in the hope that it will be useful,
0010: // but WITHOUT ANY WARRANTY; without even the implied warranty of
0011: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0012: // Lesser General Public License for more details.
0013: //
0014: // You should have received a copy of the GNU Lesser General Public
0015: // License along with this library; if not, write to the Free Software
0016: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0017: //
0018: package net.sourceforge.jtds.jdbc;
0019:
0020: import java.io.InputStream;
0021: import java.io.Reader;
0022: import java.math.BigDecimal;
0023: import java.net.URL;
0024: import java.net.MalformedURLException;
0025: import java.sql.Array;
0026: import java.sql.Blob;
0027: import java.sql.Clob;
0028: import java.sql.Date;
0029: import java.sql.Ref;
0030: import java.sql.ResultSet;
0031: import java.sql.ResultSetMetaData;
0032: import java.sql.SQLException;
0033: import java.sql.SQLWarning;
0034: import java.sql.Statement;
0035: import java.sql.Time;
0036: import java.sql.Timestamp;
0037: import java.sql.Types;
0038: import java.util.Calendar;
0039: import java.util.HashMap;
0040: import java.util.Map;
0041: import java.util.ArrayList;
0042: import java.text.NumberFormat;
0043: import java.io.UnsupportedEncodingException;
0044: import java.io.InputStreamReader;
0045:
0046: /**
0047: * jTDS Implementation of the java.sql.ResultSet interface supporting forward read
0048: * only result sets.
0049: * <p>
0050: * Implementation notes:
0051: * <ol>
0052: * <li>This class is also the base for more sophisticated result sets and
0053: * incorporates the update methods required by them.
0054: * <li>The class supports the BLOB/CLOB objects added by Brian.
0055: * </ol>
0056: *
0057: * @author Mike Hutchinson
0058: * @version $Id: JtdsResultSet.java,v 1.46 2005/09/26 18:21:09 ddkilzer Exp $
0059: */
0060: public class JtdsResultSet implements ResultSet {
0061: /*
0062: * Constants for backwards compatibility with JDK 1.3
0063: */
0064: static final int HOLD_CURSORS_OVER_COMMIT = 1;
0065: static final int CLOSE_CURSORS_AT_COMMIT = 2;
0066:
0067: protected static final int POS_BEFORE_FIRST = 0;
0068: protected static final int POS_AFTER_LAST = -1;
0069:
0070: /** Initial size for row array. */
0071: protected static final int INITIAL_ROW_COUNT = 1000;
0072:
0073: /*
0074: * Protected Instance variables.
0075: */
0076: /** The current row number. */
0077: protected int pos = POS_BEFORE_FIRST;
0078: /** The number of rows in the result. */
0079: protected int rowsInResult;
0080: /** The fetch direction. */
0081: protected int direction = FETCH_FORWARD;
0082: /** The result set type. */
0083: protected int resultSetType;
0084: /** The result set concurrency. */
0085: protected int concurrency;
0086: /** Number of visible columns in row. */
0087: protected int columnCount;
0088: /** The array of column descriptors. */
0089: protected ColInfo[] columns;
0090: /** The current result set row. */
0091: protected Object[] currentRow;
0092: /** Cached row data for forward only result set. */
0093: protected ArrayList rowData;
0094: /** Index of current row in rowData. */
0095: protected int rowPtr;
0096: /** True if last column retrieved was null. */
0097: protected boolean wasNull;
0098: /** The parent statement. */
0099: protected JtdsStatement statement;
0100: /** True if this result set is closed. */
0101: protected boolean closed;
0102: /** True if the query has been cancelled by another thread. */
0103: protected boolean cancelled;
0104: /** The fetch direction. */
0105: protected int fetchDirection = FETCH_FORWARD;
0106: /** The fetch size (only applies to cursor <code>ResultSet</code>s). */
0107: protected int fetchSize;
0108: /** The cursor name to be used for positioned updates. */
0109: protected String cursorName;
0110: /** Cache to optimize findColumn(String) lookups */
0111: private HashMap columnMap;
0112:
0113: /*
0114: * Private instance variables.
0115: */
0116: /** Used to format numeric values when scale is specified. */
0117: private static NumberFormat f = NumberFormat.getInstance();
0118:
0119: /**
0120: * Construct a simple result set from a statement, metadata or generated keys.
0121: *
0122: * @param statement The parent statement object or null.
0123: * @param resultSetType one of FORWARD_ONLY, SCROLL_INSENSITIVE, SCROLL_SENSITIVE.
0124: * @param concurrency One of CONCUR_READ_ONLY, CONCUR_UPDATE.
0125: * @param columns The array of column descriptors for the result set row.
0126: * @throws SQLException
0127: */
0128: JtdsResultSet(JtdsStatement statement, int resultSetType,
0129: int concurrency, ColInfo[] columns) throws SQLException {
0130: if (statement == null) {
0131: throw new IllegalArgumentException(
0132: "Statement parameter must not be null");
0133: }
0134: this .statement = statement;
0135: this .resultSetType = resultSetType;
0136: this .concurrency = concurrency;
0137: this .columns = columns;
0138: this .fetchSize = statement.fetchSize;
0139: this .fetchDirection = statement.fetchDirection;
0140: this .cursorName = statement.cursorName;
0141:
0142: if (columns != null) {
0143: columnCount = getColumnCount(columns);
0144: rowsInResult = (statement.getTds().isDataInResultSet()) ? 1
0145: : 0;
0146: }
0147: }
0148:
0149: /**
0150: * Retrieve the column count excluding hidden columns
0151: *
0152: * @param columns The columns array
0153: * @return The new column count as an <code>int</code>.
0154: */
0155: protected static int getColumnCount(ColInfo[] columns) {
0156: // MJH - Modified to cope with more than one hidden column
0157: int i;
0158: for (i = columns.length - 1; i >= 0 && columns[i].isHidden; i--)
0159: ;
0160: return i + 1;
0161: }
0162:
0163: /**
0164: * Retrieve the column descriptor array.
0165: *
0166: * @return The column descriptors as a <code>ColInfo[]</code>.
0167: */
0168: protected ColInfo[] getColumns() {
0169: return this .columns;
0170: }
0171:
0172: /**
0173: * Set the specified column's name.
0174: *
0175: * @param colIndex The index of the column in the row.
0176: * @param name The new name.
0177: */
0178: protected void setColName(int colIndex, String name) {
0179: if (colIndex < 1 || colIndex > columns.length) {
0180: throw new IllegalArgumentException("columnIndex "
0181: + colIndex + " invalid");
0182: }
0183:
0184: columns[colIndex - 1].realName = name;
0185: }
0186:
0187: /**
0188: * Set the specified column's label.
0189: *
0190: * @param colIndex The index of the column in the row.
0191: * @param name The new label.
0192: */
0193: protected void setColLabel(int colIndex, String name) {
0194: if (colIndex < 1 || colIndex > columns.length) {
0195: throw new IllegalArgumentException("columnIndex "
0196: + colIndex + " invalid");
0197: }
0198:
0199: columns[colIndex - 1].name = name;
0200: }
0201:
0202: /**
0203: * Set the specified column's JDBC type.
0204: *
0205: * @param colIndex The index of the column in the row.
0206: * @param jdbcType The new type value.
0207: */
0208: protected void setColType(int colIndex, int jdbcType) {
0209: if (colIndex < 1 || colIndex > columns.length) {
0210: throw new IllegalArgumentException("columnIndex "
0211: + colIndex + " invalid");
0212: }
0213:
0214: columns[colIndex - 1].jdbcType = jdbcType;
0215: }
0216:
0217: /**
0218: * Set the specified column's data value.
0219: *
0220: * @param colIndex index of the column
0221: * @param value new column value
0222: * @param length the length of a stream parameter
0223: * @return the value, possibly converted to an internal type
0224: */
0225: protected Object setColValue(int colIndex, int jdbcType,
0226: Object value, int length) throws SQLException {
0227: checkOpen();
0228: checkUpdateable();
0229: if (colIndex < 1 || colIndex > columnCount) {
0230: throw new SQLException(Messages.get(
0231: "error.resultset.colindex", Integer
0232: .toString(colIndex)), "07009");
0233: }
0234: //
0235: // Convert java date/time objects to internal DateTime objects
0236: //
0237: if (value instanceof java.sql.Timestamp) {
0238: value = new DateTime((java.sql.Timestamp) value);
0239: } else if (value instanceof java.sql.Date) {
0240: value = new DateTime((java.sql.Date) value);
0241: } else if (value instanceof java.sql.Time) {
0242: value = new DateTime((java.sql.Time) value);
0243: }
0244:
0245: return value;
0246: }
0247:
0248: /**
0249: * Set the current row's column count.
0250: *
0251: * @param columnCount The number of visible columns in the row.
0252: */
0253: protected void setColumnCount(int columnCount) {
0254: if (columnCount < 1 || columnCount > columns.length) {
0255: throw new IllegalArgumentException("columnCount "
0256: + columnCount + " is invalid");
0257: }
0258:
0259: this .columnCount = columnCount;
0260: }
0261:
0262: /**
0263: * Get the specified column's data item.
0264: *
0265: * @param index the column index in the row
0266: * @return the column value as an <code>Object</code>
0267: * @throws SQLException if the connection is closed;
0268: * if <code>index</code> is less than <code>1</code>;
0269: * if <code>index</code> is greater that the number of columns;
0270: * if there is no current row
0271: */
0272: protected Object getColumn(int index) throws SQLException {
0273: checkOpen();
0274:
0275: if (index < 1 || index > columnCount) {
0276: throw new SQLException(Messages
0277: .get("error.resultset.colindex", Integer
0278: .toString(index)), "07009");
0279: }
0280:
0281: if (currentRow == null) {
0282: throw new SQLException(Messages
0283: .get("error.resultset.norow"), "24000");
0284: }
0285:
0286: Object data = currentRow[index - 1];
0287:
0288: wasNull = data == null;
0289:
0290: return data;
0291: }
0292:
0293: /**
0294: * Check that this connection is still open.
0295: *
0296: * @throws SQLException if connection closed.
0297: */
0298: protected void checkOpen() throws SQLException {
0299: if (closed) {
0300: throw new SQLException(Messages.get("error.generic.closed",
0301: "ResultSet"), "HY010");
0302: }
0303:
0304: if (cancelled) {
0305: throw new SQLException(Messages.get(
0306: "error.generic.cancelled", "ResultSet"), "HY010");
0307: }
0308: }
0309:
0310: /**
0311: * Check that this resultset is scrollable.
0312: *
0313: * @throws SQLException if connection closed.
0314: */
0315: protected void checkScrollable() throws SQLException {
0316: if (resultSetType == ResultSet.TYPE_FORWARD_ONLY) {
0317: throw new SQLException(Messages
0318: .get("error.resultset.fwdonly"), "24000");
0319: }
0320: }
0321:
0322: /**
0323: * Check that this resultset is updateable.
0324: *
0325: * @throws SQLException if connection closed.
0326: */
0327: protected void checkUpdateable() throws SQLException {
0328: if (concurrency == ResultSet.CONCUR_READ_ONLY) {
0329: throw new SQLException(Messages
0330: .get("error.resultset.readonly"), "24000");
0331: }
0332: }
0333:
0334: /**
0335: * Report that user tried to call a method which has not been implemented.
0336: *
0337: * @param method The method name to report in the error message.
0338: * @throws SQLException
0339: */
0340: protected static void notImplemented(String method)
0341: throws SQLException {
0342: throw new SQLException(Messages.get("error.generic.notimp",
0343: method), "HYC00");
0344: }
0345:
0346: /**
0347: * Create a new row containing empty data items.
0348: *
0349: * @return the new row as an <code>Object</code> array
0350: */
0351: protected Object[] newRow() {
0352: Object row[] = new Object[columns.length];
0353:
0354: return row;
0355: }
0356:
0357: /**
0358: * Copy an existing result set row.
0359: *
0360: * @param row the result set row to copy
0361: * @return the new row as an <code>Object</code> array
0362: */
0363: protected Object[] copyRow(Object[] row) {
0364: Object copy[] = new Object[columns.length];
0365:
0366: System.arraycopy(row, 0, copy, 0, row.length);
0367:
0368: return copy;
0369: }
0370:
0371: /**
0372: * Copy an existing result set column descriptor array.
0373: *
0374: * @param info The result set column descriptors to copy.
0375: * @return The new descriptors as a <code>ColInfo[]</code>.
0376: */
0377: protected ColInfo[] copyInfo(ColInfo[] info) {
0378: ColInfo copy[] = new ColInfo[info.length];
0379:
0380: System.arraycopy(info, 0, copy, 0, info.length);
0381:
0382: return copy;
0383: }
0384:
0385: /**
0386: * Retrieve the current row data.
0387: * @return The current row data as an <code>Object[]</code>.
0388: */
0389: protected Object[] getCurrentRow() {
0390: return this .currentRow;
0391: }
0392:
0393: /**
0394: * Cache the remaining results to free up connection.
0395: * @throws SQLException
0396: */
0397: protected void cacheResultSetRows() throws SQLException {
0398: if (rowData == null) {
0399: rowData = new ArrayList(INITIAL_ROW_COUNT);
0400: }
0401: if (currentRow != null) {
0402: // Need to create local copy of currentRow
0403: // as this is currently a reference to the
0404: // row defined in TdsCore
0405: currentRow = copyRow(currentRow);
0406: }
0407: //
0408: // Now load the remaining result set rows into memory
0409: //
0410: while (statement.getTds().getNextRow()) {
0411: rowData.add(copyRow(statement.getTds().getRowData()));
0412: }
0413: // Allow statement to process output vars etc
0414: statement.cacheResults();
0415: }
0416:
0417: /**
0418: * Returns the {@link ConnectionJDBC2} object referenced by the
0419: * {@link #statement} instance variable.
0420: *
0421: * @return {@link ConnectionJDBC2} object.
0422: * @throws SQLException on error.
0423: */
0424: private ConnectionJDBC2 getConnection() throws SQLException {
0425: return (ConnectionJDBC2) statement.getConnection();
0426: }
0427:
0428: //
0429: // -------------------- java.sql.ResultSet methods -------------------
0430: //
0431: public int getConcurrency() throws SQLException {
0432: checkOpen();
0433:
0434: return this .concurrency;
0435: }
0436:
0437: public int getFetchDirection() throws SQLException {
0438: checkOpen();
0439:
0440: return this .fetchDirection;
0441: }
0442:
0443: public int getFetchSize() throws SQLException {
0444: checkOpen();
0445:
0446: return fetchSize;
0447: }
0448:
0449: public int getRow() throws SQLException {
0450: checkOpen();
0451:
0452: return pos > 0 ? pos : 0;
0453: }
0454:
0455: public int getType() throws SQLException {
0456: checkOpen();
0457:
0458: return resultSetType;
0459: }
0460:
0461: public void afterLast() throws SQLException {
0462: checkOpen();
0463: checkScrollable();
0464: }
0465:
0466: public void beforeFirst() throws SQLException {
0467: checkOpen();
0468: checkScrollable();
0469: }
0470:
0471: public void cancelRowUpdates() throws SQLException {
0472: checkOpen();
0473: checkUpdateable();
0474: }
0475:
0476: public void clearWarnings() throws SQLException {
0477: checkOpen();
0478:
0479: statement.clearWarnings();
0480: }
0481:
0482: public void close() throws SQLException {
0483: if (!closed) {
0484: try {
0485: if (!getConnection().isClosed()) {
0486: // Skip to end of result set
0487: // Could send cancel but this is safer as
0488: // cancel could kill other statements in a batch.
0489: while (next())
0490: ;
0491: }
0492: } finally {
0493: closed = true;
0494: statement = null;
0495: }
0496: }
0497: }
0498:
0499: public void deleteRow() throws SQLException {
0500: checkOpen();
0501: checkUpdateable();
0502: }
0503:
0504: public void insertRow() throws SQLException {
0505: checkOpen();
0506: checkUpdateable();
0507: }
0508:
0509: public void moveToCurrentRow() throws SQLException {
0510: checkOpen();
0511: checkUpdateable();
0512: }
0513:
0514: public void moveToInsertRow() throws SQLException {
0515: checkOpen();
0516: checkUpdateable();
0517: }
0518:
0519: public void refreshRow() throws SQLException {
0520: checkOpen();
0521: checkUpdateable();
0522: }
0523:
0524: public void updateRow() throws SQLException {
0525: checkOpen();
0526: checkUpdateable();
0527: }
0528:
0529: public boolean first() throws SQLException {
0530: checkOpen();
0531: checkScrollable();
0532:
0533: return false;
0534: }
0535:
0536: public boolean isAfterLast() throws SQLException {
0537: checkOpen();
0538:
0539: return (pos == POS_AFTER_LAST) && (rowsInResult != 0);
0540: }
0541:
0542: public boolean isBeforeFirst() throws SQLException {
0543: checkOpen();
0544:
0545: return (pos == POS_BEFORE_FIRST) && (rowsInResult != 0);
0546: }
0547:
0548: public boolean isFirst() throws SQLException {
0549: checkOpen();
0550:
0551: return pos == 1;
0552: }
0553:
0554: public boolean isLast() throws SQLException {
0555: checkOpen();
0556:
0557: if (statement.getTds().isDataInResultSet()) {
0558: rowsInResult = pos + 1; // Keep rowsInResult 1 ahead of pos
0559: }
0560:
0561: return (pos == rowsInResult) && (rowsInResult != 0);
0562: }
0563:
0564: public boolean last() throws SQLException {
0565: checkOpen();
0566: checkScrollable();
0567:
0568: return false;
0569: }
0570:
0571: public boolean next() throws SQLException {
0572: checkOpen();
0573:
0574: if (pos == POS_AFTER_LAST) {
0575: // Make sure nothing will happen after the end has been reached
0576: return false;
0577: }
0578:
0579: if (rowData != null) {
0580: // The rest of the result rows have been cached so
0581: // return the next row from the buffer.
0582: if (rowPtr < rowData.size()) {
0583: currentRow = (Object[]) rowData.get(rowPtr);
0584: // This is a forward only result set so null out the buffer ref
0585: // to allow for garbage collection (we can never access the row
0586: // again once we have moved on).
0587: rowData.set(rowPtr++, null);
0588: pos++;
0589: rowsInResult = pos;
0590: } else {
0591: pos = POS_AFTER_LAST;
0592: currentRow = null;
0593: }
0594: } else {
0595: // Need to read from server response
0596: if (!statement.getTds().getNextRow()) {
0597: statement.cacheResults();
0598: pos = POS_AFTER_LAST;
0599: currentRow = null;
0600: } else {
0601: currentRow = statement.getTds().getRowData();
0602: pos++;
0603: rowsInResult = pos;
0604: }
0605: }
0606:
0607: // Check for server side errors
0608: statement.getMessages().checkErrors();
0609:
0610: return currentRow != null;
0611: }
0612:
0613: public boolean previous() throws SQLException {
0614: checkOpen();
0615: checkScrollable();
0616:
0617: return false;
0618: }
0619:
0620: public boolean rowDeleted() throws SQLException {
0621: checkOpen();
0622: checkUpdateable();
0623:
0624: return false;
0625: }
0626:
0627: public boolean rowInserted() throws SQLException {
0628: checkOpen();
0629: checkUpdateable();
0630:
0631: return false;
0632: }
0633:
0634: public boolean rowUpdated() throws SQLException {
0635: checkOpen();
0636: checkUpdateable();
0637:
0638: return false;
0639: }
0640:
0641: public boolean wasNull() throws SQLException {
0642: checkOpen();
0643:
0644: return wasNull;
0645: }
0646:
0647: public byte getByte(int columnIndex) throws SQLException {
0648: return ((Integer) Support.convert(this , getColumn(columnIndex),
0649: java.sql.Types.TINYINT, null)).byteValue();
0650: }
0651:
0652: public double getDouble(int columnIndex) throws SQLException {
0653: return ((Double) Support.convert(this , getColumn(columnIndex),
0654: java.sql.Types.DOUBLE, null)).doubleValue();
0655: }
0656:
0657: public float getFloat(int columnIndex) throws SQLException {
0658: return ((Float) Support.convert(this , getColumn(columnIndex),
0659: java.sql.Types.REAL, null)).floatValue();
0660: }
0661:
0662: public int getInt(int columnIndex) throws SQLException {
0663: return ((Integer) Support.convert(this , getColumn(columnIndex),
0664: java.sql.Types.INTEGER, null)).intValue();
0665: }
0666:
0667: public long getLong(int columnIndex) throws SQLException {
0668: return ((Long) Support.convert(this , getColumn(columnIndex),
0669: java.sql.Types.BIGINT, null)).longValue();
0670: }
0671:
0672: public short getShort(int columnIndex) throws SQLException {
0673: return ((Integer) Support.convert(this , getColumn(columnIndex),
0674: java.sql.Types.SMALLINT, null)).shortValue();
0675: }
0676:
0677: public void setFetchDirection(int direction) throws SQLException {
0678: checkOpen();
0679: switch (direction) {
0680: case FETCH_UNKNOWN:
0681: case FETCH_REVERSE:
0682: if (this .resultSetType == ResultSet.TYPE_FORWARD_ONLY) {
0683: throw new SQLException(Messages
0684: .get("error.resultset.fwdonly"), "24000");
0685: }
0686: // Fall through
0687:
0688: case FETCH_FORWARD:
0689: this .fetchDirection = direction;
0690: break;
0691:
0692: default:
0693: throw new SQLException(Messages.get(
0694: "error.generic.badoption", Integer
0695: .toString(direction), "direction"), "24000");
0696: }
0697: }
0698:
0699: public void setFetchSize(int rows) throws SQLException {
0700: checkOpen();
0701:
0702: if (rows < 0
0703: || (statement.getMaxRows() > 0 && rows > statement
0704: .getMaxRows())) {
0705: throw new SQLException(Messages.get(
0706: "error.generic.badparam", Integer.toString(rows),
0707: "rows"), "HY092");
0708: }
0709: if (rows == 0) {
0710: rows = statement.getDefaultFetchSize();
0711: }
0712: this .fetchSize = rows;
0713: }
0714:
0715: public void updateNull(int columnIndex) throws SQLException {
0716: setColValue(columnIndex, Types.NULL, null, 0);
0717: }
0718:
0719: public boolean absolute(int row) throws SQLException {
0720: checkOpen();
0721: checkScrollable();
0722: return false;
0723: }
0724:
0725: public boolean getBoolean(int columnIndex) throws SQLException {
0726: return ((Boolean) Support.convert(this , getColumn(columnIndex),
0727: JtdsStatement.BOOLEAN, null)).booleanValue();
0728: }
0729:
0730: public boolean relative(int row) throws SQLException {
0731: checkOpen();
0732: checkScrollable();
0733: return false;
0734: }
0735:
0736: public byte[] getBytes(int columnIndex) throws SQLException {
0737: checkOpen();
0738: return (byte[]) Support.convert(this , getColumn(columnIndex),
0739: java.sql.Types.BINARY, getConnection().getCharset());
0740: }
0741:
0742: public void updateByte(int columnIndex, byte x) throws SQLException {
0743: setColValue(columnIndex, Types.INTEGER, new Integer(x & 0xFF),
0744: 0);
0745: }
0746:
0747: public void updateDouble(int columnIndex, double x)
0748: throws SQLException {
0749: setColValue(columnIndex, Types.DOUBLE, new Double(x), 0);
0750: }
0751:
0752: public void updateFloat(int columnIndex, float x)
0753: throws SQLException {
0754: setColValue(columnIndex, Types.REAL, new Float(x), 0);
0755: }
0756:
0757: public void updateInt(int columnIndex, int x) throws SQLException {
0758: setColValue(columnIndex, Types.INTEGER, new Integer(x), 0);
0759: }
0760:
0761: public void updateLong(int columnIndex, long x) throws SQLException {
0762: setColValue(columnIndex, Types.BIGINT, new Long(x), 0);
0763: }
0764:
0765: public void updateShort(int columnIndex, short x)
0766: throws SQLException {
0767: setColValue(columnIndex, Types.INTEGER, new Integer(x), 0);
0768: }
0769:
0770: public void updateBoolean(int columnIndex, boolean x)
0771: throws SQLException {
0772: setColValue(columnIndex, Types.BIT, x ? Boolean.TRUE
0773: : Boolean.FALSE, 0);
0774: }
0775:
0776: public void updateBytes(int columnIndex, byte[] x)
0777: throws SQLException {
0778: setColValue(columnIndex, Types.VARBINARY, x,
0779: (x != null) ? x.length : 0);
0780: }
0781:
0782: public InputStream getAsciiStream(int columnIndex)
0783: throws SQLException {
0784: Clob clob = getClob(columnIndex);
0785:
0786: if (clob == null) {
0787: return null;
0788: }
0789:
0790: return clob.getAsciiStream();
0791: }
0792:
0793: public InputStream getBinaryStream(int columnIndex)
0794: throws SQLException {
0795: Blob blob = getBlob(columnIndex);
0796:
0797: if (blob == null) {
0798: return null;
0799: }
0800:
0801: return blob.getBinaryStream();
0802: }
0803:
0804: public InputStream getUnicodeStream(int columnIndex)
0805: throws SQLException {
0806: ClobImpl clob = (ClobImpl) getClob(columnIndex);
0807:
0808: if (clob == null) {
0809: return null;
0810: }
0811:
0812: return clob.getBlobBuffer().getUnicodeStream();
0813: }
0814:
0815: public void updateAsciiStream(int columnIndex,
0816: InputStream inputStream, int length) throws SQLException {
0817: if (inputStream == null || length < 0) {
0818: updateCharacterStream(columnIndex, null, 0);
0819: } else {
0820: try {
0821: updateCharacterStream(columnIndex,
0822: new InputStreamReader(inputStream, "US-ASCII"),
0823: length);
0824: } catch (UnsupportedEncodingException e) {
0825: // Should never happen!
0826: }
0827: }
0828: }
0829:
0830: public void updateBinaryStream(int columnIndex,
0831: InputStream inputStream, int length) throws SQLException {
0832:
0833: if (inputStream == null || length < 0) {
0834: updateBytes(columnIndex, null);
0835: return;
0836: }
0837:
0838: setColValue(columnIndex, java.sql.Types.VARBINARY, inputStream,
0839: length);
0840: }
0841:
0842: public Reader getCharacterStream(int columnIndex)
0843: throws SQLException {
0844: Clob clob = getClob(columnIndex);
0845:
0846: if (clob == null) {
0847: return null;
0848: }
0849:
0850: return clob.getCharacterStream();
0851: }
0852:
0853: public void updateCharacterStream(int columnIndex, Reader reader,
0854: int length) throws SQLException {
0855:
0856: if (reader == null || length < 0) {
0857: updateString(columnIndex, null);
0858: return;
0859: }
0860:
0861: setColValue(columnIndex, java.sql.Types.VARCHAR, reader, length);
0862: }
0863:
0864: public Object getObject(int columnIndex) throws SQLException {
0865: Object value = getColumn(columnIndex);
0866:
0867: // Don't return UniqueIdentifier objects as the user won't know how to
0868: // handle them
0869: if (value instanceof UniqueIdentifier) {
0870: return value.toString();
0871: }
0872: // Don't return DateTime objects as the user won't know how to
0873: // handle them
0874: if (value instanceof DateTime) {
0875: return ((DateTime) value).toObject();
0876: }
0877: // If the user requested String/byte[] instead of LOBs, do the conversion
0878: if (!getConnection().getUseLOBs()) {
0879: value = Support.convertLOB(value);
0880: }
0881:
0882: return value;
0883: }
0884:
0885: public void updateObject(int columnIndex, Object x)
0886: throws SQLException {
0887: checkOpen();
0888: int length = 0;
0889: int jdbcType = Types.VARCHAR; // Use for NULL values
0890:
0891: if (x != null) {
0892: // Need to do some conversion and testing here
0893: jdbcType = Support.getJdbcType(x);
0894: if (x instanceof BigDecimal) {
0895: int prec = getConnection().getMaxPrecision();
0896: x = Support.normalizeBigDecimal((BigDecimal) x, prec);
0897: } else if (x instanceof Blob) {
0898: Blob blob = (Blob) x;
0899: x = blob.getBinaryStream();
0900: length = (int) blob.length();
0901: } else if (x instanceof Clob) {
0902: Clob clob = (Clob) x;
0903: x = clob.getCharacterStream();
0904: length = (int) clob.length();
0905: } else if (x instanceof String) {
0906: length = ((String) x).length();
0907: } else if (x instanceof byte[]) {
0908: length = ((byte[]) x).length;
0909: }
0910: if (jdbcType == Types.JAVA_OBJECT) {
0911: // Unsupported class of object
0912: if (columnIndex < 1 || columnIndex > columnCount) {
0913: throw new SQLException(Messages.get(
0914: "error.resultset.colindex", Integer
0915: .toString(columnIndex)), "07009");
0916: }
0917: ColInfo ci = columns[columnIndex - 1];
0918: throw new SQLException(Messages.get(
0919: "error.convert.badtypes", x.getClass()
0920: .getName(), Support
0921: .getJdbcTypeName(ci.jdbcType)), "22005");
0922: }
0923: }
0924:
0925: setColValue(columnIndex, jdbcType, x, length);
0926: }
0927:
0928: public void updateObject(int columnIndex, Object x, int scale)
0929: throws SQLException {
0930: checkOpen();
0931: if (scale < 0 || scale > getConnection().getMaxPrecision()) {
0932: throw new SQLException(Messages
0933: .get("error.generic.badscale"), "HY092");
0934: }
0935:
0936: if (x instanceof BigDecimal) {
0937: updateObject(columnIndex, ((BigDecimal) x).setScale(scale,
0938: BigDecimal.ROUND_HALF_UP));
0939: } else if (x instanceof Number) {
0940: synchronized (f) {
0941: f.setGroupingUsed(false);
0942: f.setMaximumFractionDigits(scale);
0943: updateObject(columnIndex, f.format(x));
0944: }
0945: } else {
0946: updateObject(columnIndex, x);
0947: }
0948: }
0949:
0950: public String getCursorName() throws SQLException {
0951: checkOpen();
0952: if (cursorName != null) {
0953: return this .cursorName;
0954: }
0955: throw new SQLException(Messages
0956: .get("error.resultset.noposupdate"), "24000");
0957: }
0958:
0959: public String getString(int columnIndex) throws SQLException {
0960: Object tmp = getColumn(columnIndex);
0961:
0962: if (tmp instanceof String) {
0963: return (String) tmp;
0964: }
0965: return (String) Support.convert(this , tmp,
0966: java.sql.Types.VARCHAR, getConnection().getCharset());
0967: }
0968:
0969: public void updateString(int columnIndex, String x)
0970: throws SQLException {
0971: setColValue(columnIndex, Types.VARCHAR, x, (x != null) ? x
0972: .length() : 0);
0973: }
0974:
0975: public byte getByte(String columnName) throws SQLException {
0976: return getByte(findColumn(columnName));
0977: }
0978:
0979: public double getDouble(String columnName) throws SQLException {
0980: return getDouble(findColumn(columnName));
0981: }
0982:
0983: public float getFloat(String columnName) throws SQLException {
0984: return getFloat(findColumn(columnName));
0985: }
0986:
0987: public int findColumn(String columnName) throws SQLException {
0988: checkOpen();
0989:
0990: if (columnMap == null) {
0991: columnMap = new HashMap(columnCount);
0992: } else {
0993: Object pos = columnMap.get(columnName);
0994: if (pos != null) {
0995: return ((Integer) pos).intValue();
0996: }
0997: }
0998:
0999: // Rather than use toUpperCase()/toLowerCase(), which are costly,
1000: // just do a sequential search. It's actually faster in most cases.
1001: for (int i = 0; i < columnCount; i++) {
1002: if (columns[i].name.equalsIgnoreCase(columnName)) {
1003: columnMap.put(columnName, new Integer(i + 1));
1004:
1005: return i + 1;
1006: }
1007: }
1008:
1009: throw new SQLException(Messages.get("error.resultset.colname",
1010: columnName), "07009");
1011: }
1012:
1013: public int getInt(String columnName) throws SQLException {
1014: return getInt(findColumn(columnName));
1015: }
1016:
1017: public long getLong(String columnName) throws SQLException {
1018: return getLong(findColumn(columnName));
1019: }
1020:
1021: public short getShort(String columnName) throws SQLException {
1022: return getShort(findColumn(columnName));
1023: }
1024:
1025: public void updateNull(String columnName) throws SQLException {
1026: updateNull(findColumn(columnName));
1027: }
1028:
1029: public boolean getBoolean(String columnName) throws SQLException {
1030: return getBoolean(findColumn(columnName));
1031: }
1032:
1033: public byte[] getBytes(String columnName) throws SQLException {
1034: return getBytes(findColumn(columnName));
1035: }
1036:
1037: public void updateByte(String columnName, byte x)
1038: throws SQLException {
1039: updateByte(findColumn(columnName), x);
1040: }
1041:
1042: public void updateDouble(String columnName, double x)
1043: throws SQLException {
1044: updateDouble(findColumn(columnName), x);
1045: }
1046:
1047: public void updateFloat(String columnName, float x)
1048: throws SQLException {
1049: updateFloat(findColumn(columnName), x);
1050: }
1051:
1052: public void updateInt(String columnName, int x) throws SQLException {
1053: updateInt(findColumn(columnName), x);
1054: }
1055:
1056: public void updateLong(String columnName, long x)
1057: throws SQLException {
1058: updateLong(findColumn(columnName), x);
1059: }
1060:
1061: public void updateShort(String columnName, short x)
1062: throws SQLException {
1063: updateShort(findColumn(columnName), x);
1064: }
1065:
1066: public void updateBoolean(String columnName, boolean x)
1067: throws SQLException {
1068: updateBoolean(findColumn(columnName), x);
1069: }
1070:
1071: public void updateBytes(String columnName, byte[] x)
1072: throws SQLException {
1073: updateBytes(findColumn(columnName), x);
1074: }
1075:
1076: public BigDecimal getBigDecimal(int columnIndex)
1077: throws SQLException {
1078: return (BigDecimal) Support.convert(this ,
1079: getColumn(columnIndex), java.sql.Types.DECIMAL, null);
1080: }
1081:
1082: public BigDecimal getBigDecimal(int columnIndex, int scale)
1083: throws SQLException {
1084: BigDecimal result = (BigDecimal) Support.convert(this ,
1085: getColumn(columnIndex), java.sql.Types.DECIMAL, null);
1086:
1087: if (result == null) {
1088: return null;
1089: }
1090:
1091: return result.setScale(scale, BigDecimal.ROUND_HALF_UP);
1092: }
1093:
1094: public void updateBigDecimal(int columnIndex, BigDecimal x)
1095: throws SQLException {
1096: checkOpen();
1097: checkUpdateable();
1098: if (x != null) {
1099: int prec = getConnection().getMaxPrecision();
1100: x = Support.normalizeBigDecimal(x, prec);
1101: }
1102: setColValue(columnIndex, Types.DECIMAL, x, 0);
1103: }
1104:
1105: public URL getURL(int columnIndex) throws SQLException {
1106: String url = getString(columnIndex);
1107:
1108: try {
1109: return new java.net.URL(url);
1110: } catch (MalformedURLException e) {
1111: throw new SQLException(Messages.get(
1112: "error.resultset.badurl", url), "22000");
1113: }
1114: }
1115:
1116: public Array getArray(int columnIndex) throws SQLException {
1117: checkOpen();
1118: notImplemented("ResultSet.getArray()");
1119: return null;
1120: }
1121:
1122: public void updateArray(int columnIndex, Array x)
1123: throws SQLException {
1124: checkOpen();
1125: checkUpdateable();
1126: notImplemented("ResultSet.updateArray()");
1127: }
1128:
1129: public Blob getBlob(int columnIndex) throws SQLException {
1130: return (Blob) Support.convert(this , getColumn(columnIndex),
1131: java.sql.Types.BLOB, null);
1132: }
1133:
1134: public void updateBlob(int columnIndex, Blob x) throws SQLException {
1135: if (x == null) {
1136: updateBinaryStream(columnIndex, null, 0);
1137: } else {
1138: updateBinaryStream(columnIndex, x.getBinaryStream(),
1139: (int) x.length());
1140: }
1141: }
1142:
1143: public Clob getClob(int columnIndex) throws SQLException {
1144: return (Clob) Support.convert(this , getColumn(columnIndex),
1145: java.sql.Types.CLOB, null);
1146: }
1147:
1148: public void updateClob(int columnIndex, Clob x) throws SQLException {
1149: if (x == null) {
1150: updateCharacterStream(columnIndex, null, 0);
1151: } else {
1152: updateCharacterStream(columnIndex, x.getCharacterStream(),
1153: (int) x.length());
1154: }
1155: }
1156:
1157: public Date getDate(int columnIndex) throws SQLException {
1158: return (java.sql.Date) Support.convert(this ,
1159: getColumn(columnIndex), java.sql.Types.DATE, null);
1160: }
1161:
1162: public void updateDate(int columnIndex, Date x) throws SQLException {
1163: setColValue(columnIndex, Types.DATE, x, 0);
1164: }
1165:
1166: public Ref getRef(int columnIndex) throws SQLException {
1167: checkOpen();
1168: notImplemented("ResultSet.getRef()");
1169:
1170: return null;
1171: }
1172:
1173: public void updateRef(int columnIndex, Ref x) throws SQLException {
1174: checkOpen();
1175: checkUpdateable();
1176: notImplemented("ResultSet.updateRef()");
1177: }
1178:
1179: public ResultSetMetaData getMetaData() throws SQLException {
1180: checkOpen();
1181:
1182: // If this is a DatabaseMetaData built result set, avoid getting an
1183: // exception because the statement is closed and assume no LOBs
1184: boolean useLOBs = this instanceof CachedResultSet
1185: && statement.closed ? false : getConnection()
1186: .getUseLOBs();
1187: return new JtdsResultSetMetaData(this .columns,
1188: this .columnCount, useLOBs);
1189: }
1190:
1191: public SQLWarning getWarnings() throws SQLException {
1192: checkOpen();
1193:
1194: return statement.getWarnings();
1195: }
1196:
1197: public Statement getStatement() throws SQLException {
1198: checkOpen();
1199:
1200: return this .statement;
1201: }
1202:
1203: public Time getTime(int columnIndex) throws SQLException {
1204: return (java.sql.Time) Support.convert(this ,
1205: getColumn(columnIndex), java.sql.Types.TIME, null);
1206: }
1207:
1208: public void updateTime(int columnIndex, Time x) throws SQLException {
1209: setColValue(columnIndex, Types.TIME, x, 0);
1210: }
1211:
1212: public Timestamp getTimestamp(int columnIndex) throws SQLException {
1213: return (Timestamp) Support.convert(this ,
1214: getColumn(columnIndex), java.sql.Types.TIMESTAMP, null);
1215: }
1216:
1217: public void updateTimestamp(int columnIndex, Timestamp x)
1218: throws SQLException {
1219: setColValue(columnIndex, Types.TIMESTAMP, x, 0);
1220: }
1221:
1222: public InputStream getAsciiStream(String columnName)
1223: throws SQLException {
1224: return getAsciiStream(findColumn(columnName));
1225: }
1226:
1227: public InputStream getBinaryStream(String columnName)
1228: throws SQLException {
1229: return getBinaryStream(findColumn(columnName));
1230: }
1231:
1232: public InputStream getUnicodeStream(String columnName)
1233: throws SQLException {
1234: return getUnicodeStream(findColumn(columnName));
1235: }
1236:
1237: public void updateAsciiStream(String columnName, InputStream x,
1238: int length) throws SQLException {
1239: updateAsciiStream(findColumn(columnName), x, length);
1240: }
1241:
1242: public void updateBinaryStream(String columnName, InputStream x,
1243: int length) throws SQLException {
1244: updateBinaryStream(findColumn(columnName), x, length);
1245: }
1246:
1247: public Reader getCharacterStream(String columnName)
1248: throws SQLException {
1249: return getCharacterStream(findColumn(columnName));
1250: }
1251:
1252: public void updateCharacterStream(String columnName, Reader x,
1253: int length) throws SQLException {
1254: updateCharacterStream(findColumn(columnName), x, length);
1255: }
1256:
1257: public Object getObject(String columnName) throws SQLException {
1258: return getObject(findColumn(columnName));
1259: }
1260:
1261: public void updateObject(String columnName, Object x)
1262: throws SQLException {
1263: updateObject(findColumn(columnName), x);
1264: }
1265:
1266: public void updateObject(String columnName, Object x, int scale)
1267: throws SQLException {
1268: updateObject(findColumn(columnName), x, scale);
1269: }
1270:
1271: public Object getObject(int columnIndex, Map map)
1272: throws SQLException {
1273: notImplemented("ResultSet.getObject(int, Map)");
1274: return null;
1275: }
1276:
1277: public String getString(String columnName) throws SQLException {
1278: return getString(findColumn(columnName));
1279: }
1280:
1281: public void updateString(String columnName, String x)
1282: throws SQLException {
1283: updateString(findColumn(columnName), x);
1284: }
1285:
1286: public BigDecimal getBigDecimal(String columnName)
1287: throws SQLException {
1288: return getBigDecimal(findColumn(columnName));
1289: }
1290:
1291: public BigDecimal getBigDecimal(String columnName, int scale)
1292: throws SQLException {
1293: return getBigDecimal(findColumn(columnName), scale);
1294: }
1295:
1296: public void updateBigDecimal(String columnName, BigDecimal x)
1297: throws SQLException {
1298: updateObject(findColumn(columnName), x);
1299: }
1300:
1301: public URL getURL(String columnName) throws SQLException {
1302: return getURL(findColumn(columnName));
1303: }
1304:
1305: public Array getArray(String columnName) throws SQLException {
1306: return getArray(findColumn(columnName));
1307: }
1308:
1309: public void updateArray(String columnName, Array x)
1310: throws SQLException {
1311: updateArray(findColumn(columnName), x);
1312: }
1313:
1314: public Blob getBlob(String columnName) throws SQLException {
1315: return getBlob(findColumn(columnName));
1316: }
1317:
1318: public void updateBlob(String columnName, Blob x)
1319: throws SQLException {
1320: updateBlob(findColumn(columnName), x);
1321: }
1322:
1323: public Clob getClob(String columnName) throws SQLException {
1324: return getClob(findColumn(columnName));
1325: }
1326:
1327: public void updateClob(String columnName, Clob x)
1328: throws SQLException {
1329: updateClob(findColumn(columnName), x);
1330: }
1331:
1332: public Date getDate(String columnName) throws SQLException {
1333: return getDate(findColumn(columnName));
1334: }
1335:
1336: public void updateDate(String columnName, Date x)
1337: throws SQLException {
1338: updateDate(findColumn(columnName), x);
1339: }
1340:
1341: public Date getDate(int columnIndex, Calendar cal)
1342: throws SQLException {
1343: java.sql.Date date = getDate(columnIndex);
1344:
1345: if (date != null && cal != null) {
1346: date = new java.sql.Date(Support.timeToZone(date, cal));
1347: }
1348:
1349: return date;
1350: }
1351:
1352: public Ref getRef(String columnName) throws SQLException {
1353: return getRef(findColumn(columnName));
1354: }
1355:
1356: public void updateRef(String columnName, Ref x) throws SQLException {
1357: updateRef(findColumn(columnName), x);
1358: }
1359:
1360: public Time getTime(String columnName) throws SQLException {
1361: return getTime(findColumn(columnName));
1362: }
1363:
1364: public void updateTime(String columnName, Time x)
1365: throws SQLException {
1366: updateTime(findColumn(columnName), x);
1367: }
1368:
1369: public Time getTime(int columnIndex, Calendar cal)
1370: throws SQLException {
1371: checkOpen();
1372: java.sql.Time time = getTime(columnIndex);
1373:
1374: if (time != null && cal != null) {
1375: return new Time(Support.timeToZone(time, cal));
1376: }
1377:
1378: return time;
1379: }
1380:
1381: public Timestamp getTimestamp(String columnName)
1382: throws SQLException {
1383: return getTimestamp(findColumn(columnName));
1384: }
1385:
1386: public void updateTimestamp(String columnName, Timestamp x)
1387: throws SQLException {
1388: updateTimestamp(findColumn(columnName), x);
1389: }
1390:
1391: public Timestamp getTimestamp(int columnIndex, Calendar cal)
1392: throws SQLException {
1393: checkOpen();
1394: Timestamp timestamp = getTimestamp(columnIndex);
1395:
1396: if (timestamp != null && cal != null) {
1397: timestamp = new Timestamp(Support
1398: .timeToZone(timestamp, cal));
1399: }
1400:
1401: return timestamp;
1402: }
1403:
1404: public Object getObject(String columnName, Map map)
1405: throws SQLException {
1406: return getObject(findColumn(columnName), map);
1407: }
1408:
1409: public Date getDate(String columnName, Calendar cal)
1410: throws SQLException {
1411: return getDate(findColumn(columnName), cal);
1412: }
1413:
1414: public Time getTime(String columnName, Calendar cal)
1415: throws SQLException {
1416: return getTime(findColumn(columnName), cal);
1417: }
1418:
1419: public Timestamp getTimestamp(String columnName, Calendar cal)
1420: throws SQLException {
1421: return getTimestamp(findColumn(columnName), cal);
1422: }
1423: }
|