View Javadoc
1 // 2 // Copyright 1998, 1999 CDS Networks, Inc., Medford Oregon 3 // 4 // All rights reserved. 5 // 6 // Redistribution and use in source and binary forms, with or without 7 // modification, are permitted provided that the following conditions are met: 8 // 1. Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // 2. Redistributions in binary form must reproduce the above copyright 11 // notice, this list of conditions and the following disclaimer in the 12 // documentation and/or other materials provided with the distribution. 13 // 3. All advertising materials mentioning features or use of this software 14 // must display the following acknowledgement: 15 // This product includes software developed by CDS Networks, Inc. 16 // 4. The name of CDS Networks, Inc. may not be used to endorse or promote 17 // products derived from this software without specific prior 18 // written permission. 19 // 20 // THIS SOFTWARE IS PROVIDED BY CDS NETWORKS, INC. ``AS IS'' AND 21 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 // ARE DISCLAIMED. IN NO EVENT SHALL CDS NETWORKS, INC. BE LIABLE 24 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 // SUCH DAMAGE. 31 // 32 33 34 package com.internetcds.jdbc.tds; 35 36 import java.sql.*; 37 import java.math.BigDecimal; 38 import java.util.Vector; 39 // import java.util.Calendar; 40 import java.util.GregorianCalendar; 41 import java.util.Calendar; 42 import java.io.*; 43 44 /*** 45 * <P>A ResultSet provides access to a table of data generated by 46 * executing a Statement. The table rows are retrieved in 47 * sequence. Within a row its column values can be accessed in any 48 * order. 49 * 50 * <P>A ResultSet maintains a cursor pointing to its current row of 51 * data. Initially the cursor is positioned before the first row. 52 * The 'next' method moves the cursor to the next row. 53 * 54 * <P>The getXXX methods retrieve column values for the current 55 * row. You can retrieve values either using the index number of the 56 * column, or by using the name of the column. In general using the 57 * column index will be more efficient. Columns are numbered from 1. 58 * 59 * <P>For maximum portability, ResultSet columns within each row should be 60 * read in left-to-right order and each column should be read only once. 61 * 62 * <P>For the getXXX methods, the JDBC driver attempts to convert the 63 * underlying data to the specified Java type and returns a suitable 64 * Java value. See the JDBC specification for allowable mappings 65 * from SQL types to Java types with the ResultSet.getXXX methods. 66 * 67 * <P>Column names used as input to getXXX methods are case 68 * insensitive. When performing a getXXX using a column name, if 69 * several columns have the same name, then the value of the first 70 * matching column will be returned. The column name option is 71 * designed to be used when column names are used in the SQL 72 * query. For columns that are NOT explicitly named in the query, it 73 * is best to use column numbers. If column names were used there is 74 * no way for the programmer to guarantee that they actually refer to 75 * the intended columns. 76 * 77 * <P>A ResultSet is automatically closed by the Statement that 78 * generated it when that Statement is closed, re-executed, or is used 79 * to retrieve the next result from a sequence of multiple results. 80 * 81 * <P>The number, types and properties of a ResultSet's columns are 82 * provided by the ResulSetMetaData object returned by the getMetaData 83 * method. 84 * 85 * @author Craig Spannring 86 * @author The FreeTDS project 87 * @version $Id: ResultSet_base.java,v 1.1 2003/04/29 18:07:50 sinisa Exp $ 88 * 89 * @see Statement#executeQuery 90 * @see Statement#getResultSet 91 * @see ResultSetMetaData 92 @ @see Tds#getRow 93 */ 94 95 public class ResultSet_base 96 { 97 public static final String cvsVersion = "$Id: ResultSet_base.java,v 1.1 2003/04/29 18:07:50 sinisa Exp $"; 98 99 100 Tds tds = null; 101 Statement stmt = null; 102 Columns columnsInfo = null; 103 ResultSetMetaData metaData = null; 104 PacketRowResult currentRow = null; 105 boolean lastGetWasNull = false; 106 107 boolean hitEndOfData = false; 108 boolean isClosed = false; 109 110 private SQLWarningChain warningChain = null; // The warnings chain. 111 112 public ResultSet_base(Tds tds_, Statement stmt_, Columns columns_) 113 { 114 tds = tds_; 115 stmt = stmt_; 116 columnsInfo = columns_; 117 118 hitEndOfData = false; 119 warningChain = new SQLWarningChain(); 120 } 121 122 123 protected void NotImplemented() throws java.sql.SQLException 124 { 125 throw new SQLException("Not implemented"); 126 } 127 128 129 /*** 130 * After this call getWarnings returns null until a new warning is 131 * reported for this ResultSet. 132 * 133 * @exception SQLException if a database-access error occurs. 134 */ 135 public void clearWarnings() throws SQLException 136 { 137 warningChain.clearWarnings(); 138 } 139 140 /*** 141 * In some cases, it is desirable to immediately release a 142 * ResultSet's database and JDBC resources instead of waiting for 143 * this to happen when it is automatically closed; the close 144 * method provides this immediate release. 145 * 146 * <P><B>Note:</B> A ResultSet is automatically closed by the 147 * Statement that generated it when that Statement is closed, 148 * re-executed, or is used to retrieve the next result from a 149 * sequence of multiple results. A ResultSet is also automatically 150 * closed when it is garbage collected. 151 * 152 * @exception SQLException if a database-access error occurs. 153 */ 154 public void close() throws SQLException 155 { 156 Exception exception = null; 157 158 if (isClosed) 159 { 160 // nop ??? 161 } 162 else 163 { 164 isClosed = true; 165 try 166 { 167 if (!hitEndOfData) 168 { 169 tds.discardResultSet(columnsInfo); 170 hitEndOfData = true; 171 } 172 else 173 { 174 // nop 175 } 176 } 177 catch(com.internetcds.jdbc.tds.TdsException e) 178 { 179 e.printStackTrace(); 180 exception = e; 181 } 182 catch(java.io.IOException e) 183 { 184 e.printStackTrace(); 185 exception = e; 186 } 187 188 currentRow = null; 189 metaData = null; 190 columnsInfo = null; 191 stmt = null; 192 193 if (exception != null) 194 { 195 throw new SQLException(exception.getMessage()); 196 } 197 } 198 } 199 200 201 //---------------------------------------------------------------- 202 203 /*** 204 * Map a Resultset column name to a ResultSet column index. 205 * 206 * @param columnName the name of the column 207 * @return the column index 208 * @exception SQLException if a database-access error occurs. 209 */ 210 public int findColumn(String columnName) throws SQLException 211 { 212 int i; 213 214 for(i=1; i<=columnsInfo.getColumnCount(); i++) 215 { 216 if (columnsInfo.getName(i).equalsIgnoreCase(columnName)) 217 { 218 return i; 219 } 220 // XXX also need to look at the fully qualified name ie. table.column 221 } 222 throw new SQLException("No such column " + columnName); 223 } 224 225 226 /*** 227 * A column value can be retrieved as a stream of ASCII characters 228 * and then read in chunks from the stream. This method is particularly 229 * suitable for retrieving large LONGVARCHAR values. The JDBC driver will 230 * do any necessary conversion from the database format into ASCII. 231 * 232 * <P><B>Note:</B> All the data in the returned stream must be 233 * read prior to getting the value of any other column. The next 234 * call to a get method implicitly closes the stream. . Also, a 235 * stream may return 0 for available() whether there is data 236 * available or not. 237 * 238 * @param columnIndex the first column is 1, the second is 2, ... 239 * @return a Java input stream that delivers the database column value 240 * as a stream of one byte ASCII characters. If the value is SQL NULL 241 * then the result is null. 242 * @exception SQLException if a database-access error occurs. 243 */ 244 public java.io.InputStream getAsciiStream(int columnIndex) throws SQLException 245 { 246 String val = getString(columnIndex); 247 if (val == null) 248 return null; 249 try { 250 return new ByteArrayInputStream(val.getBytes("ASCII")); 251 } catch (UnsupportedEncodingException ue) { 252 // plain impossible with encoding ASCII 253 return null; 254 } 255 } 256 257 258 /*** 259 * A column value can be retrieved as a stream of ASCII characters 260 * and then read in chunks from the stream. This method is particularly 261 * suitable for retrieving large LONGVARCHAR values. The JDBC driver will 262 * do any necessary conversion from the database format into ASCII. 263 * 264 * <P><B>Note:</B> All the data in the returned stream must 265 * be read prior to getting the value of any other column. The 266 * next call to a get method implicitly closes the stream. 267 * 268 * @param columnName is the SQL name of the column 269 * @return a Java input stream that delivers the database column value 270 * as a stream of one byte ASCII characters. If the value is SQL NULL 271 * then the result is null. 272 * @exception SQLException if a database-access error occurs. 273 */ 274 public java.io.InputStream getAsciiStream(String columnName) throws SQLException 275 { 276 return getAsciiStream(findColumn(columnName)); 277 } 278 279 280 /*** 281 * Get the value of a column in the current row as a 282 * java.lang.BigDecimal object. 283 * 284 * @param columnIndex the first column is 1, the second is 2, ... 285 * @param scale the number of digits to the right of the decimal 286 * @return the column value; if the value is SQL NULL, the result is null 287 * @exception SQLException if a database-access error occurs. 288 */ 289 public BigDecimal getBigDecimal(int columnIndex, int scale) 290 throws SQLException 291 { 292 Object tmp = getObject(columnIndex); 293 BigDecimal result = null; 294 295 296 if (tmp == null) 297 { 298 result = null; 299 } 300 else if (tmp instanceof java.lang.Double) 301 { 302 result = new BigDecimal(((Double)tmp).doubleValue()); 303 result = result.setScale(scale, BigDecimal.ROUND_HALF_UP); 304 } 305 else if (tmp instanceof java.lang.Float) 306 { 307 result = new BigDecimal(((Float)tmp).doubleValue()); 308 result = result.setScale(scale, BigDecimal.ROUND_HALF_UP); 309 } 310 else if (tmp instanceof java.lang.Number) 311 { 312 // This handles Byte, Short, Integer, and Long 313 result = BigDecimal.valueOf(((Number)tmp).longValue(), scale); 314 } 315 else if (tmp instanceof BigDecimal) 316 { 317 result = (BigDecimal)tmp; 318 } 319 else if (tmp instanceof java.lang.String) 320 { 321 try 322 { 323 result = new BigDecimal((String)tmp); 324 } 325 catch (NumberFormatException e) 326 { 327 throw new SQLException(e.getMessage()); 328 } 329 } 330 return result; 331 } 332 333 /*** 334 * Get the value of a column in the current row as a 335 * java.lang.BigDecimal object. 336 * 337 * @param columnName is the SQL name of the column 338 * @param scale the number of digits to the right of the decimal 339 * @return the column value; if the value is SQL NULL, the result is null 340 * @exception SQLException if a database-access error occurs. 341 */ 342 public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException 343 { 344 return getBigDecimal(findColumn(columnName), scale); 345 } 346 347 348 /*** 349 * A column value can be retrieved as a stream of uninterpreted bytes 350 * and then read in chunks from the stream. This method is particularly 351 * suitable for retrieving large LONGVARBINARY values. 352 * 353 * <P><B>Note:</B> All the data in the returned stream must be 354 * read prior to getting the value of any other column. The next 355 * call to a get method implicitly closes the stream. Also, a 356 * stream may return 0 for available() whether there is data 357 * available or not. 358 * 359 * @param columnIndex the first column is 1, the second is 2, ... 360 * @return a Java input stream that delivers the database column value 361 * as a stream of uninterpreted bytes. If the value is SQL NULL 362 * then the result is null. 363 * @exception SQLException if a database-access error occurs. 364 */ 365 public java.io.InputStream getBinaryStream(int columnIndex) 366 throws SQLException 367 { 368 byte[] bytes = getBytes(columnIndex); 369 if (bytes != null) 370 return new ByteArrayInputStream(bytes); 371 return null; 372 } 373 374 375 /*** 376 * A column value can be retrieved as a stream of uninterpreted bytes 377 * and then read in chunks from the stream. This method is particularly 378 * suitable for retrieving large LONGVARBINARY values. 379 * 380 * <P><B>Note:</B> All the data in the returned stream must 381 * be read prior to getting the value of any other column. The 382 * next call to a get method implicitly closes the stream. 383 * 384 * @param columnName is the SQL name of the column 385 * @return a Java input stream that delivers the database column value 386 * as a stream of uninterpreted bytes. If the value is SQL NULL 387 * then the result is null. 388 * @exception SQLException if a database-access error occurs. 389 */ 390 public java.io.InputStream getBinaryStream(String columnName) 391 throws SQLException 392 { 393 return getBinaryStream(findColumn(columnName)); 394 } 395 396 397 /*** 398 * Get the value of a column in the current row as a Java boolean. 399 * 400 * @param columnIndex the first column is 1, the second is 2, ... 401 * @return the column value; if the value is SQL NULL, the result is false 402 * @exception SQLException if a database-access error occurs. 403 */ 404 public boolean getBoolean(int columnIndex) throws SQLException 405 { 406 Object obj = getObject(columnIndex); 407 boolean result; 408 409 if (obj == null) 410 { 411 result = false; 412 } 413 else 414 { 415 switch(getMetaData().getColumnType(columnIndex)) 416 { 417 case java.sql.Types.TINYINT: 418 case java.sql.Types.SMALLINT: 419 case java.sql.Types.INTEGER: 420 case java.sql.Types.BIGINT: 421 case java.sql.Types.REAL: 422 case java.sql.Types.FLOAT: 423 case java.sql.Types.DOUBLE: 424 case java.sql.Types.DECIMAL: 425 case java.sql.Types.NUMERIC: 426 { 427 if (! (obj instanceof java.lang.Number)) 428 { 429 // Must be out of sync with the implementation of 430 // Tds.getRow() for this to happen. 431 throw new SQLException("Internal error"); 432 } 433 // Would somebody like to tell what a true/false has 434 // to do with a double? 435 result = ((java.lang.Number)obj).intValue()!=0; 436 break; 437 } 438 case java.sql.Types.BIT: 439 { 440 if (! (obj instanceof Boolean)) 441 { 442 // Must be out of sync with the implementation of 443 // Tds.getRow() for this to happen. 444 throw new SQLException("Internal error"); 445 } 446 result = ((Boolean)obj).booleanValue(); 447 break; 448 } 449 case java.sql.Types.CHAR: 450 case java.sql.Types.VARCHAR: 451 case java.sql.Types.LONGVARCHAR: 452 { 453 // Okay, I'm really confused as to what you mean 454 // by a character string being true or false. What 455 // is the boolean value for "Let the wookie win"? 456 // But since the spec says I have to convert from 457 // character to boolean data... 458 459 if (! (obj instanceof String)) 460 { 461 // Must be out of sync with the implementation of 462 // Tds.getRow() for this to happen. 463 throw new SQLException("Internal error"); 464 } 465 char ch = (((String)obj) + "n").charAt(0); 466 467 result = (ch=='Y')||(ch=='y')||(ch=='t')||(ch=='T'); 468 break; 469 } 470 default: 471 { 472 throw new SQLException("Can't convert column " + columnIndex 473 + " from " 474 + obj.getClass().getName() 475 + " to boolean"); 476 } 477 } 478 } 479 return result; 480 } // getBoolean() 481 482 483 /*** 484 * Get the value of a column in the current row as a Java boolean. 485 * 486 * @param columnName is the SQL name of the column 487 * @return the column value; if the value is SQL NULL, the result is false 488 * @exception SQLException if a database-access error occurs. 489 */ 490 public boolean getBoolean(String columnName) throws SQLException 491 { 492 return getBoolean(findColumn(columnName)); 493 } // getBoolean() 494 495 496 /*** 497 * Get the value of a column in the current row as a Java byte. 498 * 499 * @param columnIndex the first column is 1, the second is 2, ... 500 * @return the column value; if the value is SQL NULL, the result is 0 501 * @exception SQLException if a database-access error occurs. 502 */ 503 public byte getByte(int columnIndex) throws SQLException 504 { 505 return (byte) getLong(columnIndex); 506 } 507 508 509 /*** 510 * Get the value of a column in the current row as a Java byte. 511 * 512 * @param columnName is the SQL name of the column 513 * @return the column value; if the value is SQL NULL, the result is 0 514 * @exception SQLException if a database-access error occurs. 515 */ 516 public byte getByte(String columnName) throws SQLException 517 { 518 return getByte(findColumn(columnName)); 519 } 520 521 522 /*** 523 * Get the value of a column in the current row as a Java byte array. 524 * The bytes represent the raw values returned by the driver. 525 * 526 * @param columnIndex the first column is 1, the second is 2, ... 527 * @return the column value; if the value is SQL NULL, the result is null 528 * @exception SQLException if a database-access error occurs. 529 */ 530 public byte[] getBytes(int columnIndex) throws SQLException 531 { 532 byte result[]; 533 534 try 535 { 536 Object tmp = currentRow.getElementAt(columnIndex); 537 lastGetWasNull = false; 538 if (tmp == null) 539 { 540 lastGetWasNull = true; 541 result = null; 542 } 543 else if (tmp instanceof byte[]) 544 { 545 result = (byte[])tmp; 546 } 547 else if (tmp instanceof String) 548 { 549 result = tds.getEncoder().getBytes((String)tmp); 550 } 551 else 552 { 553 throw new SQLException("Can't convert column " + columnIndex 554 + " from " 555 + tmp.getClass().getName() 556 + " to byte[]"); 557 } 558 } 559 catch (TdsException e) 560 { 561 e.printStackTrace(); 562 throw new SQLException(e.getMessage()); 563 } 564 return result; 565 } 566 567 568 /*** 569 * Get the value of a column in the current row as a Java byte array. 570 * The bytes represent the raw values returned by the driver. 571 * 572 * @param columnName is the SQL name of the column 573 * @return the column value; if the value is SQL NULL, the result is null 574 * @exception SQLException if a database-access error occurs. 575 */ 576 public byte[] getBytes(String columnName) throws SQLException 577 { 578 return getBytes(findColumn(columnName)); 579 } 580 581 582 /*** 583 * Get the name of the SQL cursor used by this ResultSet. 584 * 585 * <P>In SQL, a result table is retrieved through a cursor that is 586 * named. The current row of a result can be updated or deleted 587 * using a positioned update/delete statement that references the 588 * cursor name. 589 * 590 * <P>JDBC supports this SQL feature by providing the name of the 591 * SQL cursor used by a ResultSet. The current row of a ResultSet 592 * is also the current row of this SQL cursor. 593 * 594 * <P><B>Note:</B> If positioned update is not supported a 595 * SQLException is thrown 596 * 597 * @return the ResultSet's SQL cursor name 598 * @exception SQLException if a database-access error occurs. 599 */ 600 public String getCursorName() throws SQLException 601 { 602 throw new SQLException("Not implemented (getCursorName)"); 603 } 604 605 606 /*** 607 * Get the value of a column in the current row as a java.sql.Date object. 608 * 609 * @param columnIndex the first column is 1, the second is 2, ... 610 * @return the column value; if the value is SQL NULL, the result is null 611 * @exception SQLException if a database-access error occurs. 612 */ 613 public java.sql.Date getDate(int columnIndex) throws SQLException 614 { 615 java.sql.Date result = null; 616 java.sql.Timestamp tmp = getTimestamp(columnIndex); 617 618 if (tmp != null) 619 { 620 result = new java.sql.Date(tmp.getTime()); 621 } 622 return result; 623 } 624 625 626 /*** 627 * Get the value of a column in the current row as a java.sql.Date object. 628 * 629 * @param columnName is the SQL name of the column 630 * @return the column value; if the value is SQL NULL, the result is null 631 * @exception SQLException if a database-access error occurs. 632 */ 633 public java.sql.Date getDate(String columnName) throws SQLException 634 { 635 return getDate(findColumn(columnName)); 636 } 637 638 639 /*** 640 * Get the value of a column in the current row as a Java double. 641 * 642 * @param columnIndex the first column is 1, the second is 2, ... 643 * @return the column value; if the value is SQL NULL, the result is 0 644 * @exception SQLException if a database-access error occurs. 645 */ 646 public double getDouble(int columnIndex) throws SQLException 647 { 648 double result; 649 Object obj = getObject(columnIndex); 650 651 if (obj == null) 652 { 653 result = 0.0; 654 } 655 else 656 { 657 try 658 { 659 switch(getMetaData().getColumnType(columnIndex)) 660 { 661 case java.sql.Types.TINYINT: 662 case java.sql.Types.SMALLINT: 663 case java.sql.Types.INTEGER: 664 { 665 result = ((Number)obj).doubleValue(); 666 break; 667 } 668 case java.sql.Types.BIGINT: 669 { 670 result = ((Number)obj).doubleValue(); 671 break; 672 } 673 case java.sql.Types.REAL: 674 { 675 result = ((Float)obj).doubleValue(); 676 break; 677 } 678 case java.sql.Types.FLOAT: 679 case java.sql.Types.DOUBLE: 680 { 681 result = ((Number)obj).doubleValue(); 682 break; 683 } 684 case java.sql.Types.CHAR: 685 case java.sql.Types.VARCHAR: 686 case java.sql.Types.LONGVARCHAR: 687 { 688 try 689 { 690 Double d = new Double((String)obj); 691 result = d.doubleValue(); 692 } 693 catch (NumberFormatException e) 694 { 695 throw new SQLException(e.getMessage()); 696 } 697 break; 698 } 699 case java.sql.Types.DECIMAL: 700 case java.sql.Types.NUMERIC: 701 { 702 result = ((BigDecimal)obj).doubleValue(); 703 break; 704 } 705 case java.sql.Types.BIT: 706 { 707 // XXX according to JDBC spec we need to handle these 708 // for now just fall through 709 } 710 default: 711 { 712 throw new SQLException("Internal error. " 713 + "Don't know how to convert from " 714 + "java.sql.Types." + 715 TdsUtil.javaSqlTypeToString(getMetaData().getColumnType(columnIndex)) 716 + " to an Dboule"); 717 } 718 } 719 } 720 catch(ClassCastException e) 721 { 722 throw new SQLException("Couldn't convert column " + columnIndex 723 + " to an long. " 724 + e.getMessage()); 725 } 726 } 727 return result; 728 } /* getDouble() */ 729 730 731 /*** 732 * Get the value of a column in the current row as a Java double. 733 * 734 * @param columnName is the SQL name of the column 735 * @return the column value; if the value is SQL NULL, the result is 0 736 * @exception SQLException if a database-access error occurs. 737 */ 738 public double getDouble(String columnName) throws SQLException 739 { 740 return getDouble(findColumn(columnName)); 741 } 742 743 744 /*** 745 * Get the value of a column in the current row as a Java float. 746 * 747 * @param columnIndex the first column is 1, the second is 2, ... 748 * @return the column value; if the value is SQL NULL, the result is 0 749 * @exception SQLException if a database-access error occurs. 750 */ 751 public float getFloat(int columnIndex) throws SQLException 752 { 753 return (float)getDouble(columnIndex); 754 } 755 756 757 /*** 758 * Get the value of a column in the current row as a Java float. 759 * 760 * @param columnName is the SQL name of the column 761 * @return the column value; if the value is SQL NULL, the result is 0 762 * @exception SQLException if a database-access error occurs. 763 */ 764 public float getFloat(String columnName) throws SQLException 765 { 766 return getFloat(findColumn(columnName)); 767 } 768 769 770 /*** 771 * Get the value of a column in the current row as a Java int. 772 * 773 * @param columnIndex the first column is 1, the second is 2, ... 774 * @return the column value; if the value is SQL NULL, the result is 0 775 * @exception SQLException if a database-access error occurs. 776 */ 777 public int getInt(int columnIndex) throws SQLException 778 { 779 return (int) getLong(columnIndex); 780 } 781 782 783 /*** 784 * Get the value of a column in the current row as a Java int. 785 * 786 * @param columnName is the SQL name of the column 787 * @return the column value; if the value is SQL NULL, the result is 0 788 * @exception SQLException if a database-access error occurs. 789 */ 790 public int getInt(String columnName) throws SQLException 791 { 792 return getInt(findColumn(columnName)); 793 } 794 795 796 /*** 797 * Get the value of a column in the current row as a Java long. 798 * 799 * @param columnIndex the first column is 1, the second is 2, ... 800 * @return the column value; if the value is SQL NULL, the result is 0 801 * @exception SQLException if a database-access error occurs. 802 */ 803 public long getLong(int columnIndex) throws SQLException 804 { 805 long result = 0; 806 Object obj = getObject(columnIndex); 807 808 if (obj == null) 809 { 810 result = 0; 811 } 812 else 813 { 814 try 815 { 816 switch(getMetaData().getColumnType(columnIndex)) 817 { 818 case java.sql.Types.TINYINT: 819 case java.sql.Types.SMALLINT: 820 case java.sql.Types.INTEGER: 821 { 822 result = ((Number)obj).longValue(); 823 break; 824 } 825 case java.sql.Types.BIGINT: 826 { 827 result = ((Number)obj).longValue(); 828 break; 829 } 830 case java.sql.Types.REAL: 831 case java.sql.Types.FLOAT: 832 case java.sql.Types.DOUBLE: 833 { 834 result = ((Number)obj).longValue(); 835 break; 836 } 837 case java.sql.Types.CHAR: 838 case java.sql.Types.VARCHAR: 839 case java.sql.Types.LONGVARCHAR: 840 { 841 try 842 { 843 Long i = new Long((String)obj); 844 result = i.longValue(); 845 } 846 catch (NumberFormatException e) 847 { 848 throw new SQLException(e.getMessage()); 849 } 850 break; 851 } 852 case java.sql.Types.NUMERIC: 853 { 854 result = ((Number)obj).longValue(); 855 break; 856 } 857 case java.sql.Types.DECIMAL: 858 { 859 result = ((Number)obj).longValue(); 860 break; 861 } 862 case java.sql.Types.BIT: 863 { 864 // XXX according to JDBC spec we need to handle these 865 // for now just fall through 866 } 867 default: 868 { 869 throw new SQLException("Internal error. " 870 + "Don't know how to convert from " 871 + "java.sql.Types " + 872 TdsUtil.javaSqlTypeToString(getMetaData().getColumnType(columnIndex)) 873 + " to an long"); 874 } 875 } 876 } 877 catch(ClassCastException e) 878 { 879 throw new SQLException("Couldn't convert column " + columnIndex 880 + " to an long. " 881 + e.getMessage()); 882 } 883 } 884 return result; 885 } /* getLong() */ 886 887 888 /*** 889 * Get the value of a column in the current row as a Java long. 890 * 891 * @param columnName is the SQL name of the column 892 * @return the column value; if the value is SQL NULL, the result is 0 893 * @exception SQLException if a database-access error occurs. 894 */ 895 public long getLong(String columnName) throws SQLException 896 { 897 return getLong(findColumn(columnName)); 898 } 899 900 901 /*** 902 * The number, types and properties of a ResultSet's columns 903 * are provided by the getMetaData method. 904 * 905 * @return the description of a ResultSet's columns 906 * @exception SQLException if a database-access error occurs. 907 */ 908 public java.sql.ResultSetMetaData getMetaData() throws SQLException 909 { 910 if (metaData == null) 911 { 912 metaData = new ResultSetMetaData(columnsInfo); 913 } 914 return metaData; 915 } 916 917 918 /*** 919 * <p>Get the value of a column in the current row as a Java object. 920 * 921 * <p>This method will return the value of the given column as a 922 * Java object. The type of the Java object will be the default 923 * Java Object type corresponding to the column's SQL type, 924 * following the mapping specified in the JDBC spec. 925 * 926 * <p>This method may also be used to read datatabase specific abstract 927 * data types. 928 * 929 * JDBC 2.0 930 * 931 * In the JDBC 2.0 API, the behavior of method 932 * <code>getObject</code> is extended to materialize 933 * data of SQL user-defined types. When the a column contains 934 * a structured or distinct value, the behavior of this method is as 935 * if it were a call to: getObject(columnIndex, 936 * this.getStatement().getConnection().getTypeMap()). 937 * 938 * @param columnIndex the first column is 1, the second is 2, ... 939 * @return A java.lang.Object holding the column value. 940 * @exception SQLException if a database-access error occurs. 941 */ 942 public Object getObject(int columnIndex) throws SQLException 943 { 944 // This method is implicitly coupled to the getRow() method in the 945 // Tds class. Every type that getRow() could return must 946 // be handled in this method. 947 // 948 // The object type returned by getRow() must correspond with the 949 // jdbc SQL type in the switch statement below. 950 // 951 // Note- The JDBC spec (version 1.20) does not define the type 952 // of the Object returned for LONGVARCHAR data. 953 954 // XXX- Needs modifications for JDBC 2.0 955 956 Object result = null; 957 958 if (currentRow == null) 959 { 960 throw new SQLException("No current row in the result set. " + 961 "Did you call ResultSet.next()?"); 962 } 963 964 try 965 { 966 Object tmp = currentRow.getElementAt(columnIndex); 967 lastGetWasNull = false; 968 if (tmp == null) 969 { 970 lastGetWasNull = true; 971 972 result = null; 973 } 974 else 975 { 976 switch(getMetaData().getColumnType(columnIndex)) 977 { 978 case java.sql.Types.CHAR: 979 case java.sql.Types.VARCHAR: 980 { 981 if (tmp instanceof String) 982 { 983 result = tmp; 984 } 985 else 986 { 987 throw new SQLException("Was expecting CHAR data. Got" 988 + tmp.getClass().getName()); 989 } 990 break; 991 } 992 case java.sql.Types.TINYINT: 993 { 994 if (! (tmp instanceof Long)) 995 { 996 throw new SQLException("Internal error"); 997 } 998 999 result = new Byte((byte) ((Long)tmp).intValue()); 1000 break; 1001 } 1002 case java.sql.Types.SMALLINT: 1003 { 1004 if (! (tmp instanceof Long)) 1005 { 1006 throw new SQLException("Internal error"); 1007 } 1008 1009 result = new Short((short) ((Long)tmp).intValue()); 1010 break; 1011 } 1012 case java.sql.Types.INTEGER: 1013 { 1014 if (! (tmp instanceof Long)) 1015 { 1016 throw new SQLException("Internal error"); 1017 } 1018 1019 result = new Integer(((Long)tmp).intValue()); 1020 break; 1021 } 1022 case java.sql.Types.BIGINT: 1023 { 1024 if (! (tmp instanceof Long)) 1025 { 1026 throw new SQLException("Internal error"); 1027 } 1028 1029 result = (Long)tmp; 1030 break; 1031 } 1032 case java.sql.Types.REAL: 1033 { 1034 if (! (tmp instanceof Float)) 1035 { 1036 throw new SQLException("Internal error"); 1037 } 1038 1039 result = (Float)tmp; 1040 break; 1041 } 1042 case java.sql.Types.FLOAT: 1043 case java.sql.Types.DOUBLE: 1044 { 1045 if (tmp instanceof Double) 1046 { 1047 result = (Double)tmp; 1048 } 1049 else if (tmp instanceof Float) 1050 { 1051 result = new Double(((Float)tmp).doubleValue()); 1052 } 1053 else 1054 { 1055 throw new SQLException("Was expecting Double data. Got" 1056 + tmp.getClass().getName()); 1057 } 1058 1059 break; 1060 } 1061 case java.sql.Types.DATE: 1062 { 1063 // XXX How do the time types hold up with timezones? 1064 if (! (tmp instanceof Timestamp)) 1065 { 1066 throw new SQLException("Internal error"); 1067 } 1068 1069 // java.util.Calendar cal = new java.util.GregorianCalendar(); 1070 // cal.setTime(getTimestamp(columnIndex)); 1071 // result = cal.getTime(); 1072 result = new Date(((Timestamp)tmp).getTime()); 1073 break; 1074 } 1075 case java.sql.Types.TIME: 1076 { 1077 if (! (tmp instanceof Timestamp)) 1078 { 1079 throw new SQLException("Internal error"); 1080 } 1081 1082 result = new Time(((Timestamp)tmp).getTime()); 1083 break; 1084 } 1085 case java.sql.Types.TIMESTAMP: 1086 { 1087 if (! (tmp instanceof Timestamp)) 1088 { 1089 throw new SQLException("Internal error"); 1090 } 1091 1092 result = (Timestamp) tmp; 1093 break; 1094 } 1095 case java.sql.Types.BINARY: 1096 case java.sql.Types.VARBINARY: 1097 { 1098 result = getBytes(columnIndex); 1099 break; 1100 } 1101 case java.sql.Types.DECIMAL: 1102 case java.sql.Types.NUMERIC: 1103 { 1104 if (tmp instanceof BigDecimal) 1105 { 1106 result = ((BigDecimal)tmp); 1107 } 1108 else 1109 { 1110 throw new SQLException("Was expecting NUMERIC data. Got" 1111 + tmp.getClass().getName()); 1112 } 1113 break; 1114 } 1115 case java.sql.Types.LONGVARCHAR: 1116 { 1117 if (tmp instanceof TdsAsciiInputStream) 1118 { 1119 result = ((TdsAsciiInputStream)tmp).toString(); 1120 } 1121 else if (tmp instanceof java.lang.String) 1122 { 1123 result = tmp; 1124 } 1125 else 1126 { 1127 throw new SQLException("Was expecting LONGVARCHAR data. " 1128 + "Got " 1129 + tmp.getClass().getName()); 1130 } 1131 break; 1132 } 1133 case java.sql.Types.LONGVARBINARY: 1134 { 1135 throw new SQLException("Not implemented"); 1136 } 1137 case java.sql.Types.NULL: 1138 { 1139 throw new SQLException("Not implemented"); 1140 } 1141 case java.sql.Types.OTHER: 1142 { 1143 throw new SQLException("Not implemented"); 1144 } 1145 case java.sql.Types.BIT: 1146 { 1147 if (tmp instanceof Boolean) 1148 { 1149 result = ((Boolean)tmp); 1150 } 1151 else 1152 { 1153 throw new SQLException("Was expecting BIT data. " 1154 + "Got" 1155 + tmp.getClass().getName()); 1156 } 1157 break; 1158 } 1159 default: 1160 { 1161 String msg = "" 1162 + "Unknown datatype " 1163 + getMetaData().getColumnType(columnIndex); 1164 throw new SQLException(msg); 1165 } 1166 } 1167 } 1168 } 1169 catch (com.internetcds.jdbc.tds.TdsException e) 1170 { 1171 e.printStackTrace(); 1172 throw new SQLException(e.getMessage()); 1173 } 1174 return result; 1175 } // getObject() 1176 1177 1178 /*** 1179 * <p>Get the value of a column in the current row as a Java object. 1180 * 1181 * <p>This method will return the value of the given column as a 1182 * Java object. The type of the Java object will be the default 1183 * Java Object type corresponding to the column's SQL type, 1184 * following the mapping specified in the JDBC spec. 1185 * 1186 * JDBC 2.0 1187 * 1188 * 1189 * In the JDBC 2.0 API, the behavior of method 1190 * <code>getObject</code> is extended to materialize 1191 * data of SQL user-defined types. When the a column contains 1192 * a structured or distinct value, the behavior of this method is as 1193 * if it were a call to: getObject(columnIndex, 1194 * this.getStatement().getConnection().getTypeMap()). 1195 * 1196 * <p>This method may also be used to read datatabase specific abstract 1197 * data types. 1198 * 1199 * @param columnName is the SQL name of the column 1200 * @return A java.lang.Object holding the column value. 1201 * @exception SQLException if a database-access error occurs. 1202 */ 1203 public Object getObject(String columnName) throws SQLException 1204 { 1205 return getObject(findColumn(columnName)); 1206 } 1207 1208 1209 /*** 1210 * Get the value of a column in the current row as a Java short. 1211 * 1212 * @param columnIndex the first column is 1, the second is 2, ... 1213 * @return the column value; if the value is SQL NULL, the result is 0 1214 * @exception SQLException if a database-access error occurs. 1215 */ 1216 public short getShort(int columnIndex) throws SQLException 1217 { 1218 return (short) getLong(columnIndex); 1219 } 1220 1221 1222 /*** 1223 * Get the value of a column in the current row as a Java short. 1224 * 1225 * @param columnName is the SQL name of the column 1226 * @return the column value; if the value is SQL NULL, the result is 0 1227 * @exception SQLException if a database-access error occurs. 1228 */ 1229 public short getShort(String columnName) throws SQLException 1230 { 1231 return getShort(findColumn(columnName)); 1232 } 1233 1234 1235 //====================================================================== 1236 // Methods for accessing results by column index 1237 //====================================================================== 1238 1239 /*** 1240 * Get the value of a column in the current row as a Java String. 1241 * 1242 * @param columnIndex the first column is 1, the second is 2, ... 1243 * @return the column value; if the value is SQL NULL, the result is null 1244 * @exception SQLException if a database-access error occurs. 1245 */ 1246 public String getString(int columnIndex) throws SQLException 1247 { 1248 Object tmp = getObject(columnIndex); 1249 1250 if (tmp == null) 1251 { 1252 return null; 1253 } 1254 else if (tmp instanceof byte[]) 1255 { 1256 return new String((byte[])tmp); 1257 } 1258 else 1259 { 1260 return tmp.toString(); 1261 } 1262 } 1263 1264 1265 //====================================================================== 1266 // Methods for accessing results by column name 1267 //====================================================================== 1268 1269 /*** 1270 * Get the value of a column in the current row as a Java String. 1271 * 1272 * @param columnName is the SQL name of the column 1273 * @return the column value; if the value is SQL NULL, the result is null 1274 * @exception SQLException if a database-access error occurs. 1275 */ 1276 public String getString(String columnName) throws SQLException 1277 { 1278 return getString(findColumn(columnName)); 1279 } 1280 1281 1282 /*** 1283 * Get the value of a column in the current row as a java.sql.Time object. 1284 * 1285 * @param columnIndex the first column is 1, the second is 2, ... 1286 * @return the column value; if the value is SQL NULL, the result is null 1287 * @exception SQLException if a database-access error occurs. 1288 */ 1289 public java.sql.Time getTime(int columnIndex) throws SQLException 1290 { 1291 java.sql.Time result = null; 1292 java.sql.Timestamp tmp = getTimestamp(columnIndex); 1293 1294 if (tmp != null) 1295 { 1296 result = new java.sql.Time(tmp.getTime()); 1297 } 1298 return result; 1299 } 1300 1301 1302 /*** 1303 * Get the value of a column in the current row as a java.sql.Time object. 1304 * 1305 * @param columnName is the SQL name of the column 1306 * @return the column value; if the value is SQL NULL, the result is null 1307 * @exception SQLException if a database-access error occurs. 1308 */ 1309 public java.sql.Time getTime(String columnName) throws SQLException 1310 { 1311 return getTime(findColumn(columnName)); 1312 } 1313 1314 1315 /*** 1316 * Get the value of a column in the current row as a java.sql.Timestamp object. 1317 * 1318 * @param columnIndex the first column is 1, the second is 2, ... 1319 * @return the column value; if the value is SQL NULL, the result is null 1320 * @exception SQLException if a database-access error occurs. 1321 */ 1322 public java.sql.Timestamp getTimestamp(int columnIndex) throws SQLException 1323 { 1324 Timestamp result; 1325 1326 try 1327 { 1328 Object tmp = currentRow.getElementAt(columnIndex); 1329 1330 lastGetWasNull = false; 1331 if (tmp == null) 1332 { 1333 lastGetWasNull = true; 1334 result = null; 1335 } 1336 else if (tmp instanceof Timestamp) 1337 { 1338 result = (Timestamp)tmp; 1339 } 1340 else 1341 { 1342 throw new SQLException("Can't convert column " + columnIndex 1343 + " from " 1344 + tmp.getClass().getName() 1345 + " to Timestamp"); 1346 } 1347 } 1348 catch (TdsException e) 1349 { 1350 throw new SQLException(e.getMessage()); 1351 } 1352 return result; 1353 } 1354 1355 1356 /*** 1357 * Get the value of a column in the current row as a java.sql.Timestamp object. 1358 * 1359 * @param columnName is the SQL name of the column 1360 * @return the column value; if the value is SQL NULL, the result is null 1361 * @exception SQLException if a database-access error occurs. 1362 */ 1363 public java.sql.Timestamp getTimestamp(String columnName) throws SQLException 1364 { 1365 return getTimestamp(findColumn(columnName)); 1366 } 1367 1368 1369 /*** 1370 * A column value can be retrieved as a stream of Unicode characters 1371 * and then read in chunks from the stream. This method is particularly 1372 * suitable for retrieving large LONGVARCHAR values. The JDBC driver will 1373 * do any necessary conversion from the database format into Unicode. 1374 * 1375 * <P><B>Note:</B> All the data in the returned stream must be 1376 * read prior to getting the value of any other column. The next 1377 * call to a get method implicitly closes the stream. . Also, a 1378 * stream may return 0 for available() whether there is data 1379 * available or not. 1380 * 1381 * @param columnIndex the first column is 1, the second is 2, ... 1382 * @return a Java input stream that delivers the database column value 1383 * as a stream of two byte Unicode characters. If the value is SQL NULL 1384 * then the result is null. 1385 * @exception SQLException if a database-access error occurs. 1386 */ 1387 public java.io.InputStream getUnicodeStream(int columnIndex) throws SQLException 1388 { 1389 String val = getString(columnIndex); 1390 if (val == null) 1391 return null; 1392 try { 1393 return new ByteArrayInputStream(val.getBytes("UTF8")); 1394 } catch (UnsupportedEncodingException e) { 1395 // plain impossible with UTF-8 1396 return null; 1397 } 1398 } 1399 1400 /*** 1401 * A column value can be retrieved as a stream of Unicode characters 1402 * and then read in chunks from the stream. This method is particularly 1403 * suitable for retrieving large LONGVARCHAR values. The JDBC driver will 1404 * do any necessary conversion from the database format into Unicode. 1405 * 1406 * <P><B>Note:</B> All the data in the returned stream must 1407 * be read prior to getting the value of any other column. The 1408 * next call to a get method implicitly closes the stream. 1409 * 1410 * @param columnName is the SQL name of the column 1411 * @return a Java input stream that delivers the database column value 1412 * as a stream of two byte Unicode characters. If the value is SQL NULL 1413 * then the result is null. 1414 * @exception SQLException if a database-access error occurs. 1415 */ 1416 public java.io.InputStream getUnicodeStream(String columnName) throws SQLException 1417 { 1418 return getUnicodeStream(findColumn(columnName)); 1419 } 1420 1421 1422 //===================================================================== 1423 // Advanced features: 1424 //===================================================================== 1425 1426 /*** 1427 * <p>The first warning reported by calls on this ResultSet is 1428 * returned. Subsequent ResultSet warnings will be chained to this 1429 * SQLWarning. 1430 * 1431 * <P>The warning chain is automatically cleared each time a new 1432 * row is read. 1433 * 1434 * <P><B>Note:</B> This warning chain only covers warnings caused 1435 * by ResultSet methods. Any warning caused by statement methods 1436 * (such as reading OUT parameters) will be chained on the 1437 * Statement object. 1438 * 1439 * @return the first SQLWarning or null 1440 * @exception SQLException if a database-access error occurs. 1441 */ 1442 public SQLWarning getWarnings() throws SQLException 1443 { 1444 return warningChain.getWarnings(); 1445 } 1446 1447 1448 /*** 1449 * A ResultSet is initially positioned before its first row; the 1450 * first call to next makes the first row the current row; the 1451 * second call makes the second row the current row, etc. 1452 * 1453 * <P>If an input stream from the previous row is open, it is 1454 * implicitly closed. The ResultSet's warning chain is cleared 1455 * when a new row is read. 1456 * 1457 * @return true if the new current row is valid; false if there 1458 * are no more rows 1459 * @exception SQLException if a database-access error occurs. 1460 */ 1461 public boolean next() throws SQLException 1462 { 1463 boolean result = false; 1464 SQLException exception = null; 1465 boolean done = false; 1466 boolean wasCanceled = false; 1467 1468 if (isClosed) 1469 { 1470 throw new SQLException("result set is closed"); 1471 } 1472 if(!hitEndOfData) { 1473 try 1474 { 1475 clearWarnings(); 1476 1477 Context context = new Context(); 1478 context.setColumnInfo(columnsInfo); 1479 1480 1481 // Keep eating garbage and warnings until we reach the next result 1482 while (!tds.isResultSet() && 1483 !tds.isEndOfResults() && 1484 !tds.isResultRow()) 1485 { 1486 // RMK 2000-06-08: don't choke on RET_STAT package. 1487 if (tds.isProcId() || tds.peek() == Tds.TDS_RET_STAT_TOKEN) 1488 { 1489 tds.processSubPacket(); 1490 } 1491 else if (tds.isDoneInProc()) 1492 { 1493 PacketDoneInProcResult tmp = 1494 (PacketDoneInProcResult)tds.processSubPacket(); 1495 } 1496 else if (tds.isTextUpdate()) 1497 { 1498 PacketResult tmp1 = 1499 (PacketResult)tds.processSubPacket(); 1500 } 1501 else if (tds.isMessagePacket() || tds.isErrorPacket()) 1502 { 1503 PacketMsgResult tmp = (PacketMsgResult)tds.processSubPacket(); 1504 exception = warningChain.addOrReturn(tmp); 1505 } 1506 else 1507 { 1508 throw new SQLException("Protocol confusion. " 1509 + "Got a 0x" 1510 + Integer.toHexString((tds.peek() & 0xff)) 1511 + " packet"); 1512 } 1513 } // end while 1514 1515 if (exception != null) 1516 { 1517 throw exception; 1518 } 1519 1520 if (tds.isResultRow()) 1521 { 1522 currentRow = (PacketRowResult)tds.processSubPacket(context); 1523 result = true; 1524 done = true; 1525 } 1526 else if (tds.isEndOfResults()) 1527 { 1528 PacketResult tmp = tds.processSubPacket(context); 1529 currentRow = null; 1530 done = true; 1531 hitEndOfData = true; 1532 wasCanceled = wasCanceled 1533 || ((PacketEndTokenResult)tmp).wasCanceled(); 1534 } 1535 else if (!tds.isResultSet()) 1536 { 1537 throw new SQLException("Protocol confusion. " 1538 + "Got a 0x" 1539 + Integer.toHexString((tds.peek() & 0xff)) 1540 + " packet"); 1541 } 1542 1543 1544 if (exception != null) 1545 { 1546 throw exception; 1547 } 1548 } 1549 catch(java.io.IOException e) 1550 { 1551 throw new SQLException(e.getMessage()); 1552 } 1553 catch(TdsException e) 1554 { 1555 e.printStackTrace(); 1556 throw new SQLException(e.getMessage()); 1557 } 1558 if (wasCanceled) 1559 { 1560 throw new SQLException("Query was canceled or timed out."); 1561 } 1562 } 1563 return result; 1564 } 1565 1566 1567 /*** 1568 * A column may have the value of SQL NULL; wasNull reports whether 1569 * the last column read had this special value. 1570 * Note that you must first call getXXX on a column to try to read 1571 * its value and then call wasNull() to find if the value was 1572 * the SQL NULL. 1573 * 1574 * @return true if last column read was SQL NULL 1575 * @exception SQLException if a database-access error occurs. 1576 */ 1577 public boolean wasNull() throws SQLException 1578 { 1579 return lastGetWasNull; 1580 } 1581 }

This page was automatically generated by Maven