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 }