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