0001: //
0002: // Copyright 1998, 1999 CDS Networks, Inc., Medford Oregon
0003: //
0004: // All rights reserved.
0005: //
0006: // Redistribution and use in source and binary forms, with or without
0007: // modification, are permitted provided that the following conditions are met:
0008: // 1. Redistributions of source code must retain the above copyright
0009: // notice, this list of conditions and the following disclaimer.
0010: // 2. Redistributions in binary form must reproduce the above copyright
0011: // notice, this list of conditions and the following disclaimer in the
0012: // documentation and/or other materials provided with the distribution.
0013: // 3. All advertising materials mentioning features or use of this software
0014: // must display the following acknowledgement:
0015: // This product includes software developed by CDS Networks, Inc.
0016: // 4. The name of CDS Networks, Inc. may not be used to endorse or promote
0017: // products derived from this software without specific prior
0018: // written permission.
0019: //
0020: // THIS SOFTWARE IS PROVIDED BY CDS NETWORKS, INC. ``AS IS'' AND
0021: // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0022: // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0023: // ARE DISCLAIMED. IN NO EVENT SHALL CDS NETWORKS, INC. BE LIABLE
0024: // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0025: // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
0026: // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
0027: // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
0028: // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
0029: // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0030: // SUCH DAMAGE.
0031: //
0032:
0033: package com.internetcds.jdbc.tds;
0034:
0035: import java.sql.*;
0036: import java.math.BigDecimal;
0037: import java.util.Vector; // import java.util.Calendar;
0038: import java.util.GregorianCalendar;
0039: import java.util.Calendar;
0040: import java.io.*;
0041:
0042: /**
0043: * <P>A ResultSet provides access to a table of data generated by
0044: * executing a Statement. The table rows are retrieved in
0045: * sequence. Within a row its column values can be accessed in any
0046: * order.
0047: *
0048: * <P>A ResultSet maintains a cursor pointing to its current row of
0049: * data. Initially the cursor is positioned before the first row.
0050: * The 'next' method moves the cursor to the next row.
0051: *
0052: * <P>The getXXX methods retrieve column values for the current
0053: * row. You can retrieve values either using the index number of the
0054: * column, or by using the name of the column. In general using the
0055: * column index will be more efficient. Columns are numbered from 1.
0056: *
0057: * <P>For maximum portability, ResultSet columns within each row should be
0058: * read in left-to-right order and each column should be read only once.
0059: *
0060: * <P>For the getXXX methods, the JDBC driver attempts to convert the
0061: * underlying data to the specified Java type and returns a suitable
0062: * Java value. See the JDBC specification for allowable mappings
0063: * from SQL types to Java types with the ResultSet.getXXX methods.
0064: *
0065: * <P>Column names used as input to getXXX methods are case
0066: * insensitive. When performing a getXXX using a column name, if
0067: * several columns have the same name, then the value of the first
0068: * matching column will be returned. The column name option is
0069: * designed to be used when column names are used in the SQL
0070: * query. For columns that are NOT explicitly named in the query, it
0071: * is best to use column numbers. If column names were used there is
0072: * no way for the programmer to guarantee that they actually refer to
0073: * the intended columns.
0074: *
0075: * <P>A ResultSet is automatically closed by the Statement that
0076: * generated it when that Statement is closed, re-executed, or is used
0077: * to retrieve the next result from a sequence of multiple results.
0078: *
0079: * <P>The number, types and properties of a ResultSet's columns are
0080: * provided by the ResulSetMetaData object returned by the getMetaData
0081: * method.
0082: *
0083: * @author Craig Spannring
0084: * @author The FreeTDS project
0085: * @version $Id: ResultSet_base.java,v 1.2 2007-10-19 13:21:40 sinisa Exp $
0086: *
0087: * @see Statement#executeQuery
0088: * @see Statement#getResultSet
0089: * @see ResultSetMetaData
0090: @ @see Tds#getRow
0091: */
0092:
0093: public class ResultSet_base {
0094: public static final String cvsVersion = "$Id: ResultSet_base.java,v 1.2 2007-10-19 13:21:40 sinisa Exp $";
0095:
0096: Tds tds = null;
0097: Statement stmt = null;
0098: Columns columnsInfo = null;
0099: ResultSetMetaData metaData = null;
0100: PacketRowResult currentRow = null;
0101: boolean lastGetWasNull = false;
0102:
0103: boolean hitEndOfData = false;
0104: boolean isClosed = false;
0105:
0106: private SQLWarningChain warningChain = null; // The warnings chain.
0107:
0108: public ResultSet_base(Tds tds_, Statement stmt_, Columns columns_) {
0109: tds = tds_;
0110: stmt = stmt_;
0111: columnsInfo = columns_;
0112:
0113: hitEndOfData = false;
0114: warningChain = new SQLWarningChain();
0115: }
0116:
0117: protected void NotImplemented() throws java.sql.SQLException {
0118: throw new SQLException("Not implemented");
0119: }
0120:
0121: /**
0122: * After this call getWarnings returns null until a new warning is
0123: * reported for this ResultSet.
0124: *
0125: * @exception SQLException if a database-access error occurs.
0126: */
0127: public void clearWarnings() throws SQLException {
0128: warningChain.clearWarnings();
0129: }
0130:
0131: /**
0132: * In some cases, it is desirable to immediately release a
0133: * ResultSet's database and JDBC resources instead of waiting for
0134: * this to happen when it is automatically closed; the close
0135: * method provides this immediate release.
0136: *
0137: * <P><B>Note:</B> A ResultSet is automatically closed by the
0138: * Statement that generated it when that Statement is closed,
0139: * re-executed, or is used to retrieve the next result from a
0140: * sequence of multiple results. A ResultSet is also automatically
0141: * closed when it is garbage collected.
0142: *
0143: * @exception SQLException if a database-access error occurs.
0144: */
0145: public void close() throws SQLException {
0146: Exception exception = null;
0147:
0148: if (isClosed) {
0149: // nop ???
0150: } else {
0151: isClosed = true;
0152: try {
0153: if (!hitEndOfData) {
0154: tds.discardResultSet(columnsInfo);
0155: hitEndOfData = true;
0156: } else {
0157: // nop
0158: }
0159: } catch (com.internetcds.jdbc.tds.TdsException e) {
0160: e.printStackTrace();
0161: exception = e;
0162: } catch (java.io.IOException e) {
0163: e.printStackTrace();
0164: exception = e;
0165: }
0166:
0167: currentRow = null;
0168: metaData = null;
0169: columnsInfo = null;
0170: stmt = null;
0171:
0172: if (exception != null) {
0173: throw new SQLException(exception.getMessage());
0174: }
0175: }
0176: }
0177:
0178: //----------------------------------------------------------------
0179:
0180: /**
0181: * Map a Resultset column name to a ResultSet column index.
0182: *
0183: * @param columnName the name of the column
0184: * @return the column index
0185: * @exception SQLException if a database-access error occurs.
0186: */
0187: public int findColumn(String columnName) throws SQLException {
0188: int i;
0189:
0190: for (i = 1; i <= columnsInfo.getColumnCount(); i++) {
0191: if (columnsInfo.getName(i).equalsIgnoreCase(columnName)) {
0192: return i;
0193: }
0194: // XXX also need to look at the fully qualified name ie. table.column
0195: }
0196: throw new SQLException("No such column " + columnName);
0197: }
0198:
0199: /**
0200: * A column value can be retrieved as a stream of ASCII characters
0201: * and then read in chunks from the stream. This method is particularly
0202: * suitable for retrieving large LONGVARCHAR values. The JDBC driver will
0203: * do any necessary conversion from the database format into ASCII.
0204: *
0205: * <P><B>Note:</B> All the data in the returned stream must be
0206: * read prior to getting the value of any other column. The next
0207: * call to a get method implicitly closes the stream. . Also, a
0208: * stream may return 0 for available() whether there is data
0209: * available or not.
0210: *
0211: * @param columnIndex the first column is 1, the second is 2, ...
0212: * @return a Java input stream that delivers the database column value
0213: * as a stream of one byte ASCII characters. If the value is SQL NULL
0214: * then the result is null.
0215: * @exception SQLException if a database-access error occurs.
0216: */
0217: public java.io.InputStream getAsciiStream(int columnIndex)
0218: throws SQLException {
0219: String val = getString(columnIndex);
0220: if (val == null)
0221: return null;
0222: try {
0223: return new ByteArrayInputStream(val.getBytes("ASCII"));
0224: } catch (UnsupportedEncodingException ue) {
0225: // plain impossible with encoding ASCII
0226: return null;
0227: }
0228: }
0229:
0230: /**
0231: * A column value can be retrieved as a stream of ASCII characters
0232: * and then read in chunks from the stream. This method is particularly
0233: * suitable for retrieving large LONGVARCHAR values. The JDBC driver will
0234: * do any necessary conversion from the database format into ASCII.
0235: *
0236: * <P><B>Note:</B> All the data in the returned stream must
0237: * be read prior to getting the value of any other column. The
0238: * next call to a get method implicitly closes the stream.
0239: *
0240: * @param columnName is the SQL name of the column
0241: * @return a Java input stream that delivers the database column value
0242: * as a stream of one byte ASCII characters. If the value is SQL NULL
0243: * then the result is null.
0244: * @exception SQLException if a database-access error occurs.
0245: */
0246: public java.io.InputStream getAsciiStream(String columnName)
0247: throws SQLException {
0248: return getAsciiStream(findColumn(columnName));
0249: }
0250:
0251: /**
0252: * Get the value of a column in the current row as a
0253: * java.lang.BigDecimal object.
0254: *
0255: * @param columnIndex the first column is 1, the second is 2, ...
0256: * @param scale the number of digits to the right of the decimal
0257: * @return the column value; if the value is SQL NULL, the result is null
0258: * @exception SQLException if a database-access error occurs.
0259: */
0260: public BigDecimal getBigDecimal(int columnIndex, int scale)
0261: throws SQLException {
0262: Object tmp = getObject(columnIndex);
0263: BigDecimal result = null;
0264:
0265: if (tmp == null) {
0266: result = null;
0267: } else if (tmp instanceof java.lang.Double) {
0268: result = new BigDecimal(((Double) tmp).doubleValue());
0269: result = result.setScale(scale, BigDecimal.ROUND_HALF_UP);
0270: } else if (tmp instanceof java.lang.Float) {
0271: result = new BigDecimal(((Float) tmp).doubleValue());
0272: result = result.setScale(scale, BigDecimal.ROUND_HALF_UP);
0273: } else if (tmp instanceof java.lang.Number) {
0274: // This handles Byte, Short, Integer, and Long
0275: result = BigDecimal.valueOf(((Number) tmp).longValue(),
0276: scale);
0277: } else if (tmp instanceof BigDecimal) {
0278: result = (BigDecimal) tmp;
0279: } else if (tmp instanceof java.lang.String) {
0280: try {
0281: result = new BigDecimal((String) tmp);
0282: } catch (NumberFormatException e) {
0283: throw new SQLException(e.getMessage());
0284: }
0285: }
0286: return result;
0287: }
0288:
0289: /**
0290: * Get the value of a column in the current row as a
0291: * java.lang.BigDecimal object.
0292: *
0293: * @param columnName is the SQL name of the column
0294: * @param scale the number of digits to the right of the decimal
0295: * @return the column value; if the value is SQL NULL, the result is null
0296: * @exception SQLException if a database-access error occurs.
0297: */
0298: public BigDecimal getBigDecimal(String columnName, int scale)
0299: throws SQLException {
0300: return getBigDecimal(findColumn(columnName), scale);
0301: }
0302:
0303: /**
0304: * A column value can be retrieved as a stream of uninterpreted bytes
0305: * and then read in chunks from the stream. This method is particularly
0306: * suitable for retrieving large LONGVARBINARY values.
0307: *
0308: * <P><B>Note:</B> All the data in the returned stream must be
0309: * read prior to getting the value of any other column. The next
0310: * call to a get method implicitly closes the stream. Also, a
0311: * stream may return 0 for available() whether there is data
0312: * available or not.
0313: *
0314: * @param columnIndex the first column is 1, the second is 2, ...
0315: * @return a Java input stream that delivers the database column value
0316: * as a stream of uninterpreted bytes. If the value is SQL NULL
0317: * then the result is null.
0318: * @exception SQLException if a database-access error occurs.
0319: */
0320: public java.io.InputStream getBinaryStream(int columnIndex)
0321: throws SQLException {
0322: byte[] bytes = getBytes(columnIndex);
0323: if (bytes != null)
0324: return new ByteArrayInputStream(bytes);
0325: return null;
0326: }
0327:
0328: /**
0329: * A column value can be retrieved as a stream of uninterpreted bytes
0330: * and then read in chunks from the stream. This method is particularly
0331: * suitable for retrieving large LONGVARBINARY values.
0332: *
0333: * <P><B>Note:</B> All the data in the returned stream must
0334: * be read prior to getting the value of any other column. The
0335: * next call to a get method implicitly closes the stream.
0336: *
0337: * @param columnName is the SQL name of the column
0338: * @return a Java input stream that delivers the database column value
0339: * as a stream of uninterpreted bytes. If the value is SQL NULL
0340: * then the result is null.
0341: * @exception SQLException if a database-access error occurs.
0342: */
0343: public java.io.InputStream getBinaryStream(String columnName)
0344: throws SQLException {
0345: return getBinaryStream(findColumn(columnName));
0346: }
0347:
0348: /**
0349: * Get the value of a column in the current row as a Java boolean.
0350: *
0351: * @param columnIndex the first column is 1, the second is 2, ...
0352: * @return the column value; if the value is SQL NULL, the result is false
0353: * @exception SQLException if a database-access error occurs.
0354: */
0355: public boolean getBoolean(int columnIndex) throws SQLException {
0356: Object obj = getObject(columnIndex);
0357: boolean result;
0358:
0359: if (obj == null) {
0360: result = false;
0361: } else {
0362: switch (getMetaData().getColumnType(columnIndex)) {
0363: case java.sql.Types.TINYINT:
0364: case java.sql.Types.SMALLINT:
0365: case java.sql.Types.INTEGER:
0366: case java.sql.Types.BIGINT:
0367: case java.sql.Types.REAL:
0368: case java.sql.Types.FLOAT:
0369: case java.sql.Types.DOUBLE:
0370: case java.sql.Types.DECIMAL:
0371: case java.sql.Types.NUMERIC: {
0372: if (!(obj instanceof java.lang.Number)) {
0373: // Must be out of sync with the implementation of
0374: // Tds.getRow() for this to happen.
0375: throw new SQLException("Internal error");
0376: }
0377: // Would somebody like to tell what a true/false has
0378: // to do with a double?
0379: result = ((java.lang.Number) obj).intValue() != 0;
0380: break;
0381: }
0382: case java.sql.Types.BIT: {
0383: if (!(obj instanceof Boolean)) {
0384: // Must be out of sync with the implementation of
0385: // Tds.getRow() for this to happen.
0386: throw new SQLException("Internal error");
0387: }
0388: result = ((Boolean) obj).booleanValue();
0389: break;
0390: }
0391: case java.sql.Types.CHAR:
0392: case java.sql.Types.VARCHAR:
0393: case java.sql.Types.LONGVARCHAR: {
0394: // Okay, I'm really confused as to what you mean
0395: // by a character string being true or false. What
0396: // is the boolean value for "Let the wookie win"?
0397: // But since the spec says I have to convert from
0398: // character to boolean data...
0399:
0400: if (!(obj instanceof String)) {
0401: // Must be out of sync with the implementation of
0402: // Tds.getRow() for this to happen.
0403: throw new SQLException("Internal error");
0404: }
0405: char ch = (((String) obj) + "n").charAt(0);
0406:
0407: result = (ch == 'Y') || (ch == 'y') || (ch == 't')
0408: || (ch == 'T');
0409: break;
0410: }
0411: default: {
0412: throw new SQLException("Can't convert column "
0413: + columnIndex + " from "
0414: + obj.getClass().getName() + " to boolean");
0415: }
0416: }
0417: }
0418: return result;
0419: } // getBoolean()
0420:
0421: /**
0422: * Get the value of a column in the current row as a Java boolean.
0423: *
0424: * @param columnName is the SQL name of the column
0425: * @return the column value; if the value is SQL NULL, the result is false
0426: * @exception SQLException if a database-access error occurs.
0427: */
0428: public boolean getBoolean(String columnName) throws SQLException {
0429: return getBoolean(findColumn(columnName));
0430: } // getBoolean()
0431:
0432: /**
0433: * Get the value of a column in the current row as a Java byte.
0434: *
0435: * @param columnIndex the first column is 1, the second is 2, ...
0436: * @return the column value; if the value is SQL NULL, the result is 0
0437: * @exception SQLException if a database-access error occurs.
0438: */
0439: public byte getByte(int columnIndex) throws SQLException {
0440: return (byte) getLong(columnIndex);
0441: }
0442:
0443: /**
0444: * Get the value of a column in the current row as a Java byte.
0445: *
0446: * @param columnName is the SQL name of the column
0447: * @return the column value; if the value is SQL NULL, the result is 0
0448: * @exception SQLException if a database-access error occurs.
0449: */
0450: public byte getByte(String columnName) throws SQLException {
0451: return getByte(findColumn(columnName));
0452: }
0453:
0454: /**
0455: * Get the value of a column in the current row as a Java byte array.
0456: * The bytes represent the raw values returned by the driver.
0457: *
0458: * @param columnIndex the first column is 1, the second is 2, ...
0459: * @return the column value; if the value is SQL NULL, the result is null
0460: * @exception SQLException if a database-access error occurs.
0461: */
0462: public byte[] getBytes(int columnIndex) throws SQLException {
0463: byte result[];
0464:
0465: try {
0466: Object tmp = currentRow.getElementAt(columnIndex);
0467: lastGetWasNull = false;
0468: if (tmp == null) {
0469: lastGetWasNull = true;
0470: result = null;
0471: } else if (tmp instanceof byte[]) {
0472: result = (byte[]) tmp;
0473: } else if (tmp instanceof String) {
0474: result = tds.getEncoder().getBytes((String) tmp);
0475: } else {
0476: throw new SQLException("Can't convert column "
0477: + columnIndex + " from "
0478: + tmp.getClass().getName() + " to byte[]");
0479: }
0480: } catch (TdsException e) {
0481: e.printStackTrace();
0482: throw new SQLException(e.getMessage());
0483: }
0484: return result;
0485: }
0486:
0487: /**
0488: * Get the value of a column in the current row as a Java byte array.
0489: * The bytes represent the raw values returned by the driver.
0490: *
0491: * @param columnName is the SQL name of the column
0492: * @return the column value; if the value is SQL NULL, the result is null
0493: * @exception SQLException if a database-access error occurs.
0494: */
0495: public byte[] getBytes(String columnName) throws SQLException {
0496: return getBytes(findColumn(columnName));
0497: }
0498:
0499: /**
0500: * Get the name of the SQL cursor used by this ResultSet.
0501: *
0502: * <P>In SQL, a result table is retrieved through a cursor that is
0503: * named. The current row of a result can be updated or deleted
0504: * using a positioned update/delete statement that references the
0505: * cursor name.
0506: *
0507: * <P>JDBC supports this SQL feature by providing the name of the
0508: * SQL cursor used by a ResultSet. The current row of a ResultSet
0509: * is also the current row of this SQL cursor.
0510: *
0511: * <P><B>Note:</B> If positioned update is not supported a
0512: * SQLException is thrown
0513: *
0514: * @return the ResultSet's SQL cursor name
0515: * @exception SQLException if a database-access error occurs.
0516: */
0517: public String getCursorName() throws SQLException {
0518: throw new SQLException("Not implemented (getCursorName)");
0519: }
0520:
0521: /**
0522: * Get the value of a column in the current row as a java.sql.Date object.
0523: *
0524: * @param columnIndex the first column is 1, the second is 2, ...
0525: * @return the column value; if the value is SQL NULL, the result is null
0526: * @exception SQLException if a database-access error occurs.
0527: */
0528: public java.sql.Date getDate(int columnIndex) throws SQLException {
0529: java.sql.Date result = null;
0530: java.sql.Timestamp tmp = getTimestamp(columnIndex);
0531:
0532: if (tmp != null) {
0533: result = new java.sql.Date(tmp.getTime());
0534: }
0535: return result;
0536: }
0537:
0538: /**
0539: * Get the value of a column in the current row as a java.sql.Date object.
0540: *
0541: * @param columnName is the SQL name of the column
0542: * @return the column value; if the value is SQL NULL, the result is null
0543: * @exception SQLException if a database-access error occurs.
0544: */
0545: public java.sql.Date getDate(String columnName) throws SQLException {
0546: return getDate(findColumn(columnName));
0547: }
0548:
0549: /**
0550: * Get the value of a column in the current row as a Java double.
0551: *
0552: * @param columnIndex the first column is 1, the second is 2, ...
0553: * @return the column value; if the value is SQL NULL, the result is 0
0554: * @exception SQLException if a database-access error occurs.
0555: */
0556: public double getDouble(int columnIndex) throws SQLException {
0557: double result;
0558: Object obj = getObject(columnIndex);
0559:
0560: if (obj == null) {
0561: result = 0.0;
0562: } else {
0563: try {
0564: switch (getMetaData().getColumnType(columnIndex)) {
0565: case java.sql.Types.TINYINT:
0566: case java.sql.Types.SMALLINT:
0567: case java.sql.Types.INTEGER: {
0568: result = ((Number) obj).doubleValue();
0569: break;
0570: }
0571: case java.sql.Types.BIGINT: {
0572: result = ((Number) obj).doubleValue();
0573: break;
0574: }
0575: case java.sql.Types.REAL: {
0576: result = ((Float) obj).doubleValue();
0577: break;
0578: }
0579: case java.sql.Types.FLOAT:
0580: case java.sql.Types.DOUBLE: {
0581: result = ((Number) obj).doubleValue();
0582: break;
0583: }
0584: case java.sql.Types.CHAR:
0585: case java.sql.Types.VARCHAR:
0586: case java.sql.Types.LONGVARCHAR: {
0587: try {
0588: Double d = new Double((String) obj);
0589: result = d.doubleValue();
0590: } catch (NumberFormatException e) {
0591: throw new SQLException(e.getMessage());
0592: }
0593: break;
0594: }
0595: case java.sql.Types.DECIMAL:
0596: case java.sql.Types.NUMERIC: {
0597: result = ((BigDecimal) obj).doubleValue();
0598: break;
0599: }
0600: case java.sql.Types.BIT: {
0601: // XXX according to JDBC spec we need to handle these
0602: // for now just fall through
0603: }
0604: default: {
0605: throw new SQLException("Internal error. "
0606: + "Don't know how to convert from "
0607: + "java.sql.Types."
0608: + TdsUtil.javaSqlTypeToString(getMetaData()
0609: .getColumnType(columnIndex))
0610: + " to an Dboule");
0611: }
0612: }
0613: } catch (ClassCastException e) {
0614: throw new SQLException("Couldn't convert column "
0615: + columnIndex + " to an long. "
0616: + e.getMessage());
0617: }
0618: }
0619: return result;
0620: } /* getDouble() */
0621:
0622: /**
0623: * Get the value of a column in the current row as a Java double.
0624: *
0625: * @param columnName is the SQL name of the column
0626: * @return the column value; if the value is SQL NULL, the result is 0
0627: * @exception SQLException if a database-access error occurs.
0628: */
0629: public double getDouble(String columnName) throws SQLException {
0630: return getDouble(findColumn(columnName));
0631: }
0632:
0633: /**
0634: * Get the value of a column in the current row as a Java float.
0635: *
0636: * @param columnIndex the first column is 1, the second is 2, ...
0637: * @return the column value; if the value is SQL NULL, the result is 0
0638: * @exception SQLException if a database-access error occurs.
0639: */
0640: public float getFloat(int columnIndex) throws SQLException {
0641: return (float) getDouble(columnIndex);
0642: }
0643:
0644: /**
0645: * Get the value of a column in the current row as a Java float.
0646: *
0647: * @param columnName is the SQL name of the column
0648: * @return the column value; if the value is SQL NULL, the result is 0
0649: * @exception SQLException if a database-access error occurs.
0650: */
0651: public float getFloat(String columnName) throws SQLException {
0652: return getFloat(findColumn(columnName));
0653: }
0654:
0655: /**
0656: * Get the value of a column in the current row as a Java int.
0657: *
0658: * @param columnIndex the first column is 1, the second is 2, ...
0659: * @return the column value; if the value is SQL NULL, the result is 0
0660: * @exception SQLException if a database-access error occurs.
0661: */
0662: public int getInt(int columnIndex) throws SQLException {
0663: return (int) getLong(columnIndex);
0664: }
0665:
0666: /**
0667: * Get the value of a column in the current row as a Java int.
0668: *
0669: * @param columnName is the SQL name of the column
0670: * @return the column value; if the value is SQL NULL, the result is 0
0671: * @exception SQLException if a database-access error occurs.
0672: */
0673: public int getInt(String columnName) throws SQLException {
0674: return getInt(findColumn(columnName));
0675: }
0676:
0677: /**
0678: * Get the value of a column in the current row as a Java long.
0679: *
0680: * @param columnIndex the first column is 1, the second is 2, ...
0681: * @return the column value; if the value is SQL NULL, the result is 0
0682: * @exception SQLException if a database-access error occurs.
0683: */
0684: public long getLong(int columnIndex) throws SQLException {
0685: long result = 0;
0686: Object obj = getObject(columnIndex);
0687:
0688: if (obj == null) {
0689: result = 0;
0690: } else {
0691: try {
0692: switch (getMetaData().getColumnType(columnIndex)) {
0693: case java.sql.Types.TINYINT:
0694: case java.sql.Types.SMALLINT:
0695: case java.sql.Types.INTEGER: {
0696: result = ((Number) obj).longValue();
0697: break;
0698: }
0699: case java.sql.Types.BIGINT: {
0700: result = ((Number) obj).longValue();
0701: break;
0702: }
0703: case java.sql.Types.REAL:
0704: case java.sql.Types.FLOAT:
0705: case java.sql.Types.DOUBLE: {
0706: result = ((Number) obj).longValue();
0707: break;
0708: }
0709: case java.sql.Types.CHAR:
0710: case java.sql.Types.VARCHAR:
0711: case java.sql.Types.LONGVARCHAR: {
0712: try {
0713: Long i = new Long((String) obj);
0714: result = i.longValue();
0715: } catch (NumberFormatException e) {
0716: throw new SQLException(e.getMessage());
0717: }
0718: break;
0719: }
0720: case java.sql.Types.NUMERIC: {
0721: result = ((Number) obj).longValue();
0722: break;
0723: }
0724: case java.sql.Types.DECIMAL: {
0725: result = ((Number) obj).longValue();
0726: break;
0727: }
0728: case java.sql.Types.BIT: {
0729: // XXX according to JDBC spec we need to handle these
0730: // for now just fall through
0731: }
0732: default: {
0733: throw new SQLException("Internal error. "
0734: + "Don't know how to convert from "
0735: + "java.sql.Types "
0736: + TdsUtil.javaSqlTypeToString(getMetaData()
0737: .getColumnType(columnIndex))
0738: + " to an long");
0739: }
0740: }
0741: } catch (ClassCastException e) {
0742: throw new SQLException("Couldn't convert column "
0743: + columnIndex + " to an long. "
0744: + e.getMessage());
0745: }
0746: }
0747: return result;
0748: } /* getLong() */
0749:
0750: /**
0751: * Get the value of a column in the current row as a Java long.
0752: *
0753: * @param columnName is the SQL name of the column
0754: * @return the column value; if the value is SQL NULL, the result is 0
0755: * @exception SQLException if a database-access error occurs.
0756: */
0757: public long getLong(String columnName) throws SQLException {
0758: return getLong(findColumn(columnName));
0759: }
0760:
0761: /**
0762: * The number, types and properties of a ResultSet's columns
0763: * are provided by the getMetaData method.
0764: *
0765: * @return the description of a ResultSet's columns
0766: * @exception SQLException if a database-access error occurs.
0767: */
0768: public java.sql.ResultSetMetaData getMetaData() throws SQLException {
0769: if (metaData == null) {
0770: metaData = new ResultSetMetaData(columnsInfo);
0771: }
0772: return metaData;
0773: }
0774:
0775: /**
0776: * <p>Get the value of a column in the current row as a Java object.
0777: *
0778: * <p>This method will return the value of the given column as a
0779: * Java object. The type of the Java object will be the default
0780: * Java Object type corresponding to the column's SQL type,
0781: * following the mapping specified in the JDBC spec.
0782: *
0783: * <p>This method may also be used to read datatabase specific abstract
0784: * data types.
0785: *
0786: * JDBC 2.0
0787: *
0788: * In the JDBC 2.0 API, the behavior of method
0789: * <code>getObject</code> is extended to materialize
0790: * data of SQL user-defined types. When the a column contains
0791: * a structured or distinct value, the behavior of this method is as
0792: * if it were a call to: getObject(columnIndex,
0793: * this.getStatement().getConnection().getTypeMap()).
0794: *
0795: * @param columnIndex the first column is 1, the second is 2, ...
0796: * @return A java.lang.Object holding the column value.
0797: * @exception SQLException if a database-access error occurs.
0798: */
0799: public Object getObject(int columnIndex) throws SQLException {
0800: // This method is implicitly coupled to the getRow() method in the
0801: // Tds class. Every type that getRow() could return must
0802: // be handled in this method.
0803: //
0804: // The object type returned by getRow() must correspond with the
0805: // jdbc SQL type in the switch statement below.
0806: //
0807: // Note- The JDBC spec (version 1.20) does not define the type
0808: // of the Object returned for LONGVARCHAR data.
0809:
0810: // XXX- Needs modifications for JDBC 2.0
0811:
0812: Object result = null;
0813:
0814: if (currentRow == null) {
0815: throw new SQLException(
0816: "No current row in the result set. "
0817: + "Did you call ResultSet.next()?");
0818: }
0819:
0820: try {
0821: Object tmp = currentRow.getElementAt(columnIndex);
0822: lastGetWasNull = false;
0823: if (tmp == null) {
0824: lastGetWasNull = true;
0825:
0826: result = null;
0827: } else {
0828: switch (getMetaData().getColumnType(columnIndex)) {
0829: case java.sql.Types.CHAR:
0830: case java.sql.Types.VARCHAR: {
0831: if (tmp instanceof String) {
0832: result = tmp;
0833: } else {
0834: throw new SQLException(
0835: "Was expecting CHAR data. Got"
0836: + tmp.getClass().getName());
0837: }
0838: break;
0839: }
0840: case java.sql.Types.TINYINT: {
0841: if (!(tmp instanceof Long)) {
0842: throw new SQLException("Internal error");
0843: }
0844:
0845: result = new Byte((byte) ((Long) tmp).intValue());
0846: break;
0847: }
0848: case java.sql.Types.SMALLINT: {
0849: if (!(tmp instanceof Long)) {
0850: throw new SQLException("Internal error");
0851: }
0852:
0853: result = new Short((short) ((Long) tmp).intValue());
0854: break;
0855: }
0856: case java.sql.Types.INTEGER: {
0857: if (!(tmp instanceof Long)) {
0858: throw new SQLException("Internal error");
0859: }
0860:
0861: result = new Integer(((Long) tmp).intValue());
0862: break;
0863: }
0864: case java.sql.Types.BIGINT: {
0865: if (!(tmp instanceof Long)) {
0866: throw new SQLException("Internal error");
0867: }
0868:
0869: result = (Long) tmp;
0870: break;
0871: }
0872: case java.sql.Types.REAL: {
0873: if (!(tmp instanceof Float)) {
0874: throw new SQLException("Internal error");
0875: }
0876:
0877: result = (Float) tmp;
0878: break;
0879: }
0880: case java.sql.Types.FLOAT:
0881: case java.sql.Types.DOUBLE: {
0882: if (tmp instanceof Double) {
0883: result = (Double) tmp;
0884: } else if (tmp instanceof Float) {
0885: result = new Double(((Float) tmp).doubleValue());
0886: } else {
0887: throw new SQLException(
0888: "Was expecting Double data. Got"
0889: + tmp.getClass().getName());
0890: }
0891:
0892: break;
0893: }
0894: case java.sql.Types.DATE: {
0895: // XXX How do the time types hold up with timezones?
0896: if (!(tmp instanceof Timestamp)) {
0897: throw new SQLException("Internal error");
0898: }
0899:
0900: // java.util.Calendar cal = new java.util.GregorianCalendar();
0901: // cal.setTime(getTimestamp(columnIndex));
0902: // result = cal.getTime();
0903: result = new Date(((Timestamp) tmp).getTime());
0904: break;
0905: }
0906: case java.sql.Types.TIME: {
0907: if (!(tmp instanceof Timestamp)) {
0908: throw new SQLException("Internal error");
0909: }
0910:
0911: result = new Time(((Timestamp) tmp).getTime());
0912: break;
0913: }
0914: case java.sql.Types.TIMESTAMP: {
0915: if (!(tmp instanceof Timestamp)) {
0916: throw new SQLException("Internal error");
0917: }
0918:
0919: result = (Timestamp) tmp;
0920: break;
0921: }
0922: case java.sql.Types.BINARY:
0923: case java.sql.Types.VARBINARY: {
0924: result = getBytes(columnIndex);
0925: break;
0926: }
0927: case java.sql.Types.DECIMAL:
0928: case java.sql.Types.NUMERIC: {
0929: if (tmp instanceof BigDecimal) {
0930: result = ((BigDecimal) tmp);
0931: } else {
0932: throw new SQLException(
0933: "Was expecting NUMERIC data. Got"
0934: + tmp.getClass().getName());
0935: }
0936: break;
0937: }
0938: case java.sql.Types.LONGVARCHAR: {
0939: if (tmp instanceof TdsAsciiInputStream) {
0940: result = ((TdsAsciiInputStream) tmp).toString();
0941: } else if (tmp instanceof java.lang.String) {
0942: result = tmp;
0943: } else {
0944: throw new SQLException(
0945: "Was expecting LONGVARCHAR data. "
0946: + "Got "
0947: + tmp.getClass().getName());
0948: }
0949: break;
0950: }
0951: case java.sql.Types.LONGVARBINARY: {
0952: throw new SQLException("Not implemented");
0953: }
0954: case java.sql.Types.NULL: {
0955: throw new SQLException("Not implemented");
0956: }
0957: case java.sql.Types.OTHER: {
0958: throw new SQLException("Not implemented");
0959: }
0960: case java.sql.Types.BIT: {
0961: if (tmp instanceof Boolean) {
0962: result = ((Boolean) tmp);
0963: } else {
0964: throw new SQLException(
0965: "Was expecting BIT data. " + "Got"
0966: + tmp.getClass().getName());
0967: }
0968: break;
0969: }
0970: default: {
0971: String msg = "" + "Unknown datatype "
0972: + getMetaData().getColumnType(columnIndex);
0973: throw new SQLException(msg);
0974: }
0975: }
0976: }
0977: } catch (com.internetcds.jdbc.tds.TdsException e) {
0978: e.printStackTrace();
0979: throw new SQLException(e.getMessage());
0980: }
0981: return result;
0982: } // getObject()
0983:
0984: /**
0985: * <p>Get the value of a column in the current row as a Java object.
0986: *
0987: * <p>This method will return the value of the given column as a
0988: * Java object. The type of the Java object will be the default
0989: * Java Object type corresponding to the column's SQL type,
0990: * following the mapping specified in the JDBC spec.
0991: *
0992: * JDBC 2.0
0993: *
0994: *
0995: * In the JDBC 2.0 API, the behavior of method
0996: * <code>getObject</code> is extended to materialize
0997: * data of SQL user-defined types. When the a column contains
0998: * a structured or distinct value, the behavior of this method is as
0999: * if it were a call to: getObject(columnIndex,
1000: * this.getStatement().getConnection().getTypeMap()).
1001: *
1002: * <p>This method may also be used to read datatabase specific abstract
1003: * data types.
1004: *
1005: * @param columnName is the SQL name of the column
1006: * @return A java.lang.Object holding the column value.
1007: * @exception SQLException if a database-access error occurs.
1008: */
1009: public Object getObject(String columnName) throws SQLException {
1010: return getObject(findColumn(columnName));
1011: }
1012:
1013: /**
1014: * Get the value of a column in the current row as a Java short.
1015: *
1016: * @param columnIndex the first column is 1, the second is 2, ...
1017: * @return the column value; if the value is SQL NULL, the result is 0
1018: * @exception SQLException if a database-access error occurs.
1019: */
1020: public short getShort(int columnIndex) throws SQLException {
1021: return (short) getLong(columnIndex);
1022: }
1023:
1024: /**
1025: * Get the value of a column in the current row as a Java short.
1026: *
1027: * @param columnName is the SQL name of the column
1028: * @return the column value; if the value is SQL NULL, the result is 0
1029: * @exception SQLException if a database-access error occurs.
1030: */
1031: public short getShort(String columnName) throws SQLException {
1032: return getShort(findColumn(columnName));
1033: }
1034:
1035: //======================================================================
1036: // Methods for accessing results by column index
1037: //======================================================================
1038:
1039: /**
1040: * Get the value of a column in the current row as a Java String.
1041: *
1042: * @param columnIndex the first column is 1, the second is 2, ...
1043: * @return the column value; if the value is SQL NULL, the result is null
1044: * @exception SQLException if a database-access error occurs.
1045: */
1046: public String getString(int columnIndex) throws SQLException {
1047: Object tmp = getObject(columnIndex);
1048:
1049: if (tmp == null) {
1050: return null;
1051: } else if (tmp instanceof byte[]) {
1052: return new String((byte[]) tmp);
1053: } else {
1054: return tmp.toString();
1055: }
1056: }
1057:
1058: //======================================================================
1059: // Methods for accessing results by column name
1060: //======================================================================
1061:
1062: /**
1063: * Get the value of a column in the current row as a Java String.
1064: *
1065: * @param columnName is the SQL name of the column
1066: * @return the column value; if the value is SQL NULL, the result is null
1067: * @exception SQLException if a database-access error occurs.
1068: */
1069: public String getString(String columnName) throws SQLException {
1070: return getString(findColumn(columnName));
1071: }
1072:
1073: /**
1074: * Get the value of a column in the current row as a java.sql.Time object.
1075: *
1076: * @param columnIndex the first column is 1, the second is 2, ...
1077: * @return the column value; if the value is SQL NULL, the result is null
1078: * @exception SQLException if a database-access error occurs.
1079: */
1080: public java.sql.Time getTime(int columnIndex) throws SQLException {
1081: java.sql.Time result = null;
1082: java.sql.Timestamp tmp = getTimestamp(columnIndex);
1083:
1084: if (tmp != null) {
1085: result = new java.sql.Time(tmp.getTime());
1086: }
1087: return result;
1088: }
1089:
1090: /**
1091: * Get the value of a column in the current row as a java.sql.Time object.
1092: *
1093: * @param columnName is the SQL name of the column
1094: * @return the column value; if the value is SQL NULL, the result is null
1095: * @exception SQLException if a database-access error occurs.
1096: */
1097: public java.sql.Time getTime(String columnName) throws SQLException {
1098: return getTime(findColumn(columnName));
1099: }
1100:
1101: /**
1102: * Get the value of a column in the current row as a java.sql.Timestamp object.
1103: *
1104: * @param columnIndex the first column is 1, the second is 2, ...
1105: * @return the column value; if the value is SQL NULL, the result is null
1106: * @exception SQLException if a database-access error occurs.
1107: */
1108: public java.sql.Timestamp getTimestamp(int columnIndex)
1109: throws SQLException {
1110: Timestamp result;
1111:
1112: try {
1113: Object tmp = currentRow.getElementAt(columnIndex);
1114:
1115: lastGetWasNull = false;
1116: if (tmp == null) {
1117: lastGetWasNull = true;
1118: result = null;
1119: } else if (tmp instanceof Timestamp) {
1120: result = (Timestamp) tmp;
1121: } else {
1122: throw new SQLException("Can't convert column "
1123: + columnIndex + " from "
1124: + tmp.getClass().getName() + " to Timestamp");
1125: }
1126: } catch (TdsException e) {
1127: throw new SQLException(e.getMessage());
1128: }
1129: return result;
1130: }
1131:
1132: /**
1133: * Get the value of a column in the current row as a java.sql.Timestamp object.
1134: *
1135: * @param columnName is the SQL name of the column
1136: * @return the column value; if the value is SQL NULL, the result is null
1137: * @exception SQLException if a database-access error occurs.
1138: */
1139: public java.sql.Timestamp getTimestamp(String columnName)
1140: throws SQLException {
1141: return getTimestamp(findColumn(columnName));
1142: }
1143:
1144: /**
1145: * A column value can be retrieved as a stream of Unicode characters
1146: * and then read in chunks from the stream. This method is particularly
1147: * suitable for retrieving large LONGVARCHAR values. The JDBC driver will
1148: * do any necessary conversion from the database format into Unicode.
1149: *
1150: * <P><B>Note:</B> All the data in the returned stream must be
1151: * read prior to getting the value of any other column. The next
1152: * call to a get method implicitly closes the stream. . Also, a
1153: * stream may return 0 for available() whether there is data
1154: * available or not.
1155: *
1156: * @param columnIndex the first column is 1, the second is 2, ...
1157: * @return a Java input stream that delivers the database column value
1158: * as a stream of two byte Unicode characters. If the value is SQL NULL
1159: * then the result is null.
1160: * @exception SQLException if a database-access error occurs.
1161: */
1162: public java.io.InputStream getUnicodeStream(int columnIndex)
1163: throws SQLException {
1164: String val = getString(columnIndex);
1165: if (val == null)
1166: return null;
1167: try {
1168: return new ByteArrayInputStream(val.getBytes("UTF8"));
1169: } catch (UnsupportedEncodingException e) {
1170: // plain impossible with UTF-8
1171: return null;
1172: }
1173: }
1174:
1175: /**
1176: * A column value can be retrieved as a stream of Unicode characters
1177: * and then read in chunks from the stream. This method is particularly
1178: * suitable for retrieving large LONGVARCHAR values. The JDBC driver will
1179: * do any necessary conversion from the database format into Unicode.
1180: *
1181: * <P><B>Note:</B> All the data in the returned stream must
1182: * be read prior to getting the value of any other column. The
1183: * next call to a get method implicitly closes the stream.
1184: *
1185: * @param columnName is the SQL name of the column
1186: * @return a Java input stream that delivers the database column value
1187: * as a stream of two byte Unicode characters. If the value is SQL NULL
1188: * then the result is null.
1189: * @exception SQLException if a database-access error occurs.
1190: */
1191: public java.io.InputStream getUnicodeStream(String columnName)
1192: throws SQLException {
1193: return getUnicodeStream(findColumn(columnName));
1194: }
1195:
1196: //=====================================================================
1197: // Advanced features:
1198: //=====================================================================
1199:
1200: /**
1201: * <p>The first warning reported by calls on this ResultSet is
1202: * returned. Subsequent ResultSet warnings will be chained to this
1203: * SQLWarning.
1204: *
1205: * <P>The warning chain is automatically cleared each time a new
1206: * row is read.
1207: *
1208: * <P><B>Note:</B> This warning chain only covers warnings caused
1209: * by ResultSet methods. Any warning caused by statement methods
1210: * (such as reading OUT parameters) will be chained on the
1211: * Statement object.
1212: *
1213: * @return the first SQLWarning or null
1214: * @exception SQLException if a database-access error occurs.
1215: */
1216: public SQLWarning getWarnings() throws SQLException {
1217: return warningChain.getWarnings();
1218: }
1219:
1220: /**
1221: * A ResultSet is initially positioned before its first row; the
1222: * first call to next makes the first row the current row; the
1223: * second call makes the second row the current row, etc.
1224: *
1225: * <P>If an input stream from the previous row is open, it is
1226: * implicitly closed. The ResultSet's warning chain is cleared
1227: * when a new row is read.
1228: *
1229: * @return true if the new current row is valid; false if there
1230: * are no more rows
1231: * @exception SQLException if a database-access error occurs.
1232: */
1233: public boolean next() throws SQLException {
1234: boolean result = false;
1235: SQLException exception = null;
1236: boolean done = false;
1237: boolean wasCanceled = false;
1238:
1239: if (isClosed) {
1240: throw new SQLException("result set is closed");
1241: }
1242: if (!hitEndOfData) {
1243: try {
1244: clearWarnings();
1245:
1246: Context context = new Context();
1247: context.setColumnInfo(columnsInfo);
1248:
1249: // Keep eating garbage and warnings until we reach the next result
1250: while (!tds.isResultSet() && !tds.isEndOfResults()
1251: && !tds.isResultRow()) {
1252: // RMK 2000-06-08: don't choke on RET_STAT package.
1253: if (tds.isProcId()
1254: || tds.peek() == Tds.TDS_RET_STAT_TOKEN) {
1255: tds.processSubPacket();
1256: } else if (tds.isDoneInProc()) {
1257: PacketDoneInProcResult tmp = (PacketDoneInProcResult) tds
1258: .processSubPacket();
1259: } else if (tds.isTextUpdate()) {
1260: PacketResult tmp1 = (PacketResult) tds
1261: .processSubPacket();
1262: } else if (tds.isMessagePacket()
1263: || tds.isErrorPacket()) {
1264: PacketMsgResult tmp = (PacketMsgResult) tds
1265: .processSubPacket();
1266: exception = warningChain.addOrReturn(tmp);
1267: } else {
1268: throw new SQLException(
1269: "Protocol confusion. "
1270: + "Got a 0x"
1271: + Integer.toHexString((tds
1272: .peek() & 0xff))
1273: + " packet");
1274: }
1275: } // end while
1276:
1277: if (exception != null) {
1278: throw exception;
1279: }
1280:
1281: if (tds.isResultRow()) {
1282: currentRow = (PacketRowResult) tds
1283: .processSubPacket(context);
1284: result = true;
1285: done = true;
1286: } else if (tds.isEndOfResults()) {
1287: PacketResult tmp = tds.processSubPacket(context);
1288: currentRow = null;
1289: done = true;
1290: hitEndOfData = true;
1291: wasCanceled = wasCanceled
1292: || ((PacketEndTokenResult) tmp)
1293: .wasCanceled();
1294: } else if (!tds.isResultSet()) {
1295: throw new SQLException("Protocol confusion. "
1296: + "Got a 0x"
1297: + Integer.toHexString((tds.peek() & 0xff))
1298: + " packet");
1299: }
1300:
1301: if (exception != null) {
1302: throw exception;
1303: }
1304: } catch (java.io.IOException e) {
1305: throw new SQLException(e.getMessage());
1306: } catch (TdsException e) {
1307: e.printStackTrace();
1308: throw new SQLException(e.getMessage());
1309: }
1310: if (wasCanceled) {
1311: throw new SQLException(
1312: "Query was canceled or timed out.");
1313: }
1314: }
1315: return result;
1316: }
1317:
1318: /**
1319: * A column may have the value of SQL NULL; wasNull reports whether
1320: * the last column read had this special value.
1321: * Note that you must first call getXXX on a column to try to read
1322: * its value and then call wasNull() to find if the value was
1323: * the SQL NULL.
1324: *
1325: * @return true if last column read was SQL NULL
1326: * @exception SQLException if a database-access error occurs.
1327: */
1328: public boolean wasNull() throws SQLException {
1329: return lastGetWasNull;
1330: }
1331: }
|