001: package com.mockrunner.mock.jdbc;
002:
003: import java.sql.BatchUpdateException;
004: import java.sql.Connection;
005: import java.sql.ResultSet;
006: import java.sql.SQLException;
007: import java.sql.SQLWarning;
008: import java.sql.Statement;
009: import java.util.ArrayList;
010: import java.util.List;
011:
012: import com.mockrunner.base.NestedApplicationException;
013: import com.mockrunner.jdbc.AbstractResultSetHandler;
014: import com.mockrunner.jdbc.SQLUtil;
015: import com.mockrunner.util.common.ArrayUtil;
016:
017: /**
018: * Mock implementation of <code>Statement</code>.
019: */
020: public class MockStatement implements Statement {
021: private AbstractResultSetHandler resultSetHandler;
022: private ResultSet[] currentResultSets = null;
023: private int[] currentUpdateCounts = null;
024: private int currentResultSetIndex = 0;
025: private int currentUpdateCountIndex = 0;
026: private List batches = new ArrayList();
027: private String cursorName = "";
028: private int querySeconds = 0;
029: private int maxRows = 0;
030: private int maxFieldSize = 0;
031: private int fetchDirection = ResultSet.FETCH_FORWARD;
032: private int fetchSize = 0;
033: private int resultSetType = ResultSet.TYPE_FORWARD_ONLY;
034: private int resultSetConcurrency = ResultSet.CONCUR_READ_ONLY;
035: private int resultSetHoldability = ResultSet.HOLD_CURSORS_OVER_COMMIT;
036: private MockResultSet lastGeneratedKeys = null;
037: private boolean closed = false;
038: private boolean poolable = false;
039: private Connection connection;
040:
041: public MockStatement(Connection connection) {
042: this .connection = connection;
043: this .resultSetType = ResultSet.TYPE_FORWARD_ONLY;
044: this .resultSetConcurrency = ResultSet.CONCUR_READ_ONLY;
045: try {
046: this .resultSetHoldability = connection.getMetaData()
047: .getResultSetHoldability();
048: } catch (SQLException exc) {
049: throw new NestedApplicationException(exc);
050: }
051: }
052:
053: public MockStatement(Connection connection, int resultSetType,
054: int resultSetConcurrency) {
055: this .connection = connection;
056: this .resultSetType = resultSetType;
057: this .resultSetConcurrency = resultSetConcurrency;
058: try {
059: this .resultSetHoldability = connection.getMetaData()
060: .getResultSetHoldability();
061: } catch (SQLException exc) {
062: throw new NestedApplicationException(exc);
063: }
064: }
065:
066: public MockStatement(Connection connection, int resultSetType,
067: int resultSetConcurrency, int resultSetHoldability) {
068: this .connection = connection;
069: this .resultSetType = resultSetType;
070: this .resultSetConcurrency = resultSetConcurrency;
071: this .resultSetHoldability = resultSetHoldability;
072: }
073:
074: public boolean isClosed() {
075: return closed;
076: }
077:
078: public void setResultSetHandler(
079: AbstractResultSetHandler resultSetHandler) {
080: this .resultSetHandler = resultSetHandler;
081: }
082:
083: protected void setResultSets(ResultSet[] resultSets) {
084: closeCurrentResultSets();
085: this .currentUpdateCounts = null;
086: this .currentResultSets = resultSets;
087: this .currentResultSetIndex = 0;
088: this .currentUpdateCountIndex = 0;
089: }
090:
091: protected void setUpdateCounts(int[] updateCounts) {
092: closeCurrentResultSets();
093: this .currentResultSets = null;
094: this .currentUpdateCounts = updateCounts;
095: this .currentResultSetIndex = 0;
096: this .currentUpdateCountIndex = 0;
097: }
098:
099: public String getCursorName() {
100: return cursorName;
101: }
102:
103: public ResultSet executeQuery(String sql) throws SQLException {
104: SQLException exception = resultSetHandler.getSQLException(sql);
105: if (null != exception) {
106: throw exception;
107: }
108: resultSetHandler.addExecutedStatement(sql);
109: if (resultSetHandler.hasMultipleResultSets(sql)) {
110: MockResultSet[] results = resultSetHandler
111: .getResultSets(sql);
112: if (null != results)
113: return cloneAndSetMultipleResultSets(results);
114: } else {
115: MockResultSet result = resultSetHandler.getResultSet(sql);
116: if (null != result)
117: return cloneAndSetSingleResultSet(result);
118: }
119: if (resultSetHandler.hasMultipleGlobalResultSets()) {
120: return cloneAndSetMultipleResultSets(resultSetHandler
121: .getGlobalResultSets());
122: }
123: return cloneAndSetSingleResultSet(resultSetHandler
124: .getGlobalResultSet());
125: }
126:
127: private MockResultSet cloneAndSetSingleResultSet(
128: MockResultSet result) {
129: result = cloneResultSet(result);
130: if (null != result) {
131: resultSetHandler.addReturnedResultSet(result);
132: }
133: setResultSets(new MockResultSet[] { result });
134: setLastGeneratedKeysResultSet(null);
135: return result;
136: }
137:
138: private MockResultSet cloneAndSetMultipleResultSets(
139: MockResultSet[] results) {
140: results = cloneResultSets(results);
141: if (null != results) {
142: resultSetHandler.addReturnedResultSets(results);
143: }
144: setResultSets(results);
145: setLastGeneratedKeysResultSet(null);
146: if (null != results && results.length > 0) {
147: return results[0];
148: }
149: return null;
150: }
151:
152: private void closeCurrentResultSets() {
153: if (null != currentResultSets) {
154: for (int ii = 0; ii < currentResultSets.length; ii++) {
155: try {
156: if (null != currentResultSets[ii]) {
157: currentResultSets[ii].close();
158: }
159: } catch (SQLException exc) {
160: throw new NestedApplicationException(exc);
161: }
162: }
163: }
164: }
165:
166: public int executeUpdate(String sql) throws SQLException {
167: SQLException exception = resultSetHandler.getSQLException(sql);
168: if (null != exception) {
169: throw exception;
170: }
171: resultSetHandler.addExecutedStatement(sql);
172: if (resultSetHandler.hasMultipleUpdateCounts(sql)) {
173: Integer[] returnValues = resultSetHandler
174: .getUpdateCounts(sql);
175: if (null != returnValues) {
176: return setMultipleUpdateCounts((int[]) ArrayUtil
177: .convertToPrimitiveArray(returnValues));
178: }
179: } else {
180: Integer returnValue = resultSetHandler.getUpdateCount(sql);
181: if (null != returnValue) {
182: return setSingleUpdateCount(returnValue.intValue());
183: }
184: }
185: if (resultSetHandler.hasMultipleGlobalUpdateCounts()) {
186: return setMultipleUpdateCounts(resultSetHandler
187: .getGlobalUpdateCounts());
188: }
189: return setSingleUpdateCount(resultSetHandler
190: .getGlobalUpdateCount());
191: }
192:
193: private int setSingleUpdateCount(int updateCount) {
194: setUpdateCounts(new int[] { updateCount });
195: setLastGeneratedKeysResultSet(null);
196: return updateCount;
197: }
198:
199: private int setMultipleUpdateCounts(int[] updateCounts) {
200: setUpdateCounts(updateCounts);
201: setLastGeneratedKeysResultSet(null);
202: if (null != updateCounts && updateCounts.length > 0) {
203: return updateCounts[0];
204: }
205: return 0;
206: }
207:
208: public boolean execute(String sql) throws SQLException {
209: boolean callExecuteQuery = isQuery(sql);
210: if (callExecuteQuery) {
211: executeQuery(sql);
212: } else {
213: executeUpdate(sql);
214: }
215: return callExecuteQuery;
216: }
217:
218: public int[] executeBatch() throws SQLException {
219: int[] results = new int[batches.size()];
220: SQLException exception = null;
221: for (int ii = 0; ii < results.length; ii++) {
222: String nextSQL = (String) batches.get(ii);
223: if (isQuery(nextSQL)) {
224: exception = prepareFailedResult(
225: results,
226: ii,
227: "SQL "
228: + batches.get(ii)
229: + " in the list of batches returned a ResultSet.",
230: null);
231: } else {
232: try {
233: results[ii] = executeUpdate(nextSQL);
234: } catch (SQLException exc) {
235: exception = prepareFailedResult(results, ii, null,
236: exc);
237: }
238: }
239: if (null != exception
240: && !resultSetHandler
241: .getContinueProcessingOnBatchFailure()) {
242: throw exception;
243: }
244: }
245: if (null != exception) {
246: throw new BatchUpdateException(exception.getMessage(),
247: exception.getSQLState(), exception.getErrorCode(),
248: results);
249: }
250: return results;
251: }
252:
253: protected SQLException prepareFailedResult(int[] actualResults,
254: int index, String message, SQLException caughtException) {
255: actualResults[index] = -3;
256: if (caughtException instanceof BatchUpdateException) {
257: return caughtException;
258: } else {
259: int[] partialResults = (int[]) ArrayUtil.truncateArray(
260: actualResults, index);
261: if (null == caughtException) {
262: return new BatchUpdateException(message, partialResults);
263: } else {
264: return new BatchUpdateException(caughtException
265: .getMessage(), caughtException.getSQLState(),
266: caughtException.getErrorCode(), partialResults);
267: }
268: }
269: }
270:
271: public int executeUpdate(String sql, int autoGeneratedKeys)
272: throws SQLException {
273: int updateCount = executeUpdate(sql);
274: setGeneratedKeysResultSet(sql, autoGeneratedKeys);
275: return updateCount;
276: }
277:
278: public int executeUpdate(String sql, int[] columnIndexes)
279: throws SQLException {
280: return executeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
281: }
282:
283: public int executeUpdate(String sql, String[] columnNames)
284: throws SQLException {
285: return executeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
286: }
287:
288: public boolean execute(String sql, int autoGeneratedKeys)
289: throws SQLException {
290: boolean isQuery = execute(sql);
291: setGeneratedKeysResultSet(sql, autoGeneratedKeys);
292: return isQuery;
293: }
294:
295: public boolean execute(String sql, int[] columnIndexes)
296: throws SQLException {
297: return execute(sql, Statement.RETURN_GENERATED_KEYS);
298: }
299:
300: public boolean execute(String sql, String[] columnNames)
301: throws SQLException {
302: return execute(sql, Statement.RETURN_GENERATED_KEYS);
303: }
304:
305: private void setGeneratedKeysResultSet(String sql,
306: int autoGeneratedKeys) throws SQLException {
307: if (Statement.RETURN_GENERATED_KEYS != autoGeneratedKeys
308: && Statement.NO_GENERATED_KEYS != autoGeneratedKeys) {
309: throw new SQLException(
310: "autoGeneratedKeys must be either Statement.RETURN_GENERATED_KEYS or Statement.NO_GENERATED_KEYS");
311: }
312: if (Statement.RETURN_GENERATED_KEYS == autoGeneratedKeys) {
313: setLastGeneratedKeysResultSet(determineGeneratedKeysResultSet(sql));
314: } else {
315: setLastGeneratedKeysResultSet(null);
316: }
317: }
318:
319: protected void setLastGeneratedKeysResultSet(
320: MockResultSet generatedKeys) {
321: lastGeneratedKeys = generatedKeys;
322: }
323:
324: protected MockResultSet determineGeneratedKeysResultSet(String sql) {
325: MockResultSet generatedKeys = resultSetHandler
326: .getGeneratedKeys(sql);
327: if (null != generatedKeys)
328: return generatedKeys;
329: return resultSetHandler.getGlobalGeneratedKeys();
330: }
331:
332: public void close() throws SQLException {
333: closed = true;
334: }
335:
336: public int getMaxFieldSize() throws SQLException {
337: return maxFieldSize;
338: }
339:
340: public void setMaxFieldSize(int maxFieldSize) throws SQLException {
341: this .maxFieldSize = maxFieldSize;
342: }
343:
344: public int getMaxRows() throws SQLException {
345: return maxRows;
346: }
347:
348: public void setMaxRows(int maxRows) throws SQLException {
349: this .maxRows = maxRows;
350: }
351:
352: public void setEscapeProcessing(boolean enable) throws SQLException {
353:
354: }
355:
356: public int getQueryTimeout() throws SQLException {
357: return querySeconds;
358: }
359:
360: public void setQueryTimeout(int querySeconds) throws SQLException {
361: this .querySeconds = querySeconds;
362: }
363:
364: public void cancel() throws SQLException {
365:
366: }
367:
368: public SQLWarning getWarnings() throws SQLException {
369: return null;
370: }
371:
372: public void clearWarnings() throws SQLException {
373:
374: }
375:
376: public void setCursorName(String cursorName) throws SQLException {
377: this .cursorName = cursorName;
378: }
379:
380: protected boolean isQuery(String sql) {
381: boolean isQuery;
382: Boolean returnsResultSet = resultSetHandler
383: .getReturnsResultSet(sql);
384: if (null != returnsResultSet) {
385: isQuery = returnsResultSet.booleanValue();
386: } else {
387: isQuery = SQLUtil.isSelect(sql);
388: }
389: return isQuery;
390: }
391:
392: public ResultSet getResultSet() throws SQLException {
393: if (null == currentResultSets)
394: return null;
395: if (currentResultSetIndex >= currentResultSets.length)
396: return null;
397: return currentResultSets[currentResultSetIndex];
398: }
399:
400: public int getUpdateCount() throws SQLException {
401: if (null == currentUpdateCounts)
402: return -1;
403: if (currentUpdateCountIndex >= currentUpdateCounts.length)
404: return -1;
405: return currentUpdateCounts[currentUpdateCountIndex];
406: }
407:
408: public boolean getMoreResults(int current) throws SQLException {
409: return getMoreResults(current != Statement.KEEP_CURRENT_RESULT);
410: }
411:
412: public boolean getMoreResults() throws SQLException {
413: return getMoreResults(true);
414: }
415:
416: private boolean getMoreResults(boolean doCloseCurrentResult)
417: throws SQLException {
418: if (null != currentResultSets) {
419: if (currentResultSetIndex < currentResultSets.length) {
420: if (null != currentResultSets[currentResultSetIndex]
421: && doCloseCurrentResult) {
422: currentResultSets[currentResultSetIndex].close();
423: }
424: currentResultSetIndex++;
425: }
426: return (currentResultSetIndex < currentResultSets.length);
427: } else if (null != currentUpdateCounts) {
428: if (currentUpdateCountIndex < currentUpdateCounts.length) {
429: currentUpdateCountIndex++;
430: }
431: }
432: return false;
433: }
434:
435: public void setFetchDirection(int fetchDirection)
436: throws SQLException {
437: this .fetchDirection = fetchDirection;
438: }
439:
440: public int getFetchDirection() throws SQLException {
441: return fetchDirection;
442: }
443:
444: public void setFetchSize(int fetchSize) throws SQLException {
445: this .fetchSize = fetchSize;
446: }
447:
448: public int getFetchSize() throws SQLException {
449: return fetchSize;
450: }
451:
452: public void addBatch(String sql) throws SQLException {
453: batches.add(sql);
454: }
455:
456: public void clearBatch() throws SQLException {
457: batches.clear();
458: }
459:
460: public Connection getConnection() throws SQLException {
461: return connection;
462: }
463:
464: public ResultSet getGeneratedKeys() throws SQLException {
465: if (null == lastGeneratedKeys) {
466: MockResultSet resultSet = new MockResultSet(
467: "Last statement did not generate any keys");
468: resultSet.setStatement(this );
469: return resultSet;
470: }
471: return cloneResultSet(lastGeneratedKeys);
472: }
473:
474: public int getResultSetType() throws SQLException {
475: return resultSetType;
476: }
477:
478: public int getResultSetConcurrency() throws SQLException {
479: return resultSetConcurrency;
480: }
481:
482: public int getResultSetHoldability() throws SQLException {
483: return resultSetHoldability;
484: }
485:
486: public boolean isPoolable() throws SQLException {
487: return poolable;
488: }
489:
490: public void setPoolable(boolean poolable) throws SQLException {
491: this .poolable = poolable;
492: }
493:
494: public boolean isWrapperFor(Class iface) throws SQLException {
495: return false;
496: }
497:
498: public Object unwrap(Class iface) throws SQLException {
499: throw new SQLException("No object found for " + iface);
500: }
501:
502: protected MockResultSet cloneResultSet(MockResultSet resultSet) {
503: if (null == resultSet)
504: return null;
505: MockResultSet clone = (MockResultSet) resultSet.clone();
506: clone.setStatement(this );
507: return clone;
508: }
509:
510: protected MockResultSet[] cloneResultSets(MockResultSet[] resultSets) {
511: if (null == resultSets)
512: return null;
513: MockResultSet[] clonedResultsSets = new MockResultSet[resultSets.length];
514: for (int ii = 0; ii < resultSets.length; ii++) {
515: if (null != resultSets[ii]) {
516: clonedResultsSets[ii] = (MockResultSet) resultSets[ii]
517: .clone();
518: clonedResultsSets[ii].setStatement(this);
519: }
520: }
521: return clonedResultsSets;
522: }
523: }
|