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 }