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