Quadcap Embeddable Database

com/quadcap/jdbc/ResultSet.java

Go to the documentation of this file.
00001 package com.quadcap.jdbc; 00002 00003 /* Copyright 1999 - 2003 Quadcap Software. All rights reserved. 00004 * 00005 * This software is distributed under the Quadcap Free Software License. 00006 * This software may be used or modified for any purpose, personal or 00007 * commercial. Open Source redistributions are permitted. Commercial 00008 * redistribution of larger works derived from, or works which bundle 00009 * this software requires a "Commercial Redistribution License"; see 00010 * http://www.quadcap.com/purchase. 00011 * 00012 * Redistributions qualify as "Open Source" under one of the following terms: 00013 * 00014 * Redistributions are made at no charge beyond the reasonable cost of 00015 * materials and delivery. 00016 * 00017 * Redistributions are accompanied by a copy of the Source Code or by an 00018 * irrevocable offer to provide a copy of the Source Code for up to three 00019 * years at the cost of materials and delivery. Such redistributions 00020 * must allow further use, modification, and redistribution of the Source 00021 * Code under substantially the same terms as this license. 00022 * 00023 * Redistributions of source code must retain the copyright notices as they 00024 * appear in each source code file, these license terms, and the 00025 * disclaimer/limitation of liability set forth as paragraph 6 below. 00026 * 00027 * Redistributions in binary form must reproduce this Copyright Notice, 00028 * these license terms, and the disclaimer/limitation of liability set 00029 * forth as paragraph 6 below, in the documentation and/or other materials 00030 * provided with the distribution. 00031 * 00032 * The Software is provided on an "AS IS" basis. No warranty is 00033 * provided that the Software is free of defects, or fit for a 00034 * particular purpose. 00035 * 00036 * Limitation of Liability. Quadcap Software shall not be liable 00037 * for any damages suffered by the Licensee or any third party resulting 00038 * from use of the Software. 00039 */ 00040 00041 import java.io.Externalizable; 00042 import java.io.IOException; 00043 import java.io.ObjectInput; 00044 import java.io.ObjectOutput; 00045 import java.io.InputStream; 00046 import java.io.Reader; 00047 00048 import java.util.Calendar; 00049 import java.util.Vector; 00050 00051 import java.math.BigDecimal; 00052 import java.math.BigInteger; 00053 00054 //#ifndef JDK11 00055 import java.util.Map; 00056 00057 import java.sql.Array; 00058 import java.sql.Blob; 00059 import java.sql.Clob; 00060 import java.sql.Ref; 00061 //#endif 00062 00063 import java.sql.Date; 00064 import java.sql.SQLException; 00065 import java.sql.SQLWarning; 00066 import java.sql.Time; 00067 import java.sql.Timestamp; 00068 import java.sql.Types; 00069 00070 import com.quadcap.util.Debug; 00071 00072 import com.quadcap.sql.Column; 00073 import com.quadcap.sql.Cursor; 00074 import com.quadcap.sql.Database; 00075 import com.quadcap.sql.QedResultSet; 00076 import com.quadcap.sql.Row; 00077 import com.quadcap.sql.SelectExpression; 00078 import com.quadcap.sql.Session; 00079 00080 import com.quadcap.sql.types.*; 00081 00082 import com.quadcap.sql.file.BlockFile; 00083 import com.quadcap.sql.file.Log; 00084 00085 import com.quadcap.io.AsciiInputStream; 00086 import com.quadcap.io.AsciiReader; 00087 import com.quadcap.io.InputStreamReader; 00088 import com.quadcap.io.ReaderInputStream; 00089 00090 import com.quadcap.util.ConfigNumber; 00091 import com.quadcap.util.Util; 00092 00093 /** 00094 * This class implements the <code>java.sql.ResultSet</code> interface, 00095 * and provides facilities for accessing the results of a SQL query. 00096 * QED supports updateable <code>ResultSet</code>s. 00097 * 00098 * <p>TODO: update{BC}lob</p> 00099 * 00100 * @author Stan Bailes 00101 */ 00102 public class ResultSet implements QedResultSet { 00103 /*{com.quadcap.qed.Trace-vars.xml-1056} 00104 * <config-var> 00105 * <config-name>qed.trace.ResultSet</config-name> 00106 * <config-dflt>0</config-dflt> 00107 * <config-desc> 00108 * <pre> 00109 * bit 0: API execution 00110 * bit 1: findColumn 00111 * bit 2: rows 00112 * bit 3: row + column -> object 00113 * bit 5: updateObject(row, col, obj) 00114 * </pre> 00115 * </config-desc> 00116 * </config-var> 00117 */ 00118 //#ifdef DEBUG 00119 static final ConfigNumber trace = 00120 ConfigNumber.find("qed.trace.ResultSet", "0"); 00121 //#endif 00122 00123 Statement stmt; 00124 Cursor cursor; 00125 Row row; 00126 int rowNum = 0; 00127 boolean onInsertRow = false; 00128 boolean onUpdateRow = false; 00129 boolean bf = false; 00130 boolean rowUpdated = false; 00131 boolean rowDeleted = false; 00132 00133 Row insertRow = null; 00134 boolean wasNull = false; 00135 Object lock = new Object(); 00136 int rowCount = 0; 00137 00138 00139 /** 00140 * Constructor that wraps a cursor. Used internally to QED. 00141 * @deprecated 00142 * @param cursor a cursor 00143 */ 00144 public ResultSet(Cursor cursor) { 00145 this.cursor = cursor; 00146 } 00147 00148 /** 00149 * My database session/connection 00150 */ 00151 final private Session getSession() { 00152 return cursor.getSession(); 00153 } 00154 00155 /** 00156 * I have been granted access to The File itself. I am most humble. 00157 */ 00158 final private BlockFile getBlockFile() { 00159 return getSession().getFile(); 00160 } 00161 00162 /** 00163 * My "handle" for this op. 00164 */ 00165 final private long getTransactionId() throws IOException, SQLException { 00166 return getSession().getTransactionId(); 00167 } 00168 00169 /** 00170 * Return the current cursor row. 00171 */ 00172 final Row getCursorRow() throws SQLException { 00173 if (onInsertRow) { 00174 if (insertRow == null) { 00175 insertRow = new Row(cursor.getColumnCount()); 00176 for (int i = 1; i <= insertRow.size(); i++) { 00177 insertRow.set(i, ValueNull.valueNull); 00178 } 00179 } 00180 return insertRow; 00181 } else if (onUpdateRow) { 00182 if (insertRow == null) { 00183 insertRow = new Row(cursor.getColumnCount()); 00184 for (int i = 1; i < insertRow.size(); i++) { 00185 insertRow.set(i, row.item(i)); 00186 } 00187 } 00188 return insertRow; 00189 } else { 00190 if (row == null) { 00191 row = cursor.getRow(); 00192 //#ifdef DEBUG 00193 if (trace.bit(2)) { 00194 Debug.println("cursor.getRow: " + row); 00195 } 00196 //#endif 00197 } 00198 return row; 00199 } 00200 } 00201 00202 /** 00203 * Return the value in the specified column. 00204 */ 00205 Value getValue(int col) throws SQLException { 00206 Value v = null; 00207 Row r = getCursorRow(); 00208 if (r != null) { 00209 v = r.item(col); 00210 if (v != null) { 00211 wasNull = Value.isNull(v); 00212 } else { 00213 throw new SQLException("Can't return column " + col); 00214 } 00215 } else { 00216 throw new SQLException("ResultSet isn't positioned on a valid row"); 00217 } 00218 return v; 00219 } 00220 00221 /** 00222 * Convert the value in the specified column to the given type. 00223 */ 00224 final Value getValue(int col, Type type) throws SQLException { 00225 return type.convert(getValue(col)); 00226 } 00227 00228 /** 00229 * Return the value in the specified column as a Java "Object" 00230 * after performing the indicated type conversion. 00231 */ 00232 public Object getObject(int col, Type type) throws SQLException { 00233 Value v = getValue(col, type); 00234 //#ifdef DEBUG 00235 if (trace.bit(3)) { 00236 Debug.println("get(" + col + ", " + type.getTypeName() + 00237 ") = " + v); 00238 } 00239 //#endif 00240 return v.asJavaObject(); 00241 } 00242 00243 //------------------------------------------------------------------ 00244 // java.sql.ResultSet implementation 00245 //------------------------------------------------------------------ 00246 00247 /** 00248 * Position the resultset to the specified row. If positive, the 00249 * row number indicates an offset from the beginning of the 00250 * <code>ResultSet</code> (row 1 is the first row). If negative, 00251 * the row number indicates an offset from the end of the 00252 * <code>ResultSet</code> (row -1 is the last row). 00253 * <p> 00254 * In general, this release of QED supports absolute positioning 00255 * to the first row of the <code>ResultSet</code> only. 00256 * 00257 * @param row the row number 00258 * @return true if we're positioned on a valid row, false if we're 00259 * before the first row or after the last row. 00260 * @exception SQLException if row is zero. 00261 */ 00262 public boolean absolute(int x) throws SQLException { 00263 checkScrollable(); 00264 //#ifdef DEBUG 00265 if (trace.bit(0)) { 00266 Debug.println("ResultSet.absolute(" + x + ")"); 00267 //Debug.println("cursor: " + cursor.getClass() + ": " + cursor); 00268 } 00269 //#endif 00270 if (x == 0) { 00271 throw new SQLException("ResultSet.absolute(0), bad parameter"); 00272 } 00273 rowNum = x; 00274 resetRow(); 00275 bf = false; 00276 return cursor.absolute(rowNum); 00277 } 00278 00279 private final void resetRow() { 00280 onInsertRow = false; 00281 onUpdateRow = false; 00282 row = null; 00283 rowUpdated = false; 00284 rowDeleted = false; 00285 } 00286 00287 00288 /** 00289 * Position the cursor to the end of the <code>ResultSet</code>, 00290 * after the last row. Our underlying cursor doesn't support this 00291 * operation, so we use 'absolute()' to get to the end, then 'next()' 00292 * to move past the end. 00293 * 00294 * @exception SQLException may be thrown. 00295 */ 00296 public void afterLast() throws SQLException { 00297 checkScrollable(); 00298 cursor.afterLast(); 00299 resetRow(); 00300 bf = false; 00301 } 00302 00303 /** 00304 * Position the cursor to the beginning of the <code>ResultSet</code>, 00305 * before the first row. 00306 * 00307 * @exception SQLException may be thrown. 00308 */ 00309 public void beforeFirst() throws SQLException { 00310 checkScrollable(); 00311 cursor.beforeFirst(); 00312 resetRow(); 00313 bf = true; 00314 } 00315 00316 /** 00317 * This function rolls back row updates, as long as 00318 * <code>updateRow()</code> hasn't been called yet. 00319 * 00320 * @exception SQLException may be thrown 00321 */ 00322 public void cancelRowUpdates() throws SQLException { 00323 if (onInsertRow) { 00324 throw new SQLException("ResultSet.cancelRowUpdates() called " + 00325 "while on insert row"); 00326 } 00327 resetRow(); 00328 } 00329 00330 /** 00331 * Clears all warnings that have been reported on this 00332 * <code>ResultSet</code> object. 00333 * QED doesn't currently throw any SQLWarnings, 00334 * so this operation does nothing. 00335 */ 00336 public void clearWarnings() throws SQLException { 00337 } 00338 00339 /** 00340 * We will clean up the user's mess for him. 00341 */ 00342 public void finalize() throws Throwable { 00343 try { 00344 if (cursor != null) close(); 00345 } catch (Throwable t) {} 00346 super.finalize(); 00347 } 00348 00349 /** 00350 * Close this <code>ResultSet</code> object. If this is an 00351 * updatable <code>ResultSet</code>, and the connection that this 00352 * <code>ResultSet</code> was created from is in <code>autoCommit</code> 00353 * mode, the transaction is committed at this time. 00354 * 00355 * @exception SQLException may be thrown 00356 */ 00357 public void close() throws SQLException { 00358 if (cursor == null) return; 00359 00360 Session s = cursor.getSession(); 00361 00362 synchronized (lock) { 00363 cursor = null; 00364 if (s != null) { 00365 try { 00366 s.endStatement(false); 00367 } catch (IOException e) { 00368 throw new SQLException(e.toString()); 00369 } 00370 } 00371 } 00372 } 00373 00374 /** 00375 * Delete the current row from the <code>ResultSet</code> and the 00376 * underlying database. 00377 * 00378 * @exception SQLException may be thrown 00379 */ 00380 public void deleteRow() throws SQLException { 00381 //#ifdef DEBUG 00382 if (trace.bit(0)) { 00383 Debug.println("ResultSet.deleteRow()"); 00384 } 00385 //#endif 00386 checkUpdatable(); 00387 if (onInsertRow) { 00388 throw new SQLException( 00389 "ResultSet.deleteRow(): Can't delete while on insert row"); 00390 } 00391 cursor.deleteRow(); 00392 rowDeleted = true; 00393 } 00394 00395 /** 00396 * Return the column number of the specified column. 00397 * 00398 * @param column the name of the column 00399 * @return the number of the column in the resultset. 00400 */ 00401 public int findColumn(String column) throws SQLException { 00402 Column col = cursor.getColumn(column.toUpperCase()); 00403 if (col == null) { 00404 //#ifdef DEBUG 00405 SelectExpression.showCursor(cursor, true); 00406 //#endif 00407 throw new SQLException("Bad column name: " + column, 00408 "42000"); 00409 } 00410 int coln = col.getColumn(); 00411 //#ifdef DEBUG 00412 if (trace.bit(1)) { 00413 Debug.println("ResultSet.findColumn(" + column + ") = " + coln); 00414 } 00415 //#endif 00416 return coln; 00417 } 00418 00419 /** 00420 * Position the cursor on the first row of the <code>ResultSet</code>. 00421 * Return true if the <code>ResultSet</code> has at least one row. 00422 * 00423 * 00424 * @exception SQLException may be thrown 00425 */ 00426 public boolean first() throws SQLException { 00427 return absolute(1); 00428 } 00429 00430 /** 00431 * Return an <code>InputStream</code> object that can be used to read 00432 * the specified character value as a stream of ASCII bytes. 00433 * 00434 * @param col the column number 00435 * @return an <code>InputStream</code> 00436 * @exception SQLException may be thrown 00437 */ 00438 public InputStream getAsciiStream(int col) throws SQLException { 00439 Value v = getValue(col); 00440 if (Value.isNull(v)) return null; 00441 return new AsciiInputStream(getCharacterStream(col)); 00442 } 00443 00444 /** 00445 * Return an <code>InputStream</code> object that can be used to read 00446 * the specified character value as a stream of ASCII bytes. 00447 * 00448 * @param column the column name 00449 * @return an <code>InputStream</code> 00450 * @exception SQLException may be thrown 00451 */ 00452 public InputStream getAsciiStream(String column) throws SQLException { 00453 return getAsciiStream(findColumn(column)); 00454 } 00455 00456 /** 00457 * Retrieve the specified column as a <code>BigDecimal</code> object. 00458 * 00459 * @param col the column number 00460 * @return the column's value in the current row 00461 * @exception SQLException may be thrown 00462 */ 00463 public BigDecimal getBigDecimal(int col) throws SQLException { 00464 try { 00465 ValueScaledInteger v = 00466 (ValueScaledInteger)getValue(col, TypeDecimal.typeDecimal); 00467 if (v != null) return v.bigDecimalValue(); 00468 } catch (ClassCastException e) { 00469 if (wasNull) return null; 00470 } 00471 throw new SQLException("Can't return column " + col + 00472 " as BigDecimal", "22003"); 00473 } 00474 00475 /** 00476 * @deprecated 00477 */ 00478 public BigDecimal getBigDecimal(int col, int scale) throws SQLException { 00479 BigDecimal big = getBigDecimal(col); 00480 return big.setScale(scale); 00481 } 00482 00483 /** 00484 * Retrieve the specified column as a <code>BigDecimal</code> object. 00485 * 00486 * @param column the column name 00487 * @return the column's value in the current row 00488 * @exception SQLException may be thrown 00489 */ 00490 public BigDecimal getBigDecimal(String column) throws SQLException { 00491 return getBigDecimal(findColumn(column)); 00492 } 00493 00494 /** 00495 * @deprecated 00496 */ 00497 public BigDecimal getBigDecimal(String column, int scale) 00498 throws SQLException 00499 { 00500 return getBigDecimal(findColumn(column), scale); 00501 } 00502 00503 /** 00504 * Return an <code>InputStream</code> object that can be used to read 00505 * the specified column value as a stream of bytes. 00506 * 00507 * @param col the column number 00508 * @return an <code>InputStream</code> 00509 * @exception SQLException may be thrown 00510 */ 00511 public InputStream getBinaryStream(int col) throws SQLException { 00512 try { 00513 Value v = getValue(col); 00514 if (Value.isNull(v)) return null; 00515 int type = v.getType().getJDBCType(); 00516 switch (type) { 00517 case Types.CHAR: 00518 case Types.VARCHAR: 00519 return ((ValueString)v).getBinaryStream(); 00520 case Types.BINARY: 00521 case Types.VARBINARY: 00522 return ((ValueOctets)v).getBinaryStream(); 00523 //-//#ifdef JDK11 00524 //- case Type.BLOB: 00525 //#else 00526 case Types.BLOB: 00527 //#endif 00528 return ((ValueBlob)v).getBinaryStream(); 00529 //-//#ifdef JDK11 00530 //- case Type.CLOB: 00531 //#else 00532 case Types.CLOB: 00533 //#endif 00534 return ((ValueClob)v).getBinaryStream(); 00535 default: 00536 throw new ValueException("Can't convert: " + type + 00537 " to binary stream"); 00538 } 00539 } catch (ValueException e) { 00540 throw new SQLException("Can't return column " + col + 00541 " as Binary Stream", "22003"); 00542 } 00543 } 00544 00545 /** 00546 * Return an <code>InputStream</code> object that can be used to read 00547 * the specified column value as a stream of bytes. 00548 * 00549 * @param column the column name 00550 * @return an <code>InputStream</code> 00551 * @exception SQLException may be thrown 00552 */ 00553 public InputStream getBinaryStream(String column) throws SQLException { 00554 return getBinaryStream(findColumn(column)); 00555 } 00556 00557 /** 00558 * Retrieve the specified column as a <code>boolean</code>. 00559 * 00560 * @param col the column number 00561 * @return the column's value in the current row 00562 * @exception SQLException may be thrown 00563 */ 00564 public boolean getBoolean(int col) throws SQLException { 00565 Object obj = getObject(col); 00566 if (obj == null) return false; 00567 if (obj instanceof Boolean) { 00568 return ((Boolean)obj).booleanValue(); 00569 } 00570 Number num = asNumber(obj); 00571 if (num != null) { 00572 return num.doubleValue() != 0; 00573 } 00574 return obj.toString().toLowerCase().equals("true"); 00575 } 00576 00577 /** 00578 * Retrieve the specified column as a <code>boolean</code>. 00579 * 00580 * @param column the column name 00581 * @return the column's value in the current row 00582 * @exception SQLException may be thrown 00583 */ 00584 public boolean getBoolean(String column) throws SQLException { 00585 return getBoolean(findColumn(column)); 00586 } 00587 00588 /** 00589 * Are you a number? 00590 * 00591 * Any sort of number? 00592 * 00593 * Even some fancy schmancy number? 00594 * 00595 * Are you? 00596 * 00597 * Or not. 00598 */ 00599 final Number asNumber(Object obj) { 00600 if (obj instanceof Number) return (Number)obj; 00601 if (obj instanceof String) { 00602 try { 00603 return new Long(obj.toString()); 00604 } catch (NumberFormatException e) { 00605 } 00606 } 00607 if (obj instanceof byte[]) { 00608 return new BigDecimal(new BigInteger((byte[])obj)); 00609 } 00610 if (obj instanceof Boolean) { 00611 int val = ((Boolean)obj).booleanValue() ? 1 : 0; 00612 return new Integer(val); 00613 } 00614 return null; 00615 } 00616 00617 /** 00618 * Retrieve the specified column as a <code>byte</code>. 00619 * 00620 * @param col the column number 00621 * @return the column's value in the current row 00622 * @exception SQLException may be thrown 00623 */ 00624 public byte getByte(int col) throws SQLException { 00625 try { 00626 ValueByte v = (ValueByte)getValue(col, TypeTinyInt.typeTinyInt); 00627 if (v != null) return v.byteValue(); 00628 } catch (ClassCastException e) { 00629 if (wasNull) return 0; 00630 } 00631 throw new SQLException("Can't return column " + col + 00632 " as byte", "22003"); 00633 } 00634 00635 /** 00636 * Retrieve the specified column as a <code>byte</code>. 00637 * 00638 * @param column the column name 00639 * @return the column's value in the current row 00640 * @exception SQLException may be thrown 00641 */ 00642 public byte getByte(String column) throws SQLException { 00643 return getByte(findColumn(column)); 00644 } 00645 00646 /** 00647 * Retrieve the specified column as an array of <code>byte</code>s. 00648 * 00649 * @param col the column number 00650 * @return the column's value in the current row 00651 * @exception SQLException may be thrown 00652 */ 00653 public byte[] getBytes(int col) throws SQLException { 00654 try { 00655 Value v1 = getValue(col, TypeVarBinary.typeVarBinary); 00656 if (wasNull) return null; 00657 ValueOctets v = (ValueOctets)v1; 00658 return v.getBytes(); 00659 } catch (Exception e) { 00660 throw new SQLException("Can't return column " + col + 00661 " as bytes", "22003"); 00662 } 00663 } 00664 00665 /** 00666 * Retrieve the specified column as an array of <code>byte</code>s. 00667 * 00668 * @param column the column name 00669 * @return the column's value in the current row 00670 * @exception SQLException may be thrown 00671 */ 00672 public byte[] getBytes(String column) throws SQLException { 00673 return getBytes(findColumn(column)); 00674 } 00675 00676 /** 00677 * Return a <code>Reader</code> object that can be used to read 00678 * the specified column value as a stream of characters. 00679 * 00680 * @param col the column number 00681 * @return a <code>Reader</code> 00682 * @exception SQLException may be thrown 00683 */ 00684 public Reader getCharacterStream(int col) throws SQLException { 00685 try { 00686 Value v = getValue(col); 00687 if (Value.isNull(v)) return null; 00688 int type = v.getType().getJDBCType(); 00689 switch (type) { 00690 case Types.CHAR: 00691 case Types.VARCHAR: 00692 return ((ValueString)v).getCharacterStream(); 00693 case Types.BINARY: 00694 case Types.VARBINARY: 00695 return new ByteReader(((ValueOctets)v).getBinaryStream()); 00696 case Types.BLOB: 00697 return new ByteReader(((ValueBlob)v).getBinaryStream()); 00698 case Types.CLOB: 00699 return ((ValueClob)v).getCharacterStream(); 00700 default: 00701 throw new ValueException("Can't convert: " + type + 00702 " to character stream"); 00703 } 00704 } catch (ValueException e) { 00705 throw new SQLException("Can't return column " + col + 00706 " as character stream", "22003"); 00707 } 00708 00709 } 00710 00711 /** 00712 * Return a <code>Reader</code> object that can be used to read 00713 * the specified column value as a stream of characters. 00714 * 00715 * @param column the column name 00716 * @return a <code>Reader</code> 00717 * @exception SQLException may be thrown 00718 */ 00719 public Reader getCharacterStream(String column) throws SQLException { 00720 return getCharacterStream(findColumn(column)); 00721 } 00722 00723 /** 00724 * QED doesn't support named cursors, so this method throws a 00725 * SQLException "not implemented" 00726 * 00727 * @return never 00728 * @exception SQLException not implemented 00729 */ 00730 public String getCursorName() throws SQLException { 00731 throw new SQLException("named cursors not supported", "0A000"); 00732 } 00733 00734 /** 00735 * Retrieve the specified column as a <code>Date</code> object. 00736 * 00737 * @param col the column number 00738 * @return the column's value in the current row 00739 * @exception SQLException may be thrown 00740 */ 00741 public Date getDate(int col) throws SQLException { 00742 Date d = null; 00743 Value v = getValue(col); 00744 if (!Value.isNull(v)) { 00745 try { 00746 ValueDate vd = (ValueDate)v.convert(TypeDate.typeDate); 00747 d = new Date(vd.getTime()); 00748 } catch (Exception e) { 00749 throw new SQLException("Can't convert column " + col + 00750 " to date", "22003"); 00751 } 00752 } 00753 return d; 00754 } 00755 00756 /** 00757 * Retrieve the specified column as a <code>Date</code> object. 00758 * 00759 * @param col the column number 00760 * @param c a <code>Calendar<code> object that is used for converting 00761 * the database date to the local timezone. The database date is 00762 * adjusted based on the <code>Calendar</code> timezone and DST offset. 00763 * @return the column's value in the current row 00764 * @exception SQLException may be thrown 00765 */ 00766 public Date getDate(int col, Calendar c) throws SQLException { 00767 Date d = getDate(col); 00768 if (d != null) { 00769 long t = d.getTime(); 00770 c.setTime(d); 00771 t += (c.get(Calendar.ZONE_OFFSET) + c.get(Calendar.DST_OFFSET)); 00772 d = new Date(t); 00773 } 00774 return d; 00775 } 00776 00777 /** 00778 * Retrieve the specified column as a <code>Date</code> object. 00779 * 00780 * @param column the column name 00781 * @return the column's value in the current row 00782 * @exception SQLException may be thrown 00783 */ 00784 public Date getDate(String column) throws SQLException { 00785 return getDate(findColumn(column)); 00786 } 00787 00788 /** 00789 * Retrieve the specified column as a <code>Date</code> object. 00790 * 00791 * @param column the column name 00792 * @param c a <code>Calendar<code> object that is used for converting 00793 * the database date to the local timezone. The database date is 00794 * adjusted based on the <code>Calendar</code> timezone and DST offset. 00795 * @return the column's value in the current row 00796 * @exception SQLException may be thrown 00797 */ 00798 public Date getDate(String column, Calendar c) throws SQLException { 00799 return getDate(findColumn(column), c); 00800 } 00801 00802 /** 00803 * Retrieve the specified column as a <code>double</code>. 00804 * 00805 * @param col the column number 00806 * @return the column's value in the current row 00807 * @exception SQLException may be thrown 00808 */ 00809 public double getDouble(int col) throws SQLException { 00810 try { 00811 ValueDouble v = (ValueDouble)getValue(col, TypeReal.typeDouble); 00812 if (v != null) return v.doubleValue(); 00813 } catch (ClassCastException e) { 00814 if (wasNull) return 0; 00815 } 00816 throw new SQLException("Can't return column " + col + 00817 " as double", "22003"); 00818 } 00819 00820 /** 00821 * Retrieve the specified column as a <code>double</code>. 00822 * 00823 * @param column the column name 00824 * @return the column's value in the current row 00825 * @exception SQLException may be thrown 00826 */ 00827 public double getDouble(String column) throws SQLException { 00828 return getDouble(findColumn(column)); 00829 } 00830 00831 /** 00832 * QED, being an embedded driver, fetches rows only when they are 00833 * needed, with no performance penalty. Thus, the fetch size is 00834 * always <code>one</code>. 00835 * 00836 * @return one. 00837 */ 00838 public int getFetchSize() { 00839 return 1; 00840 } 00841 00842 /** 00843 * Retrieve the specified column as a <code>float</code>. 00844 * 00845 * @param col the column number 00846 * @return the column's value in the current row 00847 * @exception SQLException may be thrown 00848 */ 00849 public float getFloat(int col) throws SQLException { 00850 try { 00851 ValueFloat v = (ValueFloat)getValue(col, TypeReal.typeFloat); 00852 if (v != null) return v.floatValue(); 00853 } catch (ClassCastException e) { 00854 if (wasNull) return 0; 00855 } 00856 throw new SQLException("Can't return column " + col + 00857 " as float", "22003"); 00858 } 00859 00860 /** 00861 * Retrieve the specified column as a <code>float</code>. 00862 * 00863 * @param column the column name 00864 * @return the column's value in the current row 00865 * @exception SQLException may be thrown 00866 */ 00867 public float getFloat(String column) throws SQLException { 00868 return getFloat(findColumn(column)); 00869 } 00870 00871 /** 00872 * Retrieve the specified column as an <code>int</code>. 00873 * 00874 * @param col the column number 00875 * @return the column's value in the current row 00876 * @exception SQLException may be thrown 00877 */ 00878 public int getInt(int col) throws SQLException { 00879 try { 00880 ValueInteger v = (ValueInteger)getValue(col, TypeInt.typeInt); 00881 if (v != null) return v.intValue(); 00882 } catch (ClassCastException e) { 00883 if (wasNull) return 0; 00884 } 00885 throw new SQLException("Can't return column " + col + 00886 " as int", "22003"); 00887 } 00888 00889 /** 00890 * Retrieve the specified column as an <code>int</code>. 00891 * 00892 * @param column the column name 00893 * @return the column's value in the current row 00894 * @exception SQLException may be thrown 00895 */ 00896 public int getInt(String column) throws SQLException { 00897 return getInt(findColumn(column)); 00898 } 00899 00900 /** 00901 * Retrieve the specified column as a <code>long</code>. 00902 * 00903 * @param col the column number 00904 * @return the column's value in the current row 00905 * @exception SQLException may be thrown 00906 */ 00907 public long getLong(int col) throws SQLException { 00908 try { 00909 ValueLong v = (ValueLong)getValue(col, TypeBigInt.typeBigInt); 00910 if (v != null) return v.longValue(); 00911 } catch (ClassCastException e) { 00912 if (wasNull) return 0; 00913 } 00914 throw new SQLException("Can't return column " + col + 00915 " as long", "22003"); 00916 } 00917 00918 /** 00919 * Retrieve the specified column as a <code>long</code>. 00920 * 00921 * @param column the column name 00922 * @return the column's value in the current row 00923 * @exception SQLException may be thrown 00924 */ 00925 public long getLong(String column) throws SQLException { 00926 return getLong(findColumn(column)); 00927 } 00928 00929 /** 00930 * Return a <code>ResultSetMetaData</code> object that can be used 00931 * to obtain information about the columns of this 00932 * <code>ResultSet</code>. 00933 * 00934 * @return a <code>ResultSetMetaData</code> object that describes 00935 * the columns of this <code>ResultSet</code>. 00936 * @exception SQLException may be thrown 00937 */ 00938 public java.sql.ResultSetMetaData getMetaData() throws SQLException { 00939 return new ResultSetMetaData(cursor); 00940 } 00941 00942 /** 00943 * Retrieve the specified column as a Java <code>Object</code>. 00944 * The type of the object is based on the underlying SQL datatype, 00945 * using the conversions as specified by JDBC. 00946 * 00947 * @param col the column number 00948 * @return the column's value in the current row 00949 * @exception SQLException may be thrown 00950 */ 00951 public Object getObject(int col) throws SQLException { 00952 try { 00953 Value v = getValue(col); 00954 //#ifdef DEBUG 00955 if (trace.bit(3)) { 00956 Debug.println("get(" + col + ") = " + v); 00957 } 00958 //#endif 00959 return v.asJavaObject(); 00960 } catch (SQLException e) { 00961 throw e; 00962 } catch (Exception ex) { 00963 Debug.print(ex); 00964 throw new SQLException("Invalid column index: " + col, "22003"); 00965 } 00966 } 00967 00968 /** 00969 * Retrieve the specified column as a Java <code>Object</code>. 00970 * The type of the object is based on the underlying SQL datatype, 00971 * using the conversions as specified by JDBC. 00972 * 00973 * @param column the column name 00974 * @return the column's value in the current row 00975 * @exception SQLException may be thrown 00976 */ 00977 public Object getObject(String column) throws SQLException { 00978 return getObject(findColumn(column)); 00979 } 00980 00981 /** 00982 * Return the row number of the current row in the 00983 * <code>ResultSet</code>. 00984 */ 00985 public int getRow() throws SQLException { 00986 if (rowNum < 0) { 00987 int siz = (int)cursor.size(); 00988 if (siz >= 0) { 00989 rowNum = siz + 1 + rowNum; 00990 } else { 00991 throw new SQLException( 00992 "Sorry, but the underlying cursor (" + 00993 cursor + ") doesn't supply row number information"); 00994 } 00995 } 00996 return rowNum; 00997 } 00998 00999 /** 01000 * Retrieve the specified column as a <code>short</code>. 01001 * 01002 * @param col the column number 01003 * @return the column's value in the current row 01004 * @exception SQLException may be thrown 01005 */ 01006 public short getShort(int col) throws SQLException { 01007 try { 01008 ValueShort v = 01009 (ValueShort)getValue(col, TypeSmallInt.typeSmallInt); 01010 if (v != null) return v.shortValue(); 01011 } catch (ClassCastException e) { 01012 if (wasNull) return 0; 01013 } 01014 throw new SQLException("Can't return column " + col + 01015 " as short", "22003"); 01016 } 01017 01018 /** 01019 * Retrieve the specified column as a <code>short</code>. 01020 * 01021 * @param column the column name 01022 * @return the column's value in the current row 01023 * @exception SQLException may be thrown 01024 */ 01025 public short getShort(String column) throws SQLException { 01026 return getShort(findColumn(column)); 01027 } 01028 01029 /** 01030 * Attach this result set to its parent statement. 01031 */ 01032 public void setStatement(java.sql.Statement stmt) { 01033 this.stmt = (Statement)stmt; 01034 this.resultSetType = this.stmt.resultSetType; 01035 this.resultSetConcurrency = this.stmt.resultSetConcurrency; 01036 } 01037 01038 /** 01039 * Return the <code>Statement</code> object that generated this 01040 * <code>ResultSet</code>. 01041 * 01042 * @return the <code>Statement</code> object that generated this 01043 * <code>ResultSet</code> 01044 */ 01045 public java.sql.Statement getStatement() { 01046 return stmt; 01047 } 01048 01049 /** 01050 * Retrieve the specified column as a <code>String</code> object. 01051 * 01052 * @param col the column number 01053 * @return the column's value in the current row 01054 * @exception SQLException may be thrown 01055 */ 01056 public String getString(int col) throws SQLException { 01057 Object obj = getObject(col, TypeVarChar.typeVarChar); 01058 if (obj == null) return null; 01059 return obj.toString(); 01060 } 01061 01062 /** 01063 * Retrieve the specified column as a <code>String</code> object. 01064 * 01065 * @param column the column name 01066 * @return the column's value in the current row 01067 * @exception SQLException may be thrown 01068 */ 01069 public String getString(String column) throws SQLException { 01070 return getString(findColumn(column)); 01071 } 01072 01073 /** 01074 * Retrieve the specified column as a <code>Time</code> object. 01075 * 01076 * @param col the column number 01077 * @return the column's value in the current row 01078 * @exception SQLException may be thrown 01079 */ 01080 public Time getTime(int col) throws SQLException { 01081 Time t = null; 01082 Value v = getValue(col); 01083 if (!Value.isNull(v)) { 01084 try { 01085 ValueTime vt = (ValueTime)v.convert(TypeTime.typeTime); 01086 t = new Time(vt.getTime()); 01087 } catch (Exception e) { 01088 throw new SQLException("Can't convert column " + col + 01089 " to time", "22003"); 01090 } 01091 } 01092 return t; 01093 } 01094 01095 /** 01096 * Retrieve the specified column as a <code>Time</code> object. 01097 * 01098 * @param col the column number 01099 * @param c a <code>Calendar<code> object that is used for converting 01100 * the database time to the local timezone. The database time is 01101 * adjusted based on the <code>Calendar</code> timezone and DST offset. 01102 * @return the column's value in the current row 01103 * @exception SQLException may be thrown 01104 */ 01105 public Time getTime(int col, Calendar c) throws SQLException { 01106 Time d = getTime(col); 01107 if (d != null) { 01108 long t = d.getTime(); 01109 c.setTime(d); 01110 t += (c.get(Calendar.ZONE_OFFSET) + c.get(Calendar.DST_OFFSET)); 01111 d = new Time(t); 01112 } 01113 return d; 01114 } 01115 01116 /** 01117 * Retrieve the specified column as a <code>Time</code> object. 01118 * 01119 * @param column the column name 01120 * @return the column's value in the current row 01121 * @exception SQLException may be thrown 01122 */ 01123 public Time getTime(String column) throws SQLException { 01124 return getTime(findColumn(column)); 01125 } 01126 01127 /** 01128 * Retrieve the specified column as a <code>Time</code> object. 01129 * 01130 * @param column the column name 01131 * @param c a <code>Calendar<code> object that is used for converting 01132 * the database time to the local timezone. The database time is 01133 * adjusted based on the <code>Calendar</code> timezone and DST offset. 01134 * @return the column's value in the current row 01135 * @exception SQLException may be thrown 01136 */ 01137 public Time getTime(String column, Calendar c) throws SQLException { 01138 return getTime(findColumn(column)); 01139 } 01140 01141 /** 01142 * Retrieve the specified column as a <code>Timestamp</code> object. 01143 * 01144 * @param col the column number 01145 * @return the column's value in the current row 01146 * @exception SQLException may be thrown 01147 */ 01148 public Timestamp getTimestamp(int col) throws SQLException { 01149 Timestamp t = null; 01150 Value v = getValue(col, TypeTimestamp.typeTimestamp); 01151 if (!wasNull) { 01152 try { 01153 ValueTimestamp vt = (ValueTimestamp)v; 01154 t = new Timestamp(vt.getTime()); 01155 } catch (ClassCastException e) { 01156 throw new SQLException("Can't convert column " + col + 01157 " to timestamp", "22003"); 01158 } 01159 } 01160 return t; 01161 } 01162 01163 /** 01164 * Retrieve the specified column as a <code>Timestamp</code> object. 01165 * 01166 * @param col the column number 01167 * @param c a <code>Calendar<code> object that is used for converting 01168 * the database time to the local timezone. The database time is 01169 * adjusted based on the <code>Calendar</code> timezone and DST offset. 01170 * @return the column's value in the current row 01171 * @exception SQLException may be thrown 01172 */ 01173 public Timestamp getTimestamp(int col, Calendar c) throws SQLException { 01174 Timestamp d = getTimestamp(col); 01175 if (d != null) { 01176 long t = d.getTime(); 01177 c.setTime(d); 01178 t += (c.get(Calendar.ZONE_OFFSET) + c.get(Calendar.DST_OFFSET)); 01179 Timestamp r = new Timestamp(t); 01180 r.setNanos(d.getNanos()); 01181 d = r; 01182 } 01183 return d; 01184 } 01185 01186 /** 01187 * Retrieve the specified column as a <code>Timestamp</code> object. 01188 * 01189 * @param column the column name 01190 * @return the column's value in the current row 01191 * @exception SQLException may be thrown 01192 */ 01193 public Timestamp getTimestamp(String column) throws SQLException { 01194 return getTimestamp(findColumn(column)); 01195 } 01196 01197 /** 01198 * Retrieve the specified column as a <code>Timestamp</code> object. 01199 * 01200 * @param column the column name 01201 * @param c a <code>Calendar<code> object that is used for converting 01202 * the database time to the local timezone. The database time is 01203 * adjusted based on the <code>Calendar</code> timezone and DST offset. 01204 * @return the column's value in the current row 01205 * @exception SQLException may be thrown 01206 */ 01207 public Timestamp getTimestamp(String column, Calendar c) 01208 throws SQLException 01209 { 01210 return getTimestamp(findColumn(column), c); 01211 } 01212 01213 /** 01214 * @deprecated 01215 */ 01216 public InputStream getUnicodeStream(int col) throws SQLException { 01217 return getBinaryStream(col); 01218 } 01219 01220 /** 01221 * @deprecated 01222 */ 01223 public InputStream getUnicodeStream(String column) throws SQLException { 01224 return getBinaryStream(column); 01225 } 01226 01227 /** 01228 * QED doesn't implement any <code>SQLWarning</code>s, so this 01229 * function always returns <code>null</code> 01230 * 01231 * @return null 01232 */ 01233 public SQLWarning getWarnings() { 01234 return null; 01235 } 01236 01237 /** 01238 * If this <code>ResultSet</code> is currently positioned on the 01239 * insert row, then insert the current row into the database. 01240 * 01241 * @exception SQLException may be thrown if we're not currently 01242 * on the insert row, or if there is an error reported from the 01243 * database for the insert operation 01244 */ 01245 public void insertRow() throws SQLException { 01246 //#ifdef DEBUG 01247 if (trace.bit(0)) { 01248 Debug.println("ResultSet.insertRow()"); 01249 } 01250 //#endif 01251 checkUpdatable(); 01252 if (onInsertRow && insertRow != null) { 01253 cursor.insertRow(insertRow); 01254 rowUpdated = true; 01255 } else { 01256 throw new SQLException("Can't insert -- no insert row"); 01257 } 01258 } 01259 01260 /** 01261 * Update the current row (based on previous calls to the 01262 * <code>updateXXX</code> methods) in the database. 01263 * 01264 * @exception SQLException may be thrown if we're currently 01265 * on the insert row, or if there is an error reported from the 01266 * database for the update operation 01267 */ 01268 public void updateRow() throws SQLException { 01269 //#ifdef DEBUG 01270 if (trace.bit(0)) { 01271 Debug.println("ResultSet.updateRow()"); 01272 } 01273 //#endif 01274 checkUpdatable(); 01275 if (onInsertRow) { 01276 throw new SQLException( 01277 "updateRow(): Can't update while on insert row"); 01278 } 01279 Row rowX = onUpdateRow ? insertRow : row; 01280 if (rowX != null) { 01281 cursor.getSession().clearViewCheck(); 01282 cursor.updateRow(rowX); 01283 rowUpdated = true; 01284 } 01285 } 01286 01287 /** 01288 * Return <b>true</b> if this cursor is positioned after the 01289 * last row. 01290 * 01291 * @exception SQLException may be thrown 01292 */ 01293 public boolean isAfterLast() throws SQLException { 01294 checkScrollable(); 01295 return !onInsertRow && rowNum == 0 && !bf; 01296 } 01297 01298 /** 01299 * Return <b>true</b> if this cursor is positioned before the 01300 * first row. 01301 * 01302 * @exception SQLException may be thrown 01303 */ 01304 public boolean isBeforeFirst() throws SQLException { 01305 checkScrollable(); 01306 return !onInsertRow && rowNum == 0 && bf; 01307 } 01308 01309 /** 01310 * Return <b>true</b> if this cursor is positioned on the 01311 * first row. 01312 * 01313 * @exception SQLException may be thrown 01314 */ 01315 public boolean isFirst() throws SQLException { 01316 checkScrollable(); 01317 return !onInsertRow && rowNum == 1; 01318 } 01319 01320 /** 01321 * Return <b>true</b> if this cursor is positioned on the 01322 * last row. 01323 * 01324 * @exception SQLException may be thrown 01325 */ 01326 public boolean isLast() throws SQLException { 01327 checkScrollable(); 01328 if (!onInsertRow) { 01329 if (rowNum > 0) { 01330 int siz = (int)cursor.size(); 01331 if (siz > 0) { 01332 return rowNum == siz; 01333 } 01334 } else if (rowNum < 0) { 01335 return rowNum == -1; 01336 } 01337 if (!next()) { 01338 return true; 01339 } else { 01340 previous(); 01341 } 01342 } 01343 return false; 01344 } 01345 01346 /** 01347 * Move to the last row of the <code>ResultSet</code>. 01348 * 01349 * @return true if we manage to successfully position the 01350 * <code>ResultSet</code> on the last row 01351 * @exception SQLException is likely to be thrown ;-) 01352 */ 01353 public boolean last() throws SQLException { 01354 return absolute(-1); 01355 } 01356 01357 /** 01358 * If the cursor is on the insert row, move it back to the previous 01359 * position in the <code>ResultSet</code>. If the cursor is not 01360 * on the insert row, this function has no effect. 01361 */ 01362 public void moveToCurrentRow() { 01363 //#ifdef DEBUG 01364 if (trace.bit(0)) { 01365 Debug.println("ResultSet.moveToCurrentRow()"); 01366 } 01367 //#endif 01368 onInsertRow = false; 01369 } 01370 01371 /** 01372 * Move the cursor to the insert row. 01373 */ 01374 public void moveToInsertRow() { 01375 //#ifdef DEBUG 01376 if (trace.bit(0)) { 01377 Debug.println("ResultSet.moveToInsertRow()"); 01378 } 01379 //#endif 01380 insertRow = null; 01381 onInsertRow = true; 01382 } 01383 01384 /** 01385 * Advance the cursor to the next row in the <code>ResultSet</code>. 01386 * 01387 * @return true if the cursor is positioned on a valid row, false 01388 * if the cursor has passed the end of the <code>ResultSet</code>. 01389 * 01390 * @exception SQLException may be thrown 01391 */ 01392 public boolean next() throws