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.math.BigDecimal; 008 import java.net.URL; 009 import java.sql.Array; 010 import java.sql.BatchUpdateException; 011 import java.sql.Blob; 012 import java.sql.Clob; 013 import java.sql.Connection; 014 import java.sql.Date; 015 import java.sql.NClob; 016 import java.sql.ParameterMetaData; 017 import java.sql.PreparedStatement; 018 import java.sql.Ref; 019 import java.sql.ResultSet; 020 import java.sql.ResultSetMetaData; 021 import java.sql.RowId; 022 import java.sql.SQLException; 023 import java.sql.SQLXML; 024 import java.sql.Time; 025 import java.sql.Timestamp; 026 import java.util.ArrayList; 027 import java.util.Calendar; 028 import java.util.Collections; 029 import java.util.HashMap; 030 import java.util.Iterator; 031 import java.util.List; 032 import java.util.Map; 033 034 import com.mockrunner.jdbc.AbstractParameterResultSetHandler; 035 import com.mockrunner.jdbc.ParameterUtil; 036 import com.mockrunner.util.common.ArrayUtil; 037 import com.mockrunner.util.common.StreamUtil; 038 import com.mockrunner.util.common.StringUtil; 039 040 /** 041 * Mock implementation of <code>PreparedStatement</code>. 042 */ 043 public class MockPreparedStatement extends MockStatement implements PreparedStatement 044 { 045 private AbstractParameterResultSetHandler resultSetHandler; 046 private Map paramObjects = new HashMap(); 047 private List batchParameters = new ArrayList(); 048 private String sql; 049 private MockParameterMetaData parameterMetaData; 050 private boolean returnGeneratedKeys = false; 051 052 public MockPreparedStatement(Connection connection, String sql) 053 { 054 this(connection, sql, false); 055 } 056 057 public MockPreparedStatement(Connection connection, String sql, boolean returnGeneratedKeys) 058 { 059 super(connection); 060 this.sql = sql; 061 this.returnGeneratedKeys = returnGeneratedKeys; 062 prepareParameterMetaData(); 063 } 064 065 public MockPreparedStatement(Connection connection, String sql, int resultSetType, int resultSetConcurrency) 066 { 067 super(connection, resultSetType, resultSetConcurrency); 068 this.sql = sql; 069 prepareParameterMetaData(); 070 } 071 072 public MockPreparedStatement(Connection connection, String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) 073 { 074 super(connection, resultSetType, resultSetConcurrency, resultSetHoldability); 075 this.sql = sql; 076 prepareParameterMetaData(); 077 } 078 079 public void setPreparedStatementResultSetHandler(AbstractParameterResultSetHandler resultSetHandler) 080 { 081 super.setResultSetHandler(resultSetHandler); 082 this.resultSetHandler = resultSetHandler; 083 } 084 085 private void prepareParameterMetaData() 086 { 087 int number = StringUtil.countMatches(sql, "?"); 088 parameterMetaData = new MockParameterMetaData(); 089 parameterMetaData.setParameterCount(number); 090 } 091 092 public String getSQL() 093 { 094 return sql; 095 } 096 097 public Map getIndexedParameterMap() 098 { 099 return Collections.unmodifiableMap(paramObjects); 100 } 101 102 public Map getParameterMap() 103 { 104 return getIndexedParameterMap(); 105 } 106 107 public Object getParameter(int index) 108 { 109 return paramObjects.get(new Integer(index)); 110 } 111 112 public void setObject(int index, Object object) throws SQLException 113 { 114 paramObjects.put(new Integer(index), object); 115 } 116 117 public void setObject(int parameterIndex, Object object, int targetSqlType, int scale) throws SQLException 118 { 119 setObject(parameterIndex, object); 120 } 121 122 public void setObject(int parameterIndex, Object object, int targetSqlType) throws SQLException 123 { 124 setObject(parameterIndex, object); 125 } 126 127 public void addBatch() throws SQLException 128 { 129 batchParameters.add(new HashMap(paramObjects)); 130 } 131 132 public void clearParameters() throws SQLException 133 { 134 paramObjects.clear(); 135 } 136 137 public boolean execute() throws SQLException 138 { 139 boolean callExecuteQuery = isQuery(getSQL()); 140 if(callExecuteQuery) 141 { 142 executeQuery(); 143 } 144 else 145 { 146 executeUpdate(); 147 } 148 return callExecuteQuery; 149 } 150 151 public ResultSet executeQuery() throws SQLException 152 { 153 return executeQuery(paramObjects); 154 } 155 156 protected ResultSet executeQuery(Map params) throws SQLException 157 { 158 SQLException exception = resultSetHandler.getSQLException(sql, params); 159 if(null != exception) 160 { 161 throw exception; 162 } 163 exception = resultSetHandler.getSQLException(sql); 164 if(null != exception) 165 { 166 throw exception; 167 } 168 resultSetHandler.addParameterMapForExecutedStatement(getSQL(), getParameterMapCopy(params)); 169 if(resultSetHandler.hasMultipleResultSets(getSQL(), params)) 170 { 171 MockResultSet[] results = resultSetHandler.getResultSets(getSQL(), params); 172 if(null != results) 173 { 174 resultSetHandler.addExecutedStatement(getSQL()); 175 return cloneAndSetMultipleResultSets(results, params); 176 } 177 } 178 else 179 { 180 MockResultSet result = resultSetHandler.getResultSet(getSQL(), params); 181 if(null != result) 182 { 183 resultSetHandler.addExecutedStatement(getSQL()); 184 return cloneAndSetSingleResultSet(result, params); 185 } 186 } 187 ResultSet superResultSet = super.executeQuery(getSQL()); 188 setGeneratedKeysResultSet(sql, params); 189 return superResultSet; 190 } 191 192 private MockResultSet cloneAndSetSingleResultSet(MockResultSet result, Map params) 193 { 194 result = cloneResultSet(result); 195 if(null != result) 196 { 197 resultSetHandler.addReturnedResultSet(result); 198 } 199 setResultSets(new MockResultSet[] {result}); 200 setGeneratedKeysResultSet(sql, params); 201 return result; 202 } 203 204 private MockResultSet cloneAndSetMultipleResultSets(MockResultSet[] results, Map params) 205 { 206 results = cloneResultSets(results); 207 if(null != results) 208 { 209 resultSetHandler.addReturnedResultSets(results); 210 } 211 setResultSets(results); 212 setGeneratedKeysResultSet(sql, params); 213 if(null != results && results.length > 0) 214 { 215 return results[0]; 216 } 217 return null; 218 } 219 220 public int executeUpdate() throws SQLException 221 { 222 return executeUpdate(paramObjects); 223 } 224 225 protected int executeUpdate(Map params) throws SQLException 226 { 227 SQLException exception = resultSetHandler.getSQLException(sql, params); 228 if(null != exception) 229 { 230 throw exception; 231 } 232 exception = resultSetHandler.getSQLException(sql); 233 if(null != exception) 234 { 235 throw exception; 236 } 237 resultSetHandler.addParameterMapForExecutedStatement(getSQL(), getParameterMapCopy(params)); 238 if(resultSetHandler.hasMultipleUpdateCounts(getSQL(), params)) 239 { 240 Integer[] updateCounts = resultSetHandler.getUpdateCounts(getSQL(), params); 241 if(null != updateCounts) 242 { 243 resultSetHandler.addExecutedStatement(getSQL()); 244 return setMultipleUpdateCounts((int[])ArrayUtil.convertToPrimitiveArray(updateCounts), params); 245 } 246 } 247 else 248 { 249 Integer updateCount = resultSetHandler.getUpdateCount(getSQL(), params); 250 if(null != updateCount) 251 { 252 resultSetHandler.addExecutedStatement(getSQL()); 253 return setSingleUpdateCount(updateCount.intValue(), params); 254 } 255 } 256 int superUpdateCount = super.executeUpdate(getSQL()); 257 setGeneratedKeysResultSet(sql, params); 258 return superUpdateCount; 259 } 260 261 private int setSingleUpdateCount(int updateCount, Map params) 262 { 263 setUpdateCounts(new int[] {updateCount}); 264 setGeneratedKeysResultSet(sql, params); 265 return updateCount; 266 } 267 268 private int setMultipleUpdateCounts(int[] updateCounts, Map params) 269 { 270 setUpdateCounts(updateCounts); 271 setGeneratedKeysResultSet(sql, params); 272 if(null != updateCounts && updateCounts.length > 0) 273 { 274 return updateCounts[0]; 275 } 276 return 0; 277 } 278 279 public int[] executeBatch() throws SQLException 280 { 281 return executeBatch(this.batchParameters); 282 } 283 284 protected int[] executeBatch(List batchParams) throws SQLException 285 { 286 int[] results = new int[batchParams.size()]; 287 SQLException exception = null; 288 for(int ii = 0; ii < results.length; ii++) 289 { 290 if(isQuery(getSQL())) 291 { 292 exception = prepareFailedResult(results, ii, "SQL " + getSQL() + " in the list of batches returned a ResultSet.", null); 293 } 294 else 295 { 296 try 297 { 298 Map currentParameters = (Map)batchParams.get(ii); 299 results[ii] = executeUpdate(currentParameters); 300 } 301 catch(SQLException exc) 302 { 303 exception = prepareFailedResult(results, ii, null, exc); 304 } 305 } 306 if(null != exception && !resultSetHandler.getContinueProcessingOnBatchFailure()) 307 { 308 throw exception; 309 } 310 } 311 if(null != exception) 312 { 313 throw new BatchUpdateException(exception.getMessage(), exception.getSQLState(), exception.getErrorCode(), results); 314 } 315 return results; 316 } 317 318 private void setGeneratedKeysResultSet(String sql, Map params) 319 { 320 MockResultSet generatedKeys = resultSetHandler.getGeneratedKeys(sql, params); 321 if(returnGeneratedKeys) 322 { 323 if(null != generatedKeys) 324 { 325 setLastGeneratedKeysResultSet(generatedKeys); 326 } 327 else 328 { 329 setLastGeneratedKeysResultSet(determineGeneratedKeysResultSet(sql)); 330 } 331 } 332 else 333 { 334 setLastGeneratedKeysResultSet(null); 335 } 336 } 337 338 public ResultSetMetaData getMetaData() throws SQLException 339 { 340 return new MockResultSetMetaData(); 341 } 342 343 public ParameterMetaData getParameterMetaData() throws SQLException 344 { 345 return parameterMetaData; 346 } 347 348 public void setArray(int parameterIndex, Array array) throws SQLException 349 { 350 setObject(parameterIndex, array); 351 } 352 353 public void setAsciiStream(int parameterIndex, InputStream stream) throws SQLException 354 { 355 setBinaryStream(parameterIndex, stream); 356 } 357 358 public void setAsciiStream(int parameterIndex, InputStream stream, int length) throws SQLException 359 { 360 setBinaryStream(parameterIndex, stream, length); 361 } 362 363 public void setAsciiStream(int parameterIndex, InputStream stream, long length) throws SQLException 364 { 365 setBinaryStream(parameterIndex, stream, length); 366 } 367 368 public void setBinaryStream(int parameterIndex, InputStream stream) throws SQLException 369 { 370 byte[] data = StreamUtil.getStreamAsByteArray(stream); 371 setObject(parameterIndex, new ByteArrayInputStream(data)); 372 } 373 374 public void setBinaryStream(int parameterIndex, InputStream stream, int length) throws SQLException 375 { 376 byte[] data = StreamUtil.getStreamAsByteArray(stream, length); 377 setObject(parameterIndex, new ByteArrayInputStream(data)); 378 } 379 380 public void setBinaryStream(int parameterIndex, InputStream stream, long length) throws SQLException 381 { 382 setBinaryStream(parameterIndex, stream, (int)length); 383 } 384 385 public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException 386 { 387 String data = StreamUtil.getReaderAsString(reader); 388 setObject(parameterIndex, new StringReader(data)); 389 } 390 391 public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException 392 { 393 String data = StreamUtil.getReaderAsString(reader, (int)length); 394 setObject(parameterIndex, new StringReader(data)); 395 } 396 397 public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException 398 { 399 setCharacterStream(parameterIndex, reader, (int)length); 400 } 401 402 public void setNCharacterStream(int parameterIndex, Reader reader) throws SQLException 403 { 404 setCharacterStream(parameterIndex, reader); 405 } 406 407 public void setNCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException 408 { 409 setCharacterStream(parameterIndex, reader, length); 410 } 411 412 public void setBigDecimal(int parameterIndex, BigDecimal bigDecimal) throws SQLException 413 { 414 setObject(parameterIndex, bigDecimal); 415 } 416 417 public void setBlob(int parameterIndex, Blob blob) throws SQLException 418 { 419 setObject(parameterIndex, blob); 420 } 421 422 public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException 423 { 424 byte[] data = StreamUtil.getStreamAsByteArray(inputStream); 425 setBlob(parameterIndex, new MockBlob(data)); 426 } 427 428 public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException 429 { 430 byte[] data = StreamUtil.getStreamAsByteArray(inputStream, (int)length); 431 setBlob(parameterIndex, new MockBlob(data)); 432 } 433 434 public void setBoolean(int parameterIndex, boolean bool) throws SQLException 435 { 436 setObject(parameterIndex, new Boolean(bool)); 437 } 438 439 public void setByte(int parameterIndex, byte byteValue) throws SQLException 440 { 441 setObject(parameterIndex, new Byte(byteValue)); 442 } 443 444 public void setBytes(int parameterIndex, byte[] byteArray) throws SQLException 445 { 446 setObject(parameterIndex, byteArray); 447 } 448 449 public void setClob(int parameterIndex, Clob clob) throws SQLException 450 { 451 setObject(parameterIndex, clob); 452 } 453 454 public void setClob(int parameterIndex, Reader reader) throws SQLException 455 { 456 String data = StreamUtil.getReaderAsString(reader); 457 setClob(parameterIndex, new MockClob(data)); 458 } 459 460 public void setClob(int parameterIndex, Reader reader, long length) throws SQLException 461 { 462 String data = StreamUtil.getReaderAsString(reader, (int)length); 463 setClob(parameterIndex, new MockClob(data)); 464 } 465 466 public void setNClob(int parameterIndex, NClob nClob) throws SQLException 467 { 468 setObject(parameterIndex, nClob); 469 } 470 471 public void setNClob(int parameterIndex, Reader reader) throws SQLException 472 { 473 String data = StreamUtil.getReaderAsString(reader); 474 setNClob(parameterIndex, new MockNClob(data)); 475 } 476 477 public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException 478 { 479 String data = StreamUtil.getReaderAsString(reader, (int)length); 480 setNClob(parameterIndex, new MockNClob(data)); 481 } 482 483 public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException 484 { 485 setObject(parameterIndex, xmlObject); 486 } 487 488 public void setDate(int parameterIndex, Date date, Calendar calendar) throws SQLException 489 { 490 setObject(parameterIndex, date); 491 } 492 493 public void setDate(int parameterIndex, Date date) throws SQLException 494 { 495 setObject(parameterIndex, date); 496 } 497 498 public void setDouble(int parameterIndex, double doubleValue) throws SQLException 499 { 500 setObject(parameterIndex, new Double(doubleValue)); 501 } 502 503 public void setFloat(int parameterIndex, float floatValue) throws SQLException 504 { 505 setObject(parameterIndex, new Float(floatValue)); 506 } 507 508 public void setInt(int parameterIndex, int intValue) throws SQLException 509 { 510 setObject(parameterIndex, new Integer(intValue)); 511 } 512 513 public void setLong(int parameterIndex, long longValue) throws SQLException 514 { 515 setObject(parameterIndex, new Long(longValue)); 516 } 517 518 public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException 519 { 520 setObject(parameterIndex, null); 521 } 522 523 public void setNull(int parameterIndex, int sqlType) throws SQLException 524 { 525 setObject(parameterIndex, null); 526 } 527 528 public void setRef(int parameterIndex, Ref ref) throws SQLException 529 { 530 setObject(parameterIndex, ref); 531 } 532 533 public void setRowId(int parameterIndex, RowId rowId) throws SQLException 534 { 535 setObject(parameterIndex, rowId); 536 } 537 538 public void setShort(int parameterIndex, short shortValue) throws SQLException 539 { 540 setObject(parameterIndex, new Short(shortValue)); 541 } 542 543 public void setString(int parameterIndex, String string) throws SQLException 544 { 545 setObject(parameterIndex, string); 546 } 547 548 public void setNString(int parameterIndex, String string) throws SQLException 549 { 550 setObject(parameterIndex, string); 551 } 552 553 public void setTime(int parameterIndex, Time time, Calendar calendar) throws SQLException 554 { 555 setObject(parameterIndex, time); 556 } 557 558 public void setTime(int parameterIndex, Time time) throws SQLException 559 { 560 setObject(parameterIndex, time); 561 } 562 563 public void setTimestamp(int parameterIndex, Timestamp timeStamp, Calendar cal) throws SQLException 564 { 565 setObject(parameterIndex, timeStamp); 566 } 567 568 public void setTimestamp(int parameterIndex, Timestamp timeStamp) throws SQLException 569 { 570 setObject(parameterIndex, timeStamp); 571 } 572 573 public void setUnicodeStream(int parameterIndex, InputStream stream, int length) throws SQLException 574 { 575 setObject(parameterIndex, stream); 576 } 577 578 public void setURL(int parameterIndex, URL url) throws SQLException 579 { 580 setObject(parameterIndex, url); 581 } 582 583 private Map getParameterMapCopy(Map actualParameters) 584 { 585 Map copyParameters = new HashMap(); 586 Iterator keys = actualParameters.keySet().iterator(); 587 while(keys.hasNext()) 588 { 589 Object key = keys.next(); 590 Object actualParameter = actualParameters.get(key); 591 Object copyParameter = ParameterUtil.copyParameter(actualParameter); 592 copyParameters.put(key, copyParameter); 593 } 594 return copyParameters; 595 } 596 }