001 package com.mockrunner.mock.jdbc; 002 003 import java.io.ByteArrayInputStream; 004 import java.io.InputStream; 005 import java.io.Reader; 006 import java.io.StringReader; 007 import java.io.UnsupportedEncodingException; 008 import java.math.BigDecimal; 009 import java.net.MalformedURLException; 010 import java.net.URL; 011 import java.sql.Array; 012 import java.sql.Blob; 013 import java.sql.Clob; 014 import java.sql.Date; 015 import java.sql.NClob; 016 import java.sql.Ref; 017 import java.sql.ResultSet; 018 import java.sql.ResultSetMetaData; 019 import java.sql.RowId; 020 import java.sql.SQLException; 021 import java.sql.SQLWarning; 022 import java.sql.SQLXML; 023 import java.sql.Statement; 024 import java.sql.Time; 025 import java.sql.Timestamp; 026 import java.util.ArrayList; 027 import java.util.Arrays; 028 import java.util.Calendar; 029 import java.util.Collections; 030 import java.util.Iterator; 031 import java.util.List; 032 import java.util.Map; 033 034 import com.mockrunner.base.NestedApplicationException; 035 import com.mockrunner.jdbc.ParameterUtil; 036 import com.mockrunner.jdbc.SQLUtil; 037 import com.mockrunner.util.common.CaseAwareMap; 038 import com.mockrunner.util.common.CollectionUtil; 039 import com.mockrunner.util.common.StreamUtil; 040 import com.mockrunner.util.common.StringUtil; 041 042 /** 043 * Mock implementation of <code>ResultSet</code>. 044 * Can be used to add simulated database entries. 045 * You can add Java objects of any type. This 046 * mock implementation does not care about SQL 047 * data types. It tries to perform the necessary 048 * type conversions for the Java objects (e.g. it will convert a 049 * <code>String</code> "1" to <code>int</code> 1). 050 * Please check out the documentation of <code>ResultSet</code> 051 * for the description of the methods in this interface. 052 * The additional methods are described here. 053 */ 054 public class MockResultSet implements ResultSet, Cloneable 055 { 056 private Statement statement; 057 private String id; 058 private Map columnMap; 059 private Map columnMapCopy; 060 private Map insertRow; 061 private List columnNameList; 062 private List updatedRows; 063 private List deletedRows; 064 private List insertedRows; 065 private int cursor; 066 private boolean isCursorInInsertRow; 067 private boolean wasNull; 068 private String cursorName; 069 private int fetchSize = 0; 070 private int fetchDirection = ResultSet.FETCH_FORWARD; 071 private int resultSetType = ResultSet.TYPE_SCROLL_INSENSITIVE; 072 private int resultSetConcurrency = ResultSet.CONCUR_READ_ONLY; 073 private int resultSetHoldability = ResultSet.HOLD_CURSORS_OVER_COMMIT; 074 private boolean isDatabaseView; 075 private ResultSetMetaData resultSetMetaData; 076 private boolean closed; 077 private boolean columnsCaseSensitive; 078 079 public MockResultSet(String id) 080 { 081 this(id, ""); 082 } 083 084 public MockResultSet(String id, String cursorName) 085 { 086 init(); 087 this.cursorName = cursorName; 088 this.id = id; 089 columnsCaseSensitive = false; 090 } 091 092 private void init() 093 { 094 columnMap = createCaseAwareMap(); 095 columnNameList = new ArrayList(); 096 updatedRows = new ArrayList(); 097 deletedRows = new ArrayList(); 098 insertedRows = new ArrayList(); 099 cursor = -1; 100 wasNull = false; 101 closed = false; 102 isCursorInInsertRow = false; 103 isDatabaseView = false; 104 resultSetMetaData = null; 105 copyColumnMap(); 106 adjustInsertRow(); 107 } 108 109 /** 110 * Set if column names are case sensitive. Default is 111 * <code>false</code>. Please note, that switching this 112 * attribute clears and resets the complete <code>ResultSet</code>. 113 * @param columnsCaseSensitive are column names case sensitive 114 */ 115 public void setColumnsCaseSensitive(boolean columnsCaseSensitive) 116 { 117 this.columnsCaseSensitive = columnsCaseSensitive; 118 init(); 119 } 120 121 /** 122 * Copies this <code>ResultSet</code>. The data of the 123 * <code>ResultSet</code> is copied using the 124 * {@link com.mockrunner.jdbc.ParameterUtil#copyParameter} 125 * method. 126 * @return a copy of this <code>ResultSet</code> 127 */ 128 public Object clone() 129 { 130 try 131 { 132 MockResultSet copy = (MockResultSet)super.clone(); 133 copy.columnNameList = new ArrayList(columnNameList); 134 copy.updatedRows = new ArrayList(updatedRows); 135 copy.deletedRows = new ArrayList(deletedRows); 136 copy.insertedRows = new ArrayList(insertedRows); 137 copy.insertRow = copyColumnDataMap(insertRow); 138 copy.columnMap = copyColumnDataMap(columnMap); 139 copy.columnMapCopy = copyColumnDataMap(columnMapCopy); 140 if(null != resultSetMetaData && resultSetMetaData instanceof MockResultSetMetaData) 141 { 142 copy.resultSetMetaData = (ResultSetMetaData)((MockResultSetMetaData)resultSetMetaData).clone(); 143 } 144 return copy; 145 } 146 catch(CloneNotSupportedException exc) 147 { 148 throw new NestedApplicationException(exc); 149 } 150 } 151 152 /** 153 * Returns the id of this <code>ResultSet</code>. Ids are used 154 * to identify <code>ResultSet</code> objects in tests, because 155 * they are usually cloned when executing statements, so 156 * you cannot rely on the object identity. 157 * @return the id of this <code>ResultSet</code> 158 */ 159 public String getId() 160 { 161 return id; 162 } 163 164 /** 165 * Returns if this <code>ResultSet</code> is closed. 166 * @return <code>true</code> if this <code>ResultSet</code> is closed, 167 * <code>false</code> otherwise 168 */ 169 public boolean isClosed() 170 { 171 return closed; 172 } 173 174 /** 175 * Sets the <code>ResultSetMetaData</code> for this <code>ResultSet</code>. 176 * The specified object will be returned when calling {@link #getMetaData}. 177 * If no <code>ResultSetMetaData</code> is set, the method {@link #getMetaData} 178 * will return an object of {@link MockResultSetMetaData}. The 179 * <code>MockResultSetMetaData</code> returns default values for most 180 * of its attributes (however the correct number of columns will be 181 * returned). Usually you do not have to set the <code>ResultSetMetaData</code>. 182 * @param resultSetMetaData the <code>ResultSetMetaData</code> 183 */ 184 public void setResultSetMetaData(ResultSetMetaData resultSetMetaData) 185 { 186 this.resultSetMetaData = resultSetMetaData; 187 } 188 189 /** 190 * Sets the <code>Statement</code> for this <code>ResultSet</code>. 191 * The <code>ResultSet</code> takes the result set type, result 192 * set concurrency and the fetch direction from the specified 193 * <code>Statement</code>. 194 * @param statement the statement 195 */ 196 public void setStatement(Statement statement) 197 { 198 this.statement = statement; 199 try 200 { 201 fetchDirection = statement.getFetchDirection(); 202 resultSetType = statement.getResultSetType(); 203 resultSetConcurrency = statement.getResultSetConcurrency(); 204 resultSetHoldability = statement.getResultSetHoldability(); 205 fetchSize = statement.getFetchSize(); 206 cursorName = ((MockStatement)statement).getCursorName(); 207 } 208 catch(SQLException exc) 209 { 210 211 } 212 } 213 214 /** 215 * Sets the cursor name. It's not possible to set 216 * this in a real <code>ResultSet</code>. 217 * @param cursorName the cursor name 218 */ 219 public void setCursorName(String cursorName) 220 { 221 this.cursorName = cursorName; 222 } 223 224 /** 225 * Sets the result set type. It's not possible to set 226 * this in a real <code>ResultSet</code>, but in tests 227 * it can make sense to change it. 228 * @param resultSetType the result set type 229 */ 230 public void setResultSetType(int resultSetType) 231 { 232 this.resultSetType = resultSetType; 233 } 234 235 /** 236 * Sets the result set concurrency. It's not possible to set 237 * this in a real <code>ResultSet</code>, but in tests 238 * it can make sense to change it. 239 * @param resultSetConcurrency the result set concurrency 240 */ 241 public void setResultSetConcurrency(int resultSetConcurrency) 242 { 243 this.resultSetConcurrency = resultSetConcurrency; 244 } 245 246 /** 247 * Sets the result set holdability. It's not possible to set 248 * this in a real <code>ResultSet</code>, but in tests 249 * it can make sense to change it. 250 * @param resultSetHoldability the result set holdability 251 */ 252 public void setResultSetHoldability(int resultSetHoldability) 253 { 254 this.resultSetHoldability = resultSetHoldability; 255 } 256 257 /** 258 * The <code>MockResultSet</code> keeps the data that's 259 * stored in the simulated database and a copy of the data 260 * that represents the current <code>ResultSet</code> data. 261 * The <code>update</code> methods only update the 262 * <code>ResultSet</code> data. This data will be persisted 263 * when you call {@link #updateRow}. When you set <i>databaseView</i> 264 * to <code>true</code> the <code>get</code> methods will return the 265 * data in the database, otherwise the current <code>ResultSet</code> 266 * data is returned. 267 * @param databaseView <code>false</code> = get the data from the 268 * <code>ResultSet</code>, <code>true</code> = get the data 269 * from the database, default is <code>false</code> 270 * 271 */ 272 public void setDatabaseView(boolean databaseView) 273 { 274 this.isDatabaseView = databaseView; 275 } 276 277 /** 278 * Adds a row to the simulated database table. 279 * If there are not enough columns (initially there 280 * are no columns, you have to specify them with the 281 * <code>addColumn</code> methods) the missing columns will 282 * be added automatically. Automatically created columns 283 * will get the name <i>ColumnX</i> where <i>X</i> is 284 * the column index. 285 * @param values the row data as array, the array index 286 * corresponds to the column index, i.e. 287 * values[0] will be stored in the first column 288 * and so on 289 */ 290 public void addRow(Object[] values) 291 { 292 List valueList = Arrays.asList(values); 293 addRow(valueList); 294 } 295 296 /** 297 * Adds a row to the simulated database table. 298 * If there are not enough columns (initially there 299 * are no columns, you have to specify them with the 300 * <code>addColumn</code> methods) the missing columns will 301 * be added automatically. Automatically created columns 302 * will get the name <i>ColumnX</i> where <i>X</i> is 303 * the column index. 304 * @param values the row data as <code>List</code>, the index 305 * in the <code>List</code> corresponds to the column 306 * index, i.e. values.get(0) will be stored in the first 307 * column and so on 308 */ 309 public void addRow(List values) 310 { 311 int missingColumns = values.size() - columnNameList.size(); 312 for(int yy = 0; yy < missingColumns; yy++) 313 { 314 addColumn(); 315 } 316 adjustColumns(); 317 for(int ii = 0; ii < values.size(); ii++) 318 { 319 Object nextValue = values.get(ii); 320 String nextColumnName = (String)columnNameList.get(ii); 321 List nextColumnList = (List)columnMap.get(nextColumnName); 322 nextColumnList.add(nextValue); 323 } 324 adjustColumns(); 325 copyColumnMap(); 326 adjustFlags(); 327 } 328 329 /** 330 * Adds a column to the simulated database table. 331 * The column will get the name <i>ColumnX</i> where 332 * <i>X</i> is the column index. The first added column 333 * will have the name <i>Column1</i>. No data will be stored 334 * in the column. 335 */ 336 public void addColumn() 337 { 338 addColumn(determineValidColumnName()); 339 } 340 341 /** 342 * Adds a column to the simulated database table. 343 * The column will get the specified name. 344 * No data will be stored in the column. 345 * @param columnName the column name 346 */ 347 public void addColumn(String columnName) 348 { 349 addColumn(columnName, new ArrayList()); 350 } 351 352 /** 353 * Adds a column to the simulated database table. 354 * The column will get the name <i>ColumnX</i> where 355 * <i>X</i> is the column index. 356 * The specified data will be stored in the new column. If there 357 * are other columns with not enough rows, the other 358 * columns will be extended and filled with <code>null</code> 359 * values. 360 * @param values the column data as array, the array index 361 * corresponds to the row index, i.e. 362 * values[0] will be stored in the first row 363 * and so on 364 */ 365 public void addColumn(Object[] values) 366 { 367 addColumn(determineValidColumnName(), values); 368 } 369 370 /** 371 * Adds a column to the simulated database table. 372 * The column will get the name <i>ColumnX</i> where 373 * <i>X</i> is the column index. 374 * The specified data will be stored in the new column. If there 375 * are other columns with not enough rows, the other 376 * columns will be extended and filled with <code>null</code> 377 * values. 378 * @param values the column data as <code>List</code>, the index 379 * in the <code>List</code> corresponds to the row 380 * index, i.e. values.get(0) will be stored in the first 381 * row and so on 382 */ 383 public void addColumn(List values) 384 { 385 addColumn(determineValidColumnName(), values); 386 } 387 388 /** 389 * Adds a column to the simulated database table. 390 * The column will get the specified name. 391 * The specified data will be stored in the new column. If there 392 * are other columns with not enough rows, the other 393 * columns will be extended and filled with <code>null</code> 394 * values. 395 * @param columnName the column name 396 * @param values the column data as array, the array index 397 * corresponds to the row index, i.e. 398 * values[0] will be stored in the first row 399 * and so on 400 */ 401 public void addColumn(String columnName, Object[] values) 402 { 403 List columnValues = Arrays.asList(values); 404 addColumn(columnName, columnValues); 405 } 406 407 /** 408 * Adds a column to the simulated database table. 409 * The column will get the specified name. 410 * The specified data will be stored in the new column. If there 411 * are other columns with not enough rows, the other 412 * columns will be extended and filled with <code>null</code> 413 * values. 414 * @param columnName the column name 415 * @param values the column data as <code>List</code>, the index 416 * in the <code>List</code> corresponds to the row 417 * index, i.e. values.get(0) will be stored in the first 418 * row and so on 419 */ 420 public void addColumn(String columnName, List values) 421 { 422 List column = new ArrayList(values); 423 columnMap.put(columnName, column); 424 columnNameList.add(columnName); 425 adjustColumns(); 426 adjustInsertRow(); 427 copyColumnMap(); 428 adjustFlags(); 429 } 430 431 /** 432 * Returns the current number of rows. 433 * @return the number of rows 434 */ 435 public int getRowCount() 436 { 437 if(columnMapCopy.size() == 0) return 0; 438 List column = (List)columnMapCopy.values().iterator().next(); 439 return column.size(); 440 } 441 442 /** 443 * Returns the current number of columns. 444 * @return the number of columns 445 */ 446 public int getColumnCount() 447 { 448 return columnMapCopy.size(); 449 } 450 451 /** 452 * Returns if the row with the specified number was inserted 453 * The first row has the number 1. 454 * @param number the number of the row 455 * @return <code>true</code> if the row was inserted, 456 * <code>false</code> otherwise 457 */ 458 public boolean rowInserted(int number) 459 { 460 if(number < 1) return false; 461 return ((Boolean)insertedRows.get(number - 1)).booleanValue(); 462 } 463 464 /** 465 * Returns if the row with the specified number was deleted 466 * The first row has the number 1. 467 * @param number the number of the row 468 * @return <code>true</code> if the row was deleted, 469 * <code>false</code> otherwise 470 */ 471 public boolean rowDeleted(int number) 472 { 473 if(number < 1) return false; 474 return ((Boolean)deletedRows.get(number - 1)).booleanValue(); 475 } 476 477 /** 478 * Returns if the row with the specified number was updated 479 * The first row has the number 1. 480 * @param number the number of the row 481 * @return <code>true</code> if the row was updated, 482 * <code>false</code> otherwise 483 */ 484 public boolean rowUpdated(int number) 485 { 486 if(number < 1) return false; 487 return ((Boolean)updatedRows.get(number - 1)).booleanValue(); 488 } 489 490 /** 491 * Returns if the row with the specified number is 492 * equal to the specified data. Uses {@link com.mockrunner.jdbc.ParameterUtil#compareParameter}. 493 * The first row has the number 1. If the compared parameters are not of 494 * the same type (and cannot be equal according to the 495 * {@link com.mockrunner.jdbc.ParameterUtil#compareParameter} method) they 496 * will be converted to a string with the <code>toString()</code> method before 497 * comparison. 498 * @param number the number of the row 499 * @param rowData the row data 500 * @return <code>true</code> if the row is equal to the specified data, 501 * <code>false</code> otherwise 502 */ 503 public boolean isRowEqual(int number, List rowData) 504 { 505 List currentRow = getRow(number); 506 if(null == currentRow) return false; 507 if(currentRow.size() != rowData.size()) return false; 508 for(int ii = 0; ii < currentRow.size(); ii++) 509 { 510 Object source = currentRow.get(ii); 511 Object target = rowData.get(ii); 512 if(null != source && null != target) 513 { 514 if(!source.getClass().isAssignableFrom(target.getClass()) && !target.getClass().isAssignableFrom(source.getClass())) 515 { 516 source = source.toString(); 517 target = target.toString(); 518 } 519 } 520 if(!ParameterUtil.compareParameter(source, target)) 521 { 522 return false; 523 } 524 } 525 return true; 526 } 527 528 /** 529 * Returns if the column with the specified number is 530 * equal to the specified data. Uses {@link com.mockrunner.jdbc.ParameterUtil#compareParameter}. 531 * The first column has the number 1. If the compared parameters are not of 532 * the same type (and cannot be equal according to the 533 * {@link com.mockrunner.jdbc.ParameterUtil#compareParameter} method) they 534 * will be converted to a string with the <code>toString()</code> method before 535 * comparison. 536 * @param number the number of the column 537 * @param columnData the column data 538 * @return <code>true</code> if the column is equal to the specified data, 539 * <code>false</code> otherwise 540 */ 541 public boolean isColumnEqual(int number, List columnData) 542 { 543 List currentColumn = getColumn(number); 544 if(null == currentColumn) return false; 545 if(currentColumn.size() != columnData.size()) return false; 546 for(int ii = 0; ii < currentColumn.size(); ii++) 547 { 548 Object source = currentColumn.get(ii); 549 Object target = columnData.get(ii); 550 if(null != source && null != target) 551 { 552 if(!source.getClass().isAssignableFrom(target.getClass()) && !target.getClass().isAssignableFrom(source.getClass())) 553 { 554 source = source.toString(); 555 target = target.toString(); 556 } 557 } 558 if(!ParameterUtil.compareParameter(source, target)) 559 { 560 return false; 561 } 562 } 563 return true; 564 } 565 566 /** 567 * Returns if the column with the specified name is 568 * equal to the specified data. Uses {@link com.mockrunner.jdbc.ParameterUtil#compareParameter}. 569 * The first column has the number 1. If the compared parameters are not of 570 * the same type (and cannot be equal according to the 571 * {@link com.mockrunner.jdbc.ParameterUtil#compareParameter} method) they 572 * will be converted to a string with the <code>toString()</code> method before 573 * comparison. 574 * @param name the name of the column 575 * @param columnData the column data 576 * @return <code>true</code> if the column is equal to the specified data, 577 * <code>false</code> otherwise 578 */ 579 public boolean isColumnEqual(String name, List columnData) 580 { 581 List currentColumn = getColumn(name); 582 if(null == currentColumn) return false; 583 if(currentColumn.size() != columnData.size()) return false; 584 for(int ii = 0; ii < currentColumn.size(); ii++) 585 { 586 Object source = currentColumn.get(ii); 587 Object target = columnData.get(ii); 588 if(null != source && null != target) 589 { 590 if(!source.getClass().isAssignableFrom(target.getClass()) && !target.getClass().isAssignableFrom(source.getClass())) 591 { 592 source = source.toString(); 593 target = target.toString(); 594 } 595 } 596 if(!ParameterUtil.compareParameter(source, target)) 597 { 598 return false; 599 } 600 } 601 return true; 602 } 603 604 /** 605 * Returns if the specified <code>ResultSet</code> is equal to 606 * this <code>ResultSet</code>. If the compared parameters are not of 607 * the same type (and cannot be equal according to the 608 * {@link com.mockrunner.jdbc.ParameterUtil#compareParameter} method) they 609 * will be converted to a string with the <code>toString()</code> method before 610 * comparison. 611 * @return <code>true</code> if the two <code>ResultSet</code> objects are equal, 612 * <code>false</code> otherwise 613 */ 614 public boolean isEqual(MockResultSet resultSet) 615 { 616 if(null == resultSet) return false; 617 Map thisMap; 618 Map otherMap; 619 if(isDatabaseView) 620 { 621 thisMap = columnMap; 622 } 623 else 624 { 625 thisMap = columnMapCopy; 626 } 627 if(resultSet.isDatabaseView) 628 { 629 otherMap = resultSet.columnMap; 630 } 631 else 632 { 633 otherMap = resultSet.columnMapCopy; 634 } 635 Iterator keys = thisMap.keySet().iterator(); 636 while(keys.hasNext()) 637 { 638 String currentKey = (String)keys.next(); 639 List thisList = (List)thisMap.get(currentKey); 640 List otherList = (List)otherMap.get(currentKey); 641 if(null == otherList) return false; 642 if(thisList.size() != otherList.size()) return false; 643 for(int ii = 0; ii < thisList.size(); ii++) 644 { 645 Object source = thisList.get(ii); 646 Object target = otherList.get(ii); 647 if(null != source && null != target) 648 { 649 if(!source.getClass().isAssignableFrom(target.getClass()) && !target.getClass().isAssignableFrom(source.getClass())) 650 { 651 source = source.toString(); 652 target = target.toString(); 653 } 654 } 655 if(!ParameterUtil.compareParameter(source, target)) 656 { 657 return false; 658 } 659 } 660 } 661 return true; 662 } 663 664 /** 665 * Returns the row with the specified number. 666 * The first row has the number 1. 667 * If number is less than 1 or higher than the 668 * current row count, <code>null</code> will 669 * be returned. The result of this method depends 670 * on the setting of <i>databaseView</i>. 671 * See {@link #setDatabaseView}. 672 * @param number the number of the row 673 * @return the row data as <code>List</code> 674 */ 675 public List getRow(int number) 676 { 677 if(number > getRowCount()) return null; 678 if(number < 1) return null; 679 int index = number - 1; 680 List list = new ArrayList(); 681 for(int ii = 0; ii < columnNameList.size(); ii++) 682 { 683 String nextColumnName = (String)columnNameList.get(ii); 684 List nextColumnList; 685 if(isDatabaseView) 686 { 687 nextColumnList = (List)columnMap.get(nextColumnName); 688 } 689 else 690 { 691 nextColumnList = (List)columnMapCopy.get(nextColumnName); 692 } 693 list.add(nextColumnList.get(index)); 694 } 695 return list; 696 } 697 698 /** 699 * Returns the column with the specified number. 700 * The first column has the number 1. 701 * If number is less than 1 or higher than the 702 * current column count, <code>null</code> will 703 * be returned. 704 * @param number the number of the column 705 * @return the column data as <code>List</code> 706 */ 707 public List getColumn(int number) 708 { 709 if(number > getColumnCount()) return null; 710 if(number < 1) return null; 711 int index = number - 1; 712 String columnName = (String)columnNameList.get(index); 713 return getColumn(columnName); 714 } 715 716 /** 717 * Returns the column with the specified name. 718 * If a column with that name does not exist, 719 * <code>null</code> will be returned. 720 * @param name the name of the column 721 * @return the column data as <code>List</code> 722 */ 723 public List getColumn(String name) 724 { 725 List list = new ArrayList(); 726 List columnList; 727 if(isDatabaseView) 728 { 729 columnList = (List)columnMap.get(name); 730 } 731 else 732 { 733 columnList = (List)columnMapCopy.get(name); 734 } 735 if(null == columnList) return null; 736 list.addAll(columnList); 737 return list; 738 } 739 740 public void close() throws SQLException 741 { 742 closed = true; 743 } 744 745 public boolean wasNull() throws SQLException 746 { 747 return wasNull; 748 } 749 750 public Object getObject(int columnIndex) throws SQLException 751 { 752 checkColumnBounds(columnIndex); 753 checkRowBounds(); 754 String columnName = (String)columnNameList.get(columnIndex - 1); 755 return getObject(columnName); 756 } 757 758 public Object getObject(String columnName) throws SQLException 759 { 760 checkColumnName(columnName); 761 checkRowBounds(); 762 if(rowDeleted()) throw new SQLException("row was deleted"); 763 List column; 764 if(isDatabaseView) 765 { 766 column = (List)columnMap.get(columnName); 767 } 768 else 769 { 770 column = (List)columnMapCopy.get(columnName); 771 } 772 Object value = column.get(cursor); 773 wasNull = (null == value); 774 return value; 775 } 776 777 public Object getObject(int columnIndex, Map map) throws SQLException 778 { 779 return getObject(columnIndex); 780 } 781 782 public Object getObject(String colName, Map map) throws SQLException 783 { 784 return getObject(colName); 785 } 786 787 public String getString(int columnIndex) throws SQLException 788 { 789 Object value = getObject(columnIndex); 790 if(null != value) return value.toString(); 791 return null; 792 } 793 794 public String getString(String columnName) throws SQLException 795 { 796 Object value = getObject(columnName); 797 if(null != value) return value.toString(); 798 return null; 799 } 800 801 public String getNString(int columnIndex) throws SQLException 802 { 803 return getString(columnIndex); 804 } 805 806 public String getNString(String columnLabel) throws SQLException 807 { 808 return getString(columnLabel); 809 } 810 811 public boolean getBoolean(int columnIndex) throws SQLException 812 { 813 Object value = getObject(columnIndex); 814 if(null != value) 815 { 816 if(value instanceof Boolean) return ((Boolean)value).booleanValue(); 817 return new Boolean(value.toString()).booleanValue(); 818 } 819 return false; 820 } 821 822 public boolean getBoolean(String columnName) throws SQLException 823 { 824 Object value = getObject(columnName); 825 if(null != value) 826 { 827 if(value instanceof Boolean) return ((Boolean)value).booleanValue(); 828 return new Boolean(value.toString()).booleanValue(); 829 } 830 return false; 831 } 832 833 public byte getByte(int columnIndex) throws SQLException 834 { 835 Object value = getObject(columnIndex); 836 if(null != value) 837 { 838 if(value instanceof Number) return ((Number)value).byteValue(); 839 return new Byte(value.toString()).byteValue(); 840 } 841 return 0; 842 } 843 844 public byte getByte(String columnName) throws SQLException 845 { 846 Object value = getObject(columnName); 847 if(null != value) 848 { 849 if(value instanceof Number) return ((Number)value).byteValue(); 850 return new Byte(value.toString()).byteValue(); 851 } 852 return 0; 853 } 854 855 public short getShort(int columnIndex) throws SQLException 856 { 857 Object value = getObject(columnIndex); 858 if(null != value) 859 { 860 if(value instanceof Number) return ((Number)value).shortValue(); 861 return new Short(value.toString()).shortValue(); 862 } 863 return 0; 864 } 865 866 public short getShort(String columnName) throws SQLException 867 { 868 Object value = getObject(columnName); 869 if(null != value) 870 { 871 if(value instanceof Number) return ((Number)value).shortValue(); 872 return new Short(value.toString()).shortValue(); 873 } 874 return 0; 875 } 876 877 public int getInt(int columnIndex) throws SQLException 878 { 879 Object value = getObject(columnIndex); 880 if(null != value) 881 { 882 if(value instanceof Number) return ((Number)value).intValue(); 883 return new Integer(value.toString()).intValue(); 884 } 885 return 0; 886 } 887 888 public int getInt(String columnName) throws SQLException 889 { 890 Object value = getObject(columnName); 891 if(null != value) 892 { 893 if(value instanceof Number) return ((Number)value).intValue(); 894 return new Integer(value.toString()).intValue(); 895 } 896 return 0; 897 } 898 899 public long getLong(int columnIndex) throws SQLException 900 { 901 Object value = getObject(columnIndex); 902 if(null != value) 903 { 904 if(value instanceof Number) return ((Number)value).longValue(); 905 return new Long(value.toString()).longValue(); 906 } 907 return 0; 908 } 909 910 public long getLong(String columnName) throws SQLException 911 { 912 Object value = getObject(columnName); 913 if(null != value) 914 { 915 if(value instanceof Number) return ((Number)value).longValue(); 916 return new Long(value.toString()).longValue(); 917 } 918 return 0; 919 } 920 921 public float getFloat(int columnIndex) throws SQLException 922 { 923 Object value = getObject(columnIndex); 924 if(null != value) 925 { 926 if(value instanceof Number) return ((Number)value).floatValue(); 927 return new Float(value.toString()).floatValue(); 928 } 929 return 0; 930 } 931 932 public float getFloat(String columnName) throws SQLException 933 { 934 Object value = getObject(columnName); 935 if(null != value) 936 { 937 if(value instanceof Number) return ((Number)value).floatValue(); 938 return new Float(value.toString()).floatValue(); 939 } 940 return 0; 941 } 942 943 public double getDouble(int columnIndex) throws SQLException 944 { 945 Object value = getObject(columnIndex); 946 if(null != value) 947 { 948 if(value instanceof Number) return ((Number)value).doubleValue(); 949 return new Double(value.toString()).doubleValue(); 950 } 951 return 0; 952 } 953 954 public double getDouble(String columnName) throws SQLException 955 { 956 Object value = getObject(columnName); 957 if(null != value) 958 { 959 if(value instanceof Number) return ((Number)value).doubleValue(); 960 return new Double(value.toString()).doubleValue(); 961 } 962 return 0; 963 } 964 965 public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException 966 { 967 BigDecimal value = getBigDecimal(columnIndex); 968 if(null != value) 969 { 970 return value.setScale(scale); 971 } 972 return null; 973 } 974 975 public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException 976 { 977 BigDecimal value = getBigDecimal(columnName); 978 if(null != value) 979 { 980 return value.setScale(scale); 981 } 982 return null; 983 } 984 985 public BigDecimal getBigDecimal(int columnIndex) throws SQLException 986 { 987 Object value = getObject(columnIndex); 988 if(null != value) 989 { 990 if(value instanceof Number) return new BigDecimal(((Number)value).doubleValue()); 991 return new BigDecimal(value.toString()); 992 } 993 return null; 994 } 995 996 public BigDecimal getBigDecimal(String columnName) throws SQLException 997 { 998 Object value = getObject(columnName); 999 if(null != value) 1000 { 1001 if(value instanceof Number) return new BigDecimal(((Number)value).doubleValue()); 1002 return new BigDecimal(value.toString()); 1003 } 1004 return null; 1005 } 1006 1007 public byte[] getBytes(int columnIndex) throws SQLException 1008 { 1009 Object value = getObject(columnIndex); 1010 if(null != value) 1011 { 1012 if(value instanceof byte[]) return (byte[])value; 1013 try 1014 { 1015 return value.toString().getBytes("ISO-8859-1"); 1016 } 1017 catch(UnsupportedEncodingException exc) 1018 { 1019 throw new NestedApplicationException(exc); 1020 } 1021 } 1022 return null; 1023 } 1024 1025 public byte[] getBytes(String columnName) throws SQLException 1026 { 1027 Object value = getObject(columnName); 1028 if(null != value) 1029 { 1030 if(value instanceof byte[]) return (byte[])value; 1031 try 1032 { 1033 return value.toString().getBytes("ISO-8859-1"); 1034 } 1035 catch(UnsupportedEncodingException exc) 1036 { 1037 throw new NestedApplicationException(exc); 1038 } 1039 } 1040 return null; 1041 } 1042 1043 public Date getDate(int columnIndex) throws SQLException 1044 { 1045 Object value = getObject(columnIndex); 1046 if(null != value) 1047 { 1048 if(value instanceof Date) return (Date)value; 1049 return Date.valueOf(value.toString()); 1050 } 1051 return null; 1052 } 1053 1054 public Date getDate(String columnName) throws SQLException 1055 { 1056 Object value = getObject(columnName); 1057 if(null != value) 1058 { 1059 if(value instanceof Date) return (Date)value; 1060 return Date.valueOf(value.toString()); 1061 } 1062 return null; 1063 } 1064 1065 public Date getDate(int columnIndex, Calendar calendar) throws SQLException 1066 { 1067 return getDate(columnIndex); 1068 } 1069 1070 public Date getDate(String columnName, Calendar calendar) throws SQLException 1071 { 1072 return getDate(columnName); 1073 } 1074 1075 public Time getTime(int columnIndex) throws SQLException 1076 { 1077 Object value = getObject(columnIndex); 1078 if(null != value) 1079 { 1080 if(value instanceof Time) return (Time)value; 1081 return Time.valueOf(value.toString()); 1082 } 1083 return null; 1084 } 1085 1086 public Time getTime(String columnName) throws SQLException 1087 { 1088 Object value = getObject(columnName); 1089 if(null != value) 1090 { 1091 if(value instanceof Time) return (Time)value; 1092 return Time.valueOf(value.toString()); 1093 } 1094 return null; 1095 } 1096 1097 public Time getTime(int columnIndex, Calendar calendar) throws SQLException 1098 { 1099 return getTime(columnIndex); 1100 } 1101 1102 public Time getTime(String columnName, Calendar calendar) throws SQLException 1103 { 1104 return getTime(columnName); 1105 } 1106 1107 public Timestamp getTimestamp(int columnIndex) throws SQLException 1108 { 1109 Object value = getObject(columnIndex); 1110 if(null != value) 1111 { 1112 if(value instanceof Timestamp) return (Timestamp)value; 1113 return Timestamp.valueOf(value.toString()); 1114 } 1115 return null; 1116 } 1117 1118 public Timestamp getTimestamp(String columnName) throws SQLException 1119 { 1120 Object value = getObject(columnName); 1121 if(null != value) 1122 { 1123 if(value instanceof Timestamp) return (Timestamp)value; 1124 return Timestamp.valueOf(value.toString()); 1125 } 1126 return null; 1127 } 1128 1129 public Timestamp getTimestamp(int columnIndex, Calendar calendar) throws SQLException 1130 { 1131 return getTimestamp(columnIndex); 1132 } 1133 1134 public Timestamp getTimestamp(String columnName, Calendar calendar) throws SQLException 1135 { 1136 return getTimestamp(columnName); 1137 } 1138 1139 public URL getURL(int columnIndex) throws SQLException 1140 { 1141 Object value = getObject(columnIndex); 1142 if(null != value) 1143 { 1144 if(value instanceof URL) return (URL)value; 1145 try 1146 { 1147 return new URL(value.toString()); 1148 } 1149 catch(MalformedURLException exc) 1150 { 1151 1152 } 1153 } 1154 return null; 1155 } 1156 1157 public URL getURL(String columnName) throws SQLException 1158 { 1159 Object value = getObject(columnName); 1160 if(null != value) 1161 { 1162 if(value instanceof URL) return (URL)value; 1163 try 1164 { 1165 return new URL(value.toString()); 1166 } 1167 catch(MalformedURLException exc) 1168 { 1169 1170 } 1171 } 1172 return null; 1173 } 1174 1175 public Blob getBlob(int columnIndex) throws SQLException 1176 { 1177 Object value = getObject(columnIndex); 1178 if(null != value) 1179 { 1180 if(value instanceof Blob) return (Blob)value; 1181 return new MockBlob(getBytes(columnIndex)); 1182 } 1183 return null; 1184 } 1185 1186 public Blob getBlob(String columnName) throws SQLException 1187 { 1188 Object value = getObject(columnName); 1189 if(null != value) 1190 { 1191 if(value instanceof Blob) return (Blob)value; 1192 return new MockBlob(getBytes(columnName)); 1193 } 1194 return null; 1195 } 1196 1197 public Clob getClob(int columnIndex) throws SQLException 1198 { 1199 Object value = getObject(columnIndex); 1200 if(null != value) 1201 { 1202 if(value instanceof Clob) return (Clob)value; 1203 return new MockClob(getString(columnIndex)); 1204 } 1205 return null; 1206 } 1207 1208 public Clob getClob(String columnName) throws SQLException 1209 { 1210 Object value = getObject(columnName); 1211 if(null != value) 1212 { 1213 if(value instanceof Clob) return (Clob)value; 1214 return new MockClob(getString(columnName)); 1215 } 1216 return null; 1217 } 1218 1219 public NClob getNClob(int columnIndex) throws SQLException 1220 { 1221 Object value = getObject(columnIndex); 1222 if(null != value) 1223 { 1224 if(value instanceof NClob) return (NClob)value; 1225 if(value instanceof Clob) return getNClobFromClob((Clob)value); 1226 return new MockNClob(getString(columnIndex)); 1227 } 1228 return null; 1229 } 1230 1231 public NClob getNClob(String columnName) throws SQLException 1232 { 1233 Object value = getObject(columnName); 1234 if(null != value) 1235 { 1236 if(value instanceof NClob) return (NClob)value; 1237 if(value instanceof Clob) return getNClobFromClob((Clob)value); 1238 return new MockNClob(getString(columnName)); 1239 } 1240 return null; 1241 } 1242 1243 public SQLXML getSQLXML(int columnIndex) throws SQLException 1244 { 1245 Object value = getObject(columnIndex); 1246 if(null != value) 1247 { 1248 if(value instanceof SQLXML) return (SQLXML)value; 1249 return new MockSQLXML(getString(columnIndex)); 1250 } 1251 return null; 1252 } 1253 1254 public SQLXML getSQLXML(String columnName) throws SQLException 1255 { 1256 Object value = getObject(columnName); 1257 if(null != value) 1258 { 1259 if(value instanceof SQLXML) return (SQLXML)value; 1260 return new MockSQLXML(getString(columnName)); 1261 } 1262 return null; 1263 } 1264 1265 public Array getArray(int columnIndex) throws SQLException 1266 { 1267 Object value = getObject(columnIndex); 1268 if(null != value) 1269 { 1270 if(value instanceof Array) return (Array)value; 1271 return new MockArray(value); 1272 } 1273 return null; 1274 } 1275 1276 public Array getArray(String columnName) throws SQLException 1277 { 1278 Object value = getObject(columnName); 1279 if(null != value) 1280 { 1281 if(value instanceof Array) return (Array)value; 1282 return new MockArray(value); 1283 } 1284 return null; 1285 } 1286 1287 public Ref getRef(int columnIndex) throws SQLException 1288 { 1289 Object value = getObject(columnIndex); 1290 if(null != value) 1291 { 1292 if(value instanceof Ref) return (Ref)value; 1293 return new MockRef(value); 1294 } 1295 return null; 1296 } 1297 1298 public Ref getRef(String columnName) throws SQLException 1299 { 1300 Object value = getObject(columnName); 1301 if(null != value) 1302 { 1303 if(value instanceof Ref) return (Ref)value; 1304 return new MockRef(value); 1305 } 1306 return null; 1307 } 1308 1309 public RowId getRowId(int columnIndex) throws SQLException 1310 { 1311 Object value = getObject(columnIndex); 1312 if(null != value) 1313 { 1314 if(value instanceof RowId) return (RowId)value; 1315 return new MockRowId(getBytes(columnIndex)); 1316 } 1317 return null; 1318 } 1319 1320 public RowId getRowId(String columnName) throws SQLException 1321 { 1322 Object value = getObject(columnName); 1323 if(null != value) 1324 { 1325 if(value instanceof RowId) return (RowId)value; 1326 return new MockRowId(getBytes(columnName)); 1327 } 1328 return null; 1329 } 1330 1331 public InputStream getAsciiStream(int columnIndex) throws SQLException 1332 { 1333 return getBinaryStream(columnIndex); 1334 } 1335 1336 public InputStream getAsciiStream(String columnName) throws SQLException 1337 { 1338 return getBinaryStream(columnName); 1339 } 1340 1341 public InputStream getBinaryStream(int columnIndex) throws SQLException 1342 { 1343 Object value = getObject(columnIndex); 1344 if(null != value) 1345 { 1346 if(value instanceof InputStream) return (InputStream)value; 1347 return new ByteArrayInputStream(getBytes(columnIndex)); 1348 } 1349 return null; 1350 } 1351 1352 public InputStream getBinaryStream(String columnName) throws SQLException 1353 { 1354 Object value = getObject(columnName); 1355 if(null != value) 1356 { 1357 if(value instanceof InputStream) return (InputStream)value; 1358 return new ByteArrayInputStream(getBytes(columnName)); 1359 } 1360 return null; 1361 } 1362 1363 public InputStream getUnicodeStream(int columnIndex) throws SQLException 1364 { 1365 Object value = getObject(columnIndex); 1366 if(null != value) 1367 { 1368 if(value instanceof InputStream) return (InputStream)value; 1369 try 1370 { 1371 return new ByteArrayInputStream(getString(columnIndex).getBytes("UTF-8")); 1372 } 1373 catch(UnsupportedEncodingException exc) 1374 { 1375 throw new NestedApplicationException(exc); 1376 } 1377 } 1378 return null; 1379 } 1380 1381 public InputStream getUnicodeStream(String columnName) throws SQLException 1382 { 1383 Object value = getObject(columnName); 1384 if(null != value) 1385 { 1386 if(value instanceof InputStream) return (InputStream)value; 1387 try 1388 { 1389 return new ByteArrayInputStream(getString(columnName).getBytes("UTF-8")); 1390 } 1391 catch(UnsupportedEncodingException exc) 1392 { 1393 throw new NestedApplicationException(exc); 1394 } 1395 } 1396 return null; 1397 } 1398 1399 public Reader getCharacterStream(int columnIndex) throws SQLException 1400 { 1401 Object value = getObject(columnIndex); 1402 if(null != value) 1403 { 1404 if(value instanceof Reader) return (Reader)value; 1405 return new StringReader(getString(columnIndex)); 1406 } 1407 return null; 1408 } 1409 1410 public Reader getCharacterStream(String columnName) throws SQLException 1411 { 1412 Object value = getObject(columnName); 1413 if(null != value) 1414 { 1415 if(value instanceof Reader) return (Reader)value; 1416 return new StringReader(getString(columnName)); 1417 } 1418 return null; 1419 } 1420 1421 public Reader getNCharacterStream(int columnIndex) throws SQLException 1422 { 1423 return getCharacterStream(columnIndex); 1424 } 1425 1426 public Reader getNCharacterStream(String columnLabel) throws SQLException 1427 { 1428 return getCharacterStream(columnLabel); 1429 } 1430 1431 public SQLWarning getWarnings() throws SQLException 1432 { 1433 return null; 1434 } 1435 1436 public void clearWarnings() throws SQLException 1437 { 1438 1439 } 1440 1441 public String getCursorName() throws SQLException 1442 { 1443 return cursorName; 1444 } 1445 1446 public ResultSetMetaData getMetaData() throws SQLException 1447 { 1448 if(null != resultSetMetaData) return resultSetMetaData; 1449 MockResultSetMetaData metaData = new MockResultSetMetaData(); 1450 metaData.setColumnCount(getColumnCount()); 1451 for(int ii = 0; ii < columnNameList.size(); ii++) 1452 { 1453 metaData.setColumnName(ii + 1, (String)columnNameList.get(ii)); 1454 } 1455 return metaData; 1456 } 1457 1458 public Statement getStatement() throws SQLException 1459 { 1460 return statement; 1461 } 1462 1463 public boolean isBeforeFirst() throws SQLException 1464 { 1465 // Counterintuitively, this method is supposed to return false when the 1466 // result set is empty. 1467 return (getRowCount() != 0) && (cursor == -1); 1468 } 1469 1470 public boolean isAfterLast() throws SQLException 1471 { 1472 return cursor >= getRowCount(); 1473 } 1474 1475 public boolean isFirst() throws SQLException 1476 { 1477 return cursor == 0; 1478 } 1479 1480 public boolean isLast() throws SQLException 1481 { 1482 return (cursor != -1) && (cursor == getRowCount() - 1); 1483 } 1484 1485 public void beforeFirst() throws SQLException 1486 { 1487 if(isCursorInInsertRow) throw new SQLException("cursor is in insert row"); 1488 checkResultSetType(); 1489 cursor = -1; 1490 } 1491 1492 public void afterLast() throws SQLException 1493 { 1494 if(isCursorInInsertRow) throw new SQLException("cursor is in insert row"); 1495 checkResultSetType(); 1496 if(getRowCount() == 0) return; 1497 cursor = getRowCount(); 1498 } 1499 1500 public boolean next() throws SQLException 1501 { 1502 if(isCursorInInsertRow) throw new SQLException("cursor is in insert row"); 1503 if(getRowCount() == 0) return false; 1504 cursor++; 1505 adjustCursor(); 1506 return isCurrentRowValid(); 1507 } 1508 1509 1510 public boolean first() throws SQLException 1511 { 1512 if(isCursorInInsertRow) throw new SQLException("cursor is in insert row"); 1513 checkResultSetType(); 1514 if(getRowCount() == 0) return false; 1515 cursor = 0; 1516 return true; 1517 } 1518 1519 public boolean last() throws SQLException 1520 { 1521 if(isCursorInInsertRow) throw new SQLException("cursor is in insert row"); 1522 checkResultSetType(); 1523 if(getRowCount() == 0) return false; 1524 cursor = getRowCount() - 1; 1525 return true; 1526 } 1527 1528 public boolean absolute(int row) throws SQLException 1529 { 1530 if(isCursorInInsertRow) throw new SQLException("cursor is in insert row"); 1531 checkResultSetType(); 1532 if(getRowCount() == 0) return false; 1533 if(row > 0) cursor = row - 1; 1534 if(row < 0) cursor = getRowCount() + row; 1535 adjustCursor(); 1536 return isCurrentRowValid(); 1537 } 1538 1539 public boolean relative(int rows) throws SQLException 1540 { 1541 if(isCursorInInsertRow) throw new SQLException("cursor is in insert row"); 1542 checkResultSetType(); 1543 if(getRowCount() == 0) return false; 1544 cursor += rows; 1545 adjustCursor(); 1546 return isCurrentRowValid(); 1547 } 1548 1549 public int getRow() throws SQLException 1550 { 1551 return cursor + 1; 1552 } 1553 1554 public boolean previous() throws SQLException 1555 { 1556 if(isCursorInInsertRow) throw new SQLException("cursor is in insert row"); 1557 checkResultSetType(); 1558 if(getRowCount() == 0) return false; 1559 cursor--; 1560 adjustCursor(); 1561 return isCurrentRowValid(); 1562 } 1563 1564 public void setFetchDirection(int fetchDirection) throws SQLException 1565 { 1566 checkFetchDirectionArguments(fetchDirection); 1567 if(this.fetchDirection == fetchDirection) return; 1568 if(this.fetchDirection == ResultSet.FETCH_UNKNOWN || fetchDirection == ResultSet.FETCH_UNKNOWN) 1569 { 1570 this.fetchDirection = fetchDirection; 1571 return; 1572 } 1573 this.fetchDirection = fetchDirection; 1574 Iterator columns = columnMapCopy.values().iterator(); 1575 while(columns.hasNext()) 1576 { 1577 List column = (List)columns.next(); 1578 Collections.reverse(column); 1579 } 1580 if(-1 != cursor) cursor = getRowCount() - cursor - 1; 1581 } 1582 1583 public int getFetchDirection() throws SQLException 1584 { 1585 return fetchDirection; 1586 } 1587 1588 public void setFetchSize(int fetchSize) throws SQLException 1589 { 1590 this.fetchSize = fetchSize; 1591 } 1592 1593 public int getFetchSize() throws SQLException 1594 { 1595 return fetchSize; 1596 } 1597 1598 public int getType() throws SQLException 1599 { 1600 return resultSetType; 1601 } 1602 1603 public int getConcurrency() throws SQLException 1604 { 1605 return resultSetConcurrency; 1606 } 1607 1608 public int getHoldability() throws SQLException 1609 { 1610 return resultSetHoldability; 1611 } 1612 1613 public int findColumn(String columnName) throws SQLException 1614 { 1615 for(int ii = 0; ii < columnNameList.size(); ii++) 1616 { 1617 if(columnName.equals(columnNameList.get(ii))) return ii + 1; 1618 } 1619 throw new SQLException("No column with name " + columnName + " found"); 1620 } 1621 1622 public void updateObject(int columnIndex, Object value) throws SQLException 1623 { 1624 checkColumnBounds(columnIndex); 1625 if(!isCursorInInsertRow) 1626 { 1627 checkRowBounds(); 1628 if(rowDeleted()) throw new SQLException("row was deleted"); 1629 } 1630 String columnName = (String)columnNameList.get(columnIndex - 1); 1631 updateObject(columnName, value); 1632 } 1633 1634 public void updateObject(int columnIndex, Object value, int scale) throws SQLException 1635 { 1636 updateObject(columnIndex, value); 1637 } 1638 1639 public void updateObject(String columnName, Object value, int scale) throws SQLException 1640 { 1641 updateObject(columnName, value); 1642 } 1643 1644 public void updateObject(String columnName, Object value) throws SQLException 1645 { 1646 checkColumnName(columnName); 1647 checkResultSetConcurrency(); 1648 if(!isCursorInInsertRow) 1649 { 1650 checkRowBounds(); 1651 if(rowDeleted()) throw new SQLException("row was deleted"); 1652 } 1653 if(isCursorInInsertRow) 1654 { 1655 List column = (List)insertRow.get(columnName); 1656 column.set(0, value); 1657 } 1658 else 1659 { 1660 List column = (List)columnMapCopy.get(columnName); 1661 column.set(cursor, value); 1662 } 1663 } 1664 1665 public void updateString(int columnIndex, String value) throws SQLException 1666 { 1667 updateObject(columnIndex, value); 1668 } 1669 1670 public void updateString(String columnName, String value) throws SQLException 1671 { 1672 updateObject(columnName, value); 1673 } 1674 1675 public void updateNString(int columnIndex, String value) throws SQLException 1676 { 1677 updateObject(columnIndex, value); 1678 } 1679 1680 public void updateNString(String columnLabel, String value) throws SQLException 1681 { 1682 updateObject(columnLabel, value); 1683 } 1684 1685 public void updateNull(int columnIndex) throws SQLException 1686 { 1687 updateObject(columnIndex, null); 1688 } 1689 1690 public void updateNull(String columnName) throws SQLException 1691 { 1692 updateObject(columnName, null); 1693 } 1694 1695 public void updateBoolean(int columnIndex, boolean booleanValue) throws SQLException 1696 { 1697 updateObject(columnIndex, new Boolean(booleanValue)); 1698 } 1699 1700 public void updateBoolean(String columnName, boolean booleanValue) throws SQLException 1701 { 1702 updateObject(columnName, new Boolean(booleanValue)); 1703 } 1704 1705 public void updateByte(int columnIndex, byte byteValue) throws SQLException 1706 { 1707 updateObject(columnIndex, new Byte(byteValue)); 1708 } 1709 1710 public void updateByte(String columnName, byte byteValue) throws SQLException 1711 { 1712 updateObject(columnName, new Byte(byteValue)); 1713 } 1714 1715 public void updateShort(int columnIndex, short shortValue) throws SQLException 1716 { 1717 updateObject(columnIndex, new Short(shortValue)); 1718 } 1719 1720 public void updateShort(String columnName, short shortValue) throws SQLException 1721 { 1722 updateObject(columnName, new Short(shortValue)); 1723 } 1724 1725 public void updateInt(int columnIndex, int intValue) throws SQLException 1726 { 1727 updateObject(columnIndex, new Integer(intValue)); 1728 } 1729 1730 public void updateInt(String columnName, int intValue) throws SQLException 1731 { 1732 updateObject(columnName, new Integer(intValue)); 1733 } 1734 1735 public void updateLong(int columnIndex, long longValue) throws SQLException 1736 { 1737 updateObject(columnIndex, new Long(longValue)); 1738 } 1739 1740 public void updateLong(String columnName, long longValue) throws SQLException 1741 { 1742 updateObject(columnName, new Long(longValue)); 1743 } 1744 1745 public void updateFloat(int columnIndex, float floatValue) throws SQLException 1746 { 1747 updateObject(columnIndex, new Float(floatValue)); 1748 } 1749 1750 public void updateFloat(String columnName, float floatValue) throws SQLException 1751 { 1752 updateObject(columnName, new Float(floatValue)); 1753 } 1754 1755 public void updateDouble(int columnIndex, double doubleValue) throws SQLException 1756 { 1757 updateObject(columnIndex, new Double(doubleValue)); 1758 } 1759 1760 public void updateDouble(String columnName, double doubleValue) throws SQLException 1761 { 1762 updateObject(columnName, new Double(doubleValue)); 1763 } 1764 1765 public void updateBigDecimal(int columnIndex, BigDecimal bigDecimal) throws SQLException 1766 { 1767 updateObject(columnIndex, bigDecimal); 1768 } 1769 1770 public void updateBigDecimal(String columnName, BigDecimal bigDecimal) throws SQLException 1771 { 1772 updateObject(columnName, bigDecimal); 1773 } 1774 1775 public void updateBytes(int columnIndex, byte[] byteArray) throws SQLException 1776 { 1777 updateObject(columnIndex, byteArray); 1778 } 1779 1780 public void updateBytes(String columnName, byte[] byteArray) throws SQLException 1781 { 1782 updateObject(columnName, byteArray); 1783 } 1784 1785 public void updateDate(int columnIndex, Date date) throws SQLException 1786 { 1787 updateObject(columnIndex, date); 1788 } 1789 1790 public void updateDate(String columnName, Date date) throws SQLException 1791 { 1792 updateObject(columnName, date); 1793 } 1794 1795 public void updateTime(int columnIndex, Time time) throws SQLException 1796 { 1797 updateObject(columnIndex, time); 1798 } 1799 1800 public void updateTime(String columnName, Time time) throws SQLException 1801 { 1802 updateObject(columnName, time); 1803 } 1804 1805 public void updateTimestamp(int columnIndex, Timestamp timeStamp) throws SQLException 1806 { 1807 updateObject(columnIndex, timeStamp); 1808 } 1809 1810 public void updateTimestamp(String columnName, Timestamp timeStamp) throws SQLException 1811 { 1812 updateObject(columnName, timeStamp); 1813 } 1814 1815 public void updateAsciiStream(int columnIndex, InputStream stream, int length) throws SQLException 1816 { 1817 updateBinaryStream(columnIndex, stream, length); 1818 } 1819 1820 public void updateAsciiStream(String columnName, InputStream stream, int length) throws SQLException 1821 { 1822 updateBinaryStream(columnName, stream, length); 1823 } 1824 1825 public void updateAsciiStream(int columnIndex, InputStream stream, long length) throws SQLException 1826 { 1827 updateBinaryStream(columnIndex, stream, length); 1828 } 1829 1830 public void updateAsciiStream(String columnName, InputStream stream, long length) throws SQLException 1831 { 1832 updateBinaryStream(columnName, stream, length); 1833 } 1834 1835 public void updateAsciiStream(int columnIndex, InputStream stream) throws SQLException 1836 { 1837 updateBinaryStream(columnIndex, stream); 1838 } 1839 1840 public void updateAsciiStream(String columnName, InputStream stream) throws SQLException 1841 { 1842 updateBinaryStream(columnName, stream); 1843 } 1844 1845 public void updateBinaryStream(int columnIndex, InputStream stream, int length) throws SQLException 1846 { 1847 byte[] data = StreamUtil.getStreamAsByteArray(stream, length); 1848 updateObject(columnIndex, new ByteArrayInputStream(data)); 1849 } 1850 1851 public void updateBinaryStream(String columnName, InputStream stream, int length) throws SQLException 1852 { 1853 byte[] data = StreamUtil.getStreamAsByteArray(stream, length); 1854 updateObject(columnName, new ByteArrayInputStream(data)); 1855 } 1856 1857 public void updateBinaryStream(int columnIndex, InputStream stream, long length) throws SQLException 1858 { 1859 updateBinaryStream(columnIndex, stream, (int)length); 1860 } 1861 1862 public void updateBinaryStream(String columnName, InputStream stream, long length) throws SQLException 1863 { 1864 updateBinaryStream(columnName, stream, (int)length); 1865 } 1866 1867 public void updateBinaryStream(int columnIndex, InputStream stream) throws SQLException 1868 { 1869 byte[] data = StreamUtil.getStreamAsByteArray(stream); 1870 updateObject(columnIndex, new ByteArrayInputStream(data)); 1871 } 1872 1873 public void updateBinaryStream(String columnName, InputStream stream) throws SQLException 1874 { 1875 byte[] data = StreamUtil.getStreamAsByteArray(stream); 1876 updateObject(columnName, new ByteArrayInputStream(data)); 1877 } 1878 1879 public void updateCharacterStream(int columnIndex, Reader reader, int length) throws SQLException 1880 { 1881 String data = StreamUtil.getReaderAsString(reader, length); 1882 updateObject(columnIndex, new StringReader(data)); 1883 } 1884 1885 public void updateCharacterStream(String columnName, Reader reader, int length) throws SQLException 1886 { 1887 String data = StreamUtil.getReaderAsString(reader, length); 1888 updateObject(columnName, new StringReader(data)); 1889 } 1890 1891 public void updateCharacterStream(int columnIndex, Reader reader, long length) throws SQLException 1892 { 1893 updateCharacterStream(columnIndex, reader, (int)length); 1894 } 1895 1896 public void updateCharacterStream(String columnName, Reader reader, long length) throws SQLException 1897 { 1898 updateCharacterStream(columnName, reader, (int)length); 1899 } 1900 1901 public void updateCharacterStream(int columnIndex, Reader reader) throws SQLException 1902 { 1903 String data = StreamUtil.getReaderAsString(reader); 1904 updateObject(columnIndex, new StringReader(data)); 1905 } 1906 1907 public void updateCharacterStream(String columnName, Reader reader) throws SQLException 1908 { 1909 String data = StreamUtil.getReaderAsString(reader); 1910 updateObject(columnName, new StringReader(data)); 1911 } 1912 1913 public void updateNCharacterStream(int columnIndex, Reader reader) throws SQLException 1914 { 1915 updateCharacterStream(columnIndex, reader); 1916 } 1917 1918 public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException 1919 { 1920 updateCharacterStream(columnLabel, reader); 1921 } 1922 1923 public void updateNCharacterStream(int columnIndex, Reader reader, long length) throws SQLException 1924 { 1925 updateCharacterStream(columnIndex, reader, length); 1926 } 1927 1928 public void updateNCharacterStream(String columnLabel, Reader reader, long length) throws SQLException 1929 { 1930 updateCharacterStream(columnLabel, reader, length); 1931 } 1932 1933 public void updateRef(int columnIndex, Ref ref) throws SQLException 1934 { 1935 updateObject(columnIndex, ref); 1936 } 1937 1938 public void updateRef(String columnName, Ref ref) throws SQLException 1939 { 1940 updateObject(columnName, ref); 1941 } 1942 1943 public void updateRowId(int columnIndex, RowId rowId) throws SQLException 1944 { 1945 updateObject(columnIndex, rowId); 1946 } 1947 1948 public void updateRowId(String columnName, RowId rowId) throws SQLException 1949 { 1950 updateObject(columnName, rowId); 1951 } 1952 1953 public void updateBlob(int columnIndex, Blob blob) throws SQLException 1954 { 1955 updateObject(columnIndex, blob); 1956 } 1957 1958 public void updateBlob(String columnName, Blob blob) throws SQLException 1959 { 1960 updateObject(columnName, blob); 1961 } 1962 1963 public void updateBlob(int columnIndex, InputStream stream, long length) throws SQLException 1964 { 1965 byte[] data = StreamUtil.getStreamAsByteArray(stream, (int)length); 1966 updateBlob(columnIndex, new MockBlob(data)); 1967 } 1968 1969 public void updateBlob(String columnName, InputStream stream, long length) throws SQLException 1970 { 1971 byte[] data = StreamUtil.getStreamAsByteArray(stream, (int)length); 1972 updateBlob(columnName, new MockBlob(data)); 1973 } 1974 1975 public void updateBlob(int columnIndex, InputStream stream) throws SQLException 1976 { 1977 byte[] data = StreamUtil.getStreamAsByteArray(stream); 1978 updateBlob(columnIndex, new MockBlob(data)); 1979 } 1980 1981 public void updateBlob(String columnName, InputStream stream) throws SQLException 1982 { 1983 byte[] data = StreamUtil.getStreamAsByteArray(stream); 1984 updateBlob(columnName, new MockBlob(data)); 1985 } 1986 1987 public void updateClob(int columnIndex, Clob clob) throws SQLException 1988 { 1989 updateObject(columnIndex, clob); 1990 } 1991 1992 public void updateClob(String columnName, Clob clob) throws SQLException 1993 { 1994 updateObject(columnName, clob); 1995 } 1996 1997 public void updateClob(int columnIndex, Reader reader, long length) throws SQLException 1998 { 1999 String data = StreamUtil.getReaderAsString(reader, (int)length); 2000 updateClob(columnIndex, new MockClob(data)); 2001 } 2002 2003 public void updateClob(String columnName, Reader reader, long length) throws SQLException 2004 { 2005 String data = StreamUtil.getReaderAsString(reader, (int)length); 2006 updateClob(columnName, new MockClob(data)); 2007 } 2008 2009 public void updateClob(int columnIndex, Reader reader) throws SQLException 2010 { 2011 String data = StreamUtil.getReaderAsString(reader); 2012 updateClob(columnIndex, new MockClob(data)); 2013 } 2014 2015 public void updateClob(String columnName, Reader reader) throws SQLException 2016 { 2017 String data = StreamUtil.getReaderAsString(reader); 2018 updateClob(columnName, new MockClob(data)); 2019 } 2020 2021 public void updateNClob(int columnIndex, NClob nClob) throws SQLException 2022 { 2023 updateObject(columnIndex, nClob); 2024 } 2025 2026 public void updateNClob(String columnName, NClob nClob) throws SQLException 2027 { 2028 updateObject(columnName, nClob); 2029 } 2030 2031 public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException 2032 { 2033 String data = StreamUtil.getReaderAsString(reader, (int)length); 2034 updateNClob(columnIndex, new MockNClob(data)); 2035 } 2036 2037 public void updateNClob(String columnName, Reader reader, long length) throws SQLException 2038 { 2039 String data = StreamUtil.getReaderAsString(reader, (int)length); 2040 updateNClob(columnName, new MockNClob(data)); 2041 } 2042 2043 public void updateNClob(int columnIndex, Reader reader) throws SQLException 2044 { 2045 String data = StreamUtil.getReaderAsString(reader); 2046 updateNClob(columnIndex, new MockNClob(data)); 2047 } 2048 2049 public void updateNClob(String columnName, Reader reader) throws SQLException 2050 { 2051 String data = StreamUtil.getReaderAsString(reader); 2052 updateNClob(columnName, new MockNClob(data)); 2053 } 2054 2055 public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException 2056 { 2057 updateObject(columnIndex, xmlObject); 2058 } 2059 2060 public void updateSQLXML(String columnName, SQLXML xmlObject) throws SQLException 2061 { 2062 updateObject(columnName, xmlObject); 2063 } 2064 2065 public void updateArray(int columnIndex, Array array) throws SQLException 2066 { 2067 updateObject(columnIndex, array); 2068 } 2069 2070 public void updateArray(String columnName, Array array) throws SQLException 2071 { 2072 updateObject(columnName, array); 2073 } 2074 2075 public boolean rowUpdated() throws SQLException 2076 { 2077 checkRowBounds(); 2078 return ((Boolean)updatedRows.get(cursor)).booleanValue(); 2079 } 2080 2081 public boolean rowInserted() throws SQLException 2082 { 2083 checkRowBounds(); 2084 return ((Boolean)insertedRows.get(cursor)).booleanValue(); 2085 } 2086 2087 public boolean rowDeleted() throws SQLException 2088 { 2089 checkRowBounds(); 2090 return ((Boolean)deletedRows.get(cursor)).booleanValue(); 2091 } 2092 2093 public void insertRow() throws SQLException 2094 { 2095 if(!isCursorInInsertRow) throw new SQLException("cursor is not in insert row"); 2096 checkResultSetConcurrency(); 2097 insertRow(cursor); 2098 } 2099 2100 public void updateRow() throws SQLException 2101 { 2102 if(isCursorInInsertRow) throw new SQLException("cursor is in insert row"); 2103 if(rowDeleted()) throw new SQLException("row was deleted"); 2104 checkResultSetConcurrency(); 2105 checkRowBounds(); 2106 updateRow(cursor, true); 2107 updatedRows.set(cursor, new Boolean(true)); 2108 } 2109 2110 public void deleteRow() throws SQLException 2111 { 2112 if(isCursorInInsertRow) throw new SQLException("cursor is in insert row"); 2113 checkResultSetConcurrency(); 2114 checkRowBounds(); 2115 deleteRow(cursor); 2116 deletedRows.set(cursor, new Boolean(true)); 2117 } 2118 2119 public void refreshRow() throws SQLException 2120 { 2121 cancelRowUpdates(); 2122 } 2123 2124 public void cancelRowUpdates() throws SQLException 2125 { 2126 if(isCursorInInsertRow) throw new SQLException("cursor is in insert row"); 2127 if(rowDeleted()) throw new SQLException("row was deleted"); 2128 checkRowBounds(); 2129 updateRow(cursor, false); 2130 updatedRows.set(cursor, new Boolean(false)); 2131 } 2132 2133 public void moveToInsertRow() throws SQLException 2134 { 2135 adjustCursorForInsert(); 2136 isCursorInInsertRow = true; 2137 } 2138 2139 public void moveToCurrentRow() throws SQLException 2140 { 2141 isCursorInInsertRow = false; 2142 } 2143 2144 public boolean isWrapperFor(Class iface) throws SQLException 2145 { 2146 return false; 2147 } 2148 2149 public Object unwrap(Class iface) throws SQLException 2150 { 2151 throw new SQLException("No object found for " + iface); 2152 } 2153 2154 private void checkColumnName(String columnName) throws SQLException 2155 { 2156 if(!columnMap.containsKey(columnName)) 2157 { 2158 throw new SQLException("No column " + columnName); 2159 } 2160 } 2161 2162 private void checkColumnBounds(int columnIndex) throws SQLException 2163 { 2164 if(!(columnIndex - 1 < columnNameList.size())) 2165 { 2166 throw new SQLException("Index " + columnIndex + " out of bounds"); 2167 } 2168 } 2169 2170 private void checkRowBounds() throws SQLException 2171 { 2172 if(!isCurrentRowValid()) 2173 { 2174 throw new SQLException("Current row invalid"); 2175 } 2176 } 2177 2178 private boolean isCurrentRowValid() 2179 { 2180 return (cursor < getRowCount()) && (-1 != cursor); 2181 } 2182 2183 private void checkResultSetType() throws SQLException 2184 { 2185 if(resultSetType == ResultSet.TYPE_FORWARD_ONLY) 2186 { 2187 throw new SQLException("ResultSet is TYPE_FORWARD_ONLY"); 2188 } 2189 } 2190 2191 private void checkResultSetConcurrency() throws SQLException 2192 { 2193 if(resultSetConcurrency == ResultSet.CONCUR_READ_ONLY) 2194 { 2195 throw new SQLException("ResultSet is CONCUR_READ_ONLY"); 2196 } 2197 } 2198 2199 private void checkFetchDirectionArguments(int fetchDirection) throws SQLException 2200 { 2201 SQLUtil.checkFetchDirection(fetchDirection); 2202 if(resultSetType == ResultSet.TYPE_FORWARD_ONLY && fetchDirection != ResultSet.FETCH_FORWARD) 2203 { 2204 throw new SQLException("resultSetType is TYPE_FORWARD_ONLY, only FETCH_FORWARD allowed"); 2205 } 2206 } 2207 2208 private void insertRow(int index) 2209 { 2210 Iterator columnNames = columnMapCopy.keySet().iterator(); 2211 while(columnNames.hasNext()) 2212 { 2213 String currentColumnName = (String)columnNames.next(); 2214 List copyColumn = (List)columnMapCopy.get(currentColumnName); 2215 List databaseColumn = (List)columnMap.get(currentColumnName); 2216 List sourceColumn = (List)insertRow.get(currentColumnName); 2217 copyColumn.add(index, ParameterUtil.copyParameter(sourceColumn.get(0))); 2218 databaseColumn.add(index, ParameterUtil.copyParameter(sourceColumn.get(0))); 2219 } 2220 updatedRows.add(index, new Boolean(false)); 2221 deletedRows.add(index, new Boolean(false)); 2222 insertedRows.add(index, new Boolean(true)); 2223 } 2224 2225 private void deleteRow(int index) 2226 { 2227 Iterator columnNames = columnMapCopy.keySet().iterator(); 2228 while(columnNames.hasNext()) 2229 { 2230 String currentColumnName = (String)columnNames.next(); 2231 List copyColumn = (List)columnMapCopy.get(currentColumnName); 2232 List databaseColumn = (List)columnMap.get(currentColumnName); 2233 copyColumn.set(index, null); 2234 databaseColumn.set(index, null); 2235 } 2236 } 2237 2238 private void updateRow(int index, boolean toDatabase) 2239 { 2240 Iterator columnNames = columnMapCopy.keySet().iterator(); 2241 while(columnNames.hasNext()) 2242 { 2243 String currentColumnName = (String)columnNames.next(); 2244 List sourceColumn; 2245 List targetColumn; 2246 if(toDatabase) 2247 { 2248 sourceColumn = (List)columnMapCopy.get(currentColumnName); 2249 targetColumn = (List)columnMap.get(currentColumnName); 2250 } 2251 else 2252 { 2253 sourceColumn = (List)columnMap.get(currentColumnName); 2254 targetColumn = (List)columnMapCopy.get(currentColumnName); 2255 } 2256 targetColumn.set(index, ParameterUtil.copyParameter(sourceColumn.get(index))); 2257 } 2258 } 2259 2260 private void adjustCursorForInsert() 2261 { 2262 if(cursor >= getRowCount()) cursor = getRowCount() - 1; 2263 if(cursor < 0) cursor = 0; 2264 } 2265 2266 private void adjustCursor() 2267 { 2268 if(cursor < 0) cursor = -1; 2269 if(cursor >= getRowCount()) cursor = getRowCount(); 2270 } 2271 2272 private void adjustColumns() 2273 { 2274 int rowCount = 0; 2275 Iterator columns = columnMap.values().iterator(); 2276 while(columns.hasNext()) 2277 { 2278 List nextColumn = (List)columns.next(); 2279 rowCount = Math.max(rowCount, nextColumn.size()); 2280 } 2281 columns = columnMap.values().iterator(); 2282 while(columns.hasNext()) 2283 { 2284 List nextColumn = (List)columns.next(); 2285 CollectionUtil.fillList(nextColumn, rowCount); 2286 } 2287 } 2288 2289 private void adjustFlags() 2290 { 2291 for(int ii = updatedRows.size(); ii < getRowCount(); ii++) 2292 { 2293 updatedRows.add(new Boolean(false)); 2294 } 2295 for(int ii = deletedRows.size(); ii < getRowCount(); ii++) 2296 { 2297 deletedRows.add(new Boolean(false)); 2298 } 2299 for(int ii = insertedRows.size(); ii < getRowCount(); ii++) 2300 { 2301 insertedRows.add(new Boolean(false)); 2302 } 2303 } 2304 2305 private void adjustInsertRow() 2306 { 2307 insertRow = createCaseAwareMap(); 2308 Iterator columns = columnMap.keySet().iterator(); 2309 while(columns.hasNext()) 2310 { 2311 ArrayList list = new ArrayList(1); 2312 list.add(null); 2313 insertRow.put((String)columns.next(), list); 2314 } 2315 } 2316 2317 private void copyColumnMap() 2318 { 2319 columnMapCopy = copyColumnDataMap(columnMap); 2320 } 2321 2322 private String determineValidColumnName() 2323 { 2324 String name = "Column"; 2325 int count = columnNameList.size() + 1; 2326 while(columnMap.containsKey(name + count)) 2327 { 2328 count ++; 2329 } 2330 return name + count; 2331 } 2332 2333 private Map copyColumnDataMap(Map columnMap) 2334 { 2335 Map copy = createCaseAwareMap(); 2336 Iterator columns = columnMap.keySet().iterator(); 2337 while(columns.hasNext()) 2338 { 2339 List copyList = new ArrayList(); 2340 String nextKey = (String)columns.next(); 2341 List nextColumnList = (List)columnMap.get(nextKey); 2342 for(int ii = 0; ii < nextColumnList.size(); ii++) 2343 { 2344 Object copyParameter = ParameterUtil.copyParameter(nextColumnList.get(ii)); 2345 copyList.add(copyParameter); 2346 } 2347 copy.put(nextKey, copyList); 2348 } 2349 return copy; 2350 } 2351 2352 private Map createCaseAwareMap() 2353 { 2354 return new CaseAwareMap(columnsCaseSensitive); 2355 } 2356 2357 private NClob getNClobFromClob(Clob clobValue) throws SQLException 2358 { 2359 return new MockNClob(clobValue.getSubString(1, (int)clobValue.length())); 2360 } 2361 2362 public String toString() 2363 { 2364 StringBuffer buffer = new StringBuffer("ResultSet " + id + ":\n"); 2365 buffer.append("Number of rows: " + getRowCount() + "\n"); 2366 buffer.append("Number of columns: " + getColumnCount() + "\n"); 2367 buffer.append("Column names:\n"); 2368 StringUtil.appendObjectsAsString(buffer, columnNameList); 2369 buffer.append("Data:\n"); 2370 for(int ii = 1; ii <= getRowCount(); ii++) 2371 { 2372 buffer.append("Row number " + ii + ":\n"); 2373 StringUtil.appendObjectsAsString(buffer, getRow(ii)); 2374 } 2375 return buffer.toString(); 2376 } 2377 }