001: /*
002: * Copyright 2004 Clinton Begin
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package com.ibatis.sqlmap.engine.execution;
017:
018: import com.ibatis.sqlmap.engine.mapping.parameter.BasicParameterMapping;
019: import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMap;
020: import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMapping;
021: import com.ibatis.sqlmap.engine.mapping.result.ResultMap;
022: import com.ibatis.sqlmap.engine.mapping.result.ResultObjectFactoryUtil;
023: import com.ibatis.sqlmap.engine.mapping.statement.MappedStatement;
024: import com.ibatis.sqlmap.engine.mapping.statement.RowHandlerCallback;
025: import com.ibatis.sqlmap.engine.scope.ErrorContext;
026: import com.ibatis.sqlmap.engine.scope.RequestScope;
027: import com.ibatis.sqlmap.engine.scope.SessionScope;
028: import com.ibatis.sqlmap.engine.impl.ExtendedSqlMapClient;
029: import com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate;
030: import com.ibatis.sqlmap.engine.mapping.statement.DefaultRowHandler;
031:
032: import java.sql.*;
033: import java.util.ArrayList;
034: import java.util.List;
035:
036: /**
037: * Class responsible for executing the SQL
038: */
039: public class SqlExecutor {
040:
041: //
042: // Constants
043: //
044: /**
045: * Constant to let us know not to skip anything
046: */
047: public static final int NO_SKIPPED_RESULTS = 0;
048: /**
049: * Constant to let us know to include all records
050: */
051: public static final int NO_MAXIMUM_RESULTS = -999999;
052:
053: //
054: // Public Methods
055: //
056:
057: /**
058: * Execute an update
059: *
060: * @param request - the request scope
061: * @param conn - the database connection
062: * @param sql - the sql statement to execute
063: * @param parameters - the parameters for the sql statement
064: * @return - the number of records changed
065: * @throws SQLException - if the update fails
066: */
067: public int executeUpdate(RequestScope request, Connection conn,
068: String sql, Object[] parameters) throws SQLException {
069: ErrorContext errorContext = request.getErrorContext();
070: errorContext.setActivity("executing update");
071: errorContext.setObjectId(sql);
072: PreparedStatement ps = null;
073: setupResultObjectFactory(request);
074: int rows = 0;
075: try {
076: errorContext
077: .setMoreInfo("Check the SQL Statement (preparation failed).");
078: ps = prepareStatement(request.getSession(), conn, sql);
079: setStatementTimeout(request.getStatement(), ps);
080: errorContext
081: .setMoreInfo("Check the parameters (set parameters failed).");
082: request.getParameterMap().setParameters(request, ps,
083: parameters);
084: errorContext
085: .setMoreInfo("Check the statement (update failed).");
086: ps.execute();
087: rows = ps.getUpdateCount();
088: } finally {
089: closeStatement(request.getSession(), ps);
090: }
091: return rows;
092: }
093:
094: /**
095: * Adds a statement to a batch
096: *
097: * @param request - the request scope
098: * @param conn - the database connection
099: * @param sql - the sql statement
100: * @param parameters - the parameters for the statement
101: * @throws SQLException - if the statement fails
102: */
103: public void addBatch(RequestScope request, Connection conn,
104: String sql, Object[] parameters) throws SQLException {
105: Batch batch = (Batch) request.getSession().getBatch();
106: if (batch == null) {
107: batch = new Batch();
108: request.getSession().setBatch(batch);
109: }
110: batch.addBatch(request, conn, sql, parameters);
111: }
112:
113: /**
114: * Execute a batch of statements
115: *
116: * @param session - the session scope
117: * @return - the number of rows impacted by the batch
118: * @throws SQLException - if a statement fails
119: */
120: public int executeBatch(SessionScope session) throws SQLException {
121: int rows = 0;
122: Batch batch = (Batch) session.getBatch();
123: if (batch != null) {
124: try {
125: rows = batch.executeBatch();
126: } finally {
127: batch.cleanupBatch(session);
128: }
129: }
130: return rows;
131: }
132:
133: /**
134: * Execute a batch of statements
135: *
136: * @param session - the session scope
137: * @return - a List of BatchResult objects (may be null if no batch
138: * has been initiated). There will be one BatchResult object in the
139: * list for each sub-batch executed
140: * @throws SQLException if a database access error occurs, or the drive
141: * does not support batch statements
142: * @throws BatchException if the driver throws BatchUpdateException
143: */
144: public List executeBatchDetailed(SessionScope session)
145: throws SQLException, BatchException {
146: List answer = null;
147: Batch batch = (Batch) session.getBatch();
148: if (batch != null) {
149: try {
150: answer = batch.executeBatchDetailed();
151: } finally {
152: batch.cleanupBatch(session);
153: }
154: }
155: return answer;
156: }
157:
158: /**
159: * Long form of the method to execute a query
160: *
161: * @param request - the request scope
162: * @param conn - the database connection
163: * @param sql - the SQL statement to execute
164: * @param parameters - the parameters for the statement
165: * @param skipResults - the number of results to skip
166: * @param maxResults - the maximum number of results to return
167: * @param callback - the row handler for the query
168: * @throws SQLException - if the query fails
169: */
170: public void executeQuery(RequestScope request, Connection conn,
171: String sql, Object[] parameters, int skipResults,
172: int maxResults, RowHandlerCallback callback)
173: throws SQLException {
174: ErrorContext errorContext = request.getErrorContext();
175: errorContext.setActivity("executing query");
176: errorContext.setObjectId(sql);
177: PreparedStatement ps = null;
178: ResultSet rs = null;
179: setupResultObjectFactory(request);
180: try {
181: errorContext
182: .setMoreInfo("Check the SQL Statement (preparation failed).");
183: Integer rsType = request.getStatement().getResultSetType();
184: if (rsType != null) {
185: ps = prepareStatement(request.getSession(), conn, sql,
186: rsType);
187: } else {
188: ps = prepareStatement(request.getSession(), conn, sql);
189: }
190: setStatementTimeout(request.getStatement(), ps);
191: Integer fetchSize = request.getStatement().getFetchSize();
192: if (fetchSize != null) {
193: ps.setFetchSize(fetchSize.intValue());
194: }
195: errorContext
196: .setMoreInfo("Check the parameters (set parameters failed).");
197: request.getParameterMap().setParameters(request, ps,
198: parameters);
199: errorContext
200: .setMoreInfo("Check the statement (query failed).");
201: ps.execute();
202: errorContext
203: .setMoreInfo("Check the results (failed to retrieve results).");
204:
205: // Begin ResultSet Handling
206: rs = handleMultipleResults(ps, request, skipResults,
207: maxResults, callback);
208: // End ResultSet Handling
209: } finally {
210: try {
211: closeResultSet(rs);
212: } finally {
213: closeStatement(request.getSession(), ps);
214: }
215: }
216:
217: }
218:
219: /**
220: * Execute a stored procedure that updates data
221: *
222: * @param request - the request scope
223: * @param conn - the database connection
224: * @param sql - the SQL to call the procedure
225: * @param parameters - the parameters for the procedure
226: * @return - the rows impacted by the procedure
227: * @throws SQLException - if the procedure fails
228: */
229: public int executeUpdateProcedure(RequestScope request,
230: Connection conn, String sql, Object[] parameters)
231: throws SQLException {
232: ErrorContext errorContext = request.getErrorContext();
233: errorContext.setActivity("executing update procedure");
234: errorContext.setObjectId(sql);
235: CallableStatement cs = null;
236: setupResultObjectFactory(request);
237: int rows = 0;
238: try {
239: errorContext
240: .setMoreInfo("Check the SQL Statement (preparation failed).");
241: cs = prepareCall(request.getSession(), conn, sql);
242: setStatementTimeout(request.getStatement(), cs);
243: ParameterMap parameterMap = request.getParameterMap();
244: ParameterMapping[] mappings = parameterMap
245: .getParameterMappings();
246: errorContext
247: .setMoreInfo("Check the output parameters (register output parameters failed).");
248: registerOutputParameters(cs, mappings);
249: errorContext
250: .setMoreInfo("Check the parameters (set parameters failed).");
251: parameterMap.setParameters(request, cs, parameters);
252: errorContext
253: .setMoreInfo("Check the statement (update procedure failed).");
254: cs.execute();
255: rows = cs.getUpdateCount();
256: errorContext
257: .setMoreInfo("Check the output parameters (retrieval of output parameters failed).");
258: retrieveOutputParameters(request, cs, mappings, parameters,
259: null);
260: } finally {
261: closeStatement(request.getSession(), cs);
262: }
263: return rows;
264: }
265:
266: /**
267: * Execute a stored procedure
268: *
269: * @param request - the request scope
270: * @param conn - the database connection
271: * @param sql - the sql to call the procedure
272: * @param parameters - the parameters for the procedure
273: * @param skipResults - the number of results to skip
274: * @param maxResults - the maximum number of results to return
275: * @param callback - a row handler for processing the results
276: * @throws SQLException - if the procedure fails
277: */
278: public void executeQueryProcedure(RequestScope request,
279: Connection conn, String sql, Object[] parameters,
280: int skipResults, int maxResults, RowHandlerCallback callback)
281: throws SQLException {
282: ErrorContext errorContext = request.getErrorContext();
283: errorContext.setActivity("executing query procedure");
284: errorContext.setObjectId(sql);
285: CallableStatement cs = null;
286: ResultSet rs = null;
287: setupResultObjectFactory(request);
288: try {
289: errorContext
290: .setMoreInfo("Check the SQL Statement (preparation failed).");
291: Integer rsType = request.getStatement().getResultSetType();
292: if (rsType != null) {
293: cs = prepareCall(request.getSession(), conn, sql,
294: rsType);
295: } else {
296: cs = prepareCall(request.getSession(), conn, sql);
297: }
298: setStatementTimeout(request.getStatement(), cs);
299: Integer fetchSize = request.getStatement().getFetchSize();
300: if (fetchSize != null) {
301: cs.setFetchSize(fetchSize.intValue());
302: }
303: ParameterMap parameterMap = request.getParameterMap();
304: ParameterMapping[] mappings = parameterMap
305: .getParameterMappings();
306: errorContext
307: .setMoreInfo("Check the output parameters (register output parameters failed).");
308: registerOutputParameters(cs, mappings);
309: errorContext
310: .setMoreInfo("Check the parameters (set parameters failed).");
311: parameterMap.setParameters(request, cs, parameters);
312: errorContext
313: .setMoreInfo("Check the statement (update procedure failed).");
314: cs.execute();
315: errorContext
316: .setMoreInfo("Check the results (failed to retrieve results).");
317:
318: // Begin ResultSet Handling
319: rs = handleMultipleResults(cs, request, skipResults,
320: maxResults, callback);
321: // End ResultSet Handling
322: errorContext
323: .setMoreInfo("Check the output parameters (retrieval of output parameters failed).");
324: retrieveOutputParameters(request, cs, mappings, parameters,
325: callback);
326:
327: } finally {
328: try {
329: closeResultSet(rs);
330: } finally {
331: closeStatement(request.getSession(), cs);
332: }
333: }
334: }
335:
336: private ResultSet handleMultipleResults(PreparedStatement ps,
337: RequestScope request, int skipResults, int maxResults,
338: RowHandlerCallback callback) throws SQLException {
339: ResultSet rs;
340: rs = getFirstResultSet(ps);
341: if (rs != null) {
342: handleResults(request, rs, skipResults, maxResults,
343: callback);
344: }
345:
346: // Multiple ResultSet handling
347: if (callback.getRowHandler() instanceof DefaultRowHandler) {
348: MappedStatement statement = request.getStatement();
349: DefaultRowHandler defaultRowHandler = ((DefaultRowHandler) callback
350: .getRowHandler());
351: if (statement.hasMultipleResultMaps()) {
352: List multipleResults = new ArrayList();
353: multipleResults.add(defaultRowHandler.getList());
354: ResultMap[] resultMaps = statement
355: .getAdditionalResultMaps();
356: int i = 0;
357: while (moveToNextResultsSafely(ps)) {
358: if (i >= resultMaps.length)
359: break;
360: ResultMap rm = resultMaps[i];
361: request.setResultMap(rm);
362: rs = ps.getResultSet();
363: DefaultRowHandler rh = new DefaultRowHandler();
364: handleResults(request, rs, skipResults, maxResults,
365: new RowHandlerCallback(rm, null, rh));
366: multipleResults.add(rh.getList());
367: i++;
368: }
369: defaultRowHandler.setList(multipleResults);
370: request.setResultMap(statement.getResultMap());
371: } else {
372: while (moveToNextResultsSafely(ps))
373: ;
374: }
375: }
376: // End additional ResultSet handling
377: return rs;
378: }
379:
380: private ResultSet getFirstResultSet(Statement stmt)
381: throws SQLException {
382: ResultSet rs = null;
383: boolean hasMoreResults = true;
384: while (hasMoreResults) {
385: rs = stmt.getResultSet();
386: if (rs != null) {
387: break;
388: }
389: hasMoreResults = moveToNextResultsIfPresent(stmt);
390: }
391: return rs;
392: }
393:
394: private boolean moveToNextResultsIfPresent(Statement stmt)
395: throws SQLException {
396: boolean moreResults;
397: // This is the messed up JDBC approach for determining if there are more results
398: moreResults = !(((moveToNextResultsSafely(stmt) == false) && (stmt
399: .getUpdateCount() == -1)));
400: return moreResults;
401: }
402:
403: private boolean moveToNextResultsSafely(Statement stmt)
404: throws SQLException {
405: if (!stmt.getConnection().getMetaData()
406: .supportsMultipleResultSets()) {
407: return false;
408: }
409: return stmt.getMoreResults();
410: }
411:
412: private void handleResults(RequestScope request, ResultSet rs,
413: int skipResults, int maxResults, RowHandlerCallback callback)
414: throws SQLException {
415: try {
416: request.setResultSet(rs);
417: ResultMap resultMap = request.getResultMap();
418: if (resultMap != null) {
419: // Skip Results
420: if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {
421: if (skipResults > 0) {
422: rs.absolute(skipResults);
423: }
424: } else {
425: for (int i = 0; i < skipResults; i++) {
426: if (!rs.next()) {
427: return;
428: }
429: }
430: }
431:
432: // Get Results
433: int resultsFetched = 0;
434: while ((maxResults == SqlExecutor.NO_MAXIMUM_RESULTS || resultsFetched < maxResults)
435: && rs.next()) {
436: Object[] columnValues = resultMap.resolveSubMap(
437: request, rs).getResults(request, rs);
438: callback.handleResultObject(request, columnValues,
439: rs);
440: resultsFetched++;
441: }
442: }
443: } finally {
444: request.setResultSet(null);
445: }
446: }
447:
448: private void retrieveOutputParameters(RequestScope request,
449: CallableStatement cs, ParameterMapping[] mappings,
450: Object[] parameters, RowHandlerCallback callback)
451: throws SQLException {
452: for (int i = 0; i < mappings.length; i++) {
453: BasicParameterMapping mapping = ((BasicParameterMapping) mappings[i]);
454: if (mapping.isOutputAllowed()) {
455: if ("java.sql.ResultSet".equalsIgnoreCase(mapping
456: .getJavaTypeName())) {
457: ResultSet rs = (ResultSet) cs.getObject(i + 1);
458: ResultMap resultMap;
459: if (mapping.getResultMapName() == null) {
460: resultMap = request.getResultMap();
461: handleOutputParameterResults(request,
462: resultMap, rs, callback);
463: } else {
464: ExtendedSqlMapClient client = (ExtendedSqlMapClient) request
465: .getSession().getSqlMapClient();
466: resultMap = client.getDelegate().getResultMap(
467: mapping.getResultMapName());
468: DefaultRowHandler rowHandler = new DefaultRowHandler();
469: RowHandlerCallback handlerCallback = new RowHandlerCallback(
470: resultMap, null, rowHandler);
471: handleOutputParameterResults(request,
472: resultMap, rs, handlerCallback);
473: parameters[i] = rowHandler.getList();
474: }
475: rs.close();
476: } else {
477: parameters[i] = mapping.getTypeHandler().getResult(
478: cs, i + 1);
479: }
480: }
481: }
482: }
483:
484: private void registerOutputParameters(CallableStatement cs,
485: ParameterMapping[] mappings) throws SQLException {
486: for (int i = 0; i < mappings.length; i++) {
487: BasicParameterMapping mapping = ((BasicParameterMapping) mappings[i]);
488: if (mapping.isOutputAllowed()) {
489: if (null != mapping.getTypeName()
490: && !mapping.getTypeName().equals("")) { //@added
491: cs.registerOutParameter(i + 1, mapping
492: .getJdbcType(), mapping.getTypeName());
493: } else {
494: if (mapping.getNumericScale() != null
495: && (mapping.getJdbcType() == Types.NUMERIC || mapping
496: .getJdbcType() == Types.DECIMAL)) {
497: cs.registerOutParameter(i + 1, mapping
498: .getJdbcType(), mapping
499: .getNumericScale().intValue());
500: } else {
501: cs.registerOutParameter(i + 1, mapping
502: .getJdbcType());
503: }
504: }
505: }
506: }
507: }
508:
509: private void handleOutputParameterResults(RequestScope request,
510: ResultMap resultMap, ResultSet rs,
511: RowHandlerCallback callback) throws SQLException {
512: ResultMap orig = request.getResultMap();
513: try {
514: request.setResultSet(rs);
515: if (resultMap != null) {
516: request.setResultMap(resultMap);
517:
518: // Get Results
519: while (rs.next()) {
520: Object[] columnValues = resultMap.resolveSubMap(
521: request, rs).getResults(request, rs);
522: callback.handleResultObject(request, columnValues,
523: rs);
524: }
525: }
526: } finally {
527: request.setResultSet(null);
528: request.setResultMap(orig);
529: }
530: }
531:
532: /**
533: * Clean up any batches on the session
534: *
535: * @param session - the session to clean up
536: */
537: public void cleanup(SessionScope session) {
538: Batch batch = (Batch) session.getBatch();
539: if (batch != null) {
540: batch.cleanupBatch(session);
541: session.setBatch(null);
542: }
543: }
544:
545: private PreparedStatement prepareStatement(SessionScope session,
546: Connection conn, String sql, Integer rsType)
547: throws SQLException {
548: SqlMapExecutorDelegate delegate = ((ExtendedSqlMapClient) session
549: .getSqlMapExecutor()).getDelegate();
550: if (session.hasPreparedStatementFor(sql)) {
551: return session.getPreparedStatement((sql));
552: } else {
553: PreparedStatement ps = conn.prepareStatement(sql, rsType
554: .intValue(), ResultSet.CONCUR_READ_ONLY);
555: session.putPreparedStatement(delegate, sql, ps);
556: return ps;
557: }
558: }
559:
560: private CallableStatement prepareCall(SessionScope session,
561: Connection conn, String sql, Integer rsType)
562: throws SQLException {
563: SqlMapExecutorDelegate delegate = ((ExtendedSqlMapClient) session
564: .getSqlMapExecutor()).getDelegate();
565: if (session.hasPreparedStatementFor(sql)) {
566: return (CallableStatement) session
567: .getPreparedStatement((sql));
568: } else {
569: CallableStatement cs = conn.prepareCall(sql, rsType
570: .intValue(), ResultSet.CONCUR_READ_ONLY);
571: session.putPreparedStatement(delegate, sql, cs);
572: return cs;
573: }
574: }
575:
576: private static PreparedStatement prepareStatement(
577: SessionScope session, Connection conn, String sql)
578: throws SQLException {
579: SqlMapExecutorDelegate delegate = ((ExtendedSqlMapClient) session
580: .getSqlMapExecutor()).getDelegate();
581: if (session.hasPreparedStatementFor(sql)) {
582: return session.getPreparedStatement((sql));
583: } else {
584: PreparedStatement ps = conn.prepareStatement(sql);
585: session.putPreparedStatement(delegate, sql, ps);
586: return ps;
587: }
588: }
589:
590: private CallableStatement prepareCall(SessionScope session,
591: Connection conn, String sql) throws SQLException {
592: SqlMapExecutorDelegate delegate = ((ExtendedSqlMapClient) session
593: .getSqlMapExecutor()).getDelegate();
594: if (session.hasPreparedStatementFor(sql)) {
595: return (CallableStatement) session
596: .getPreparedStatement((sql));
597: } else {
598: CallableStatement cs = conn.prepareCall(sql);
599: session.putPreparedStatement(delegate, sql, cs);
600: return cs;
601: }
602: }
603:
604: private static void closeStatement(SessionScope session,
605: PreparedStatement ps) {
606: if (ps != null) {
607: if (!session.hasPreparedStatement(ps)) {
608: try {
609: ps.close();
610: } catch (SQLException e) {
611: // ignore
612: }
613: }
614: }
615: }
616:
617: /**
618: * @param rs
619: */
620: private static void closeResultSet(ResultSet rs) {
621: if (rs != null) {
622: try {
623: rs.close();
624: } catch (SQLException e) {
625: // ignore
626: }
627: }
628: }
629:
630: private static void setStatementTimeout(
631: MappedStatement mappedStatement, Statement statement)
632: throws SQLException {
633: if (mappedStatement.getTimeout() != null) {
634: statement.setQueryTimeout(mappedStatement.getTimeout()
635: .intValue());
636: }
637: }
638:
639: //
640: // Inner Classes
641: //
642:
643: private static class Batch {
644: private String currentSql;
645: private List statementList = new ArrayList();
646: private List batchResultList = new ArrayList();
647: private int size;
648:
649: /**
650: * Create a new batch
651: */
652: public Batch() {
653: this .size = 0;
654: }
655:
656: /**
657: * Getter for the batch size
658: *
659: * @return - the batch size
660: */
661: public int getSize() {
662: return size;
663: }
664:
665: /**
666: * Add a prepared statement to the batch
667: *
668: * @param request - the request scope
669: * @param conn - the database connection
670: * @param sql - the SQL to add
671: * @param parameters - the parameters for the SQL
672: * @throws SQLException - if the prepare for the SQL fails
673: */
674: public void addBatch(RequestScope request, Connection conn,
675: String sql, Object[] parameters) throws SQLException {
676: PreparedStatement ps = null;
677: if (currentSql != null
678: && sql.hashCode() == currentSql.hashCode()
679: && sql.length() == currentSql.length()) {
680: int last = statementList.size() - 1;
681: ps = (PreparedStatement) statementList.get(last);
682: } else {
683: ps = prepareStatement(request.getSession(), conn, sql);
684: setStatementTimeout(request.getStatement(), ps);
685: currentSql = sql;
686: statementList.add(ps);
687: batchResultList.add(new BatchResult(request
688: .getStatement().getId(), sql));
689: }
690: request.getParameterMap().setParameters(request, ps,
691: parameters);
692: ps.addBatch();
693: size++;
694: }
695:
696: /**
697: * TODO (Jeff Butler) - maybe this method should be deprecated in some release,
698: * and then removed in some even later release. executeBatchDetailed gives
699: * much more complete information.
700: * <p/>
701: * Execute the current session's batch
702: *
703: * @return - the number of rows updated
704: * @throws SQLException - if the batch fails
705: */
706: public int executeBatch() throws SQLException {
707: int totalRowCount = 0;
708: for (int i = 0, n = statementList.size(); i < n; i++) {
709: PreparedStatement ps = (PreparedStatement) statementList
710: .get(i);
711: int[] rowCounts = ps.executeBatch();
712: for (int j = 0; j < rowCounts.length; j++) {
713: if (rowCounts[j] == Statement.SUCCESS_NO_INFO) {
714: // do nothing
715: } else if (rowCounts[j] == Statement.EXECUTE_FAILED) {
716: throw new SQLException(
717: "The batched statement at index " + j
718: + " failed to execute.");
719: } else {
720: totalRowCount += rowCounts[j];
721: }
722: }
723: }
724: return totalRowCount;
725: }
726:
727: /**
728: * Batch execution method that returns all the information
729: * the driver has to offer.
730: *
731: * @return a List of BatchResult objects
732: * @throws BatchException (an SQLException sub class) if any nested
733: * batch fails
734: * @throws SQLException if a database access error occurs, or the drive
735: * does not support batch statements
736: * @throws BatchException if the driver throws BatchUpdateException
737: */
738: public List executeBatchDetailed() throws SQLException,
739: BatchException {
740: List answer = new ArrayList();
741: for (int i = 0, n = statementList.size(); i < n; i++) {
742: BatchResult br = (BatchResult) batchResultList.get(i);
743: PreparedStatement ps = (PreparedStatement) statementList
744: .get(i);
745: try {
746: br.setUpdateCounts(ps.executeBatch());
747: } catch (BatchUpdateException e) {
748: StringBuffer message = new StringBuffer();
749: message.append("Sub batch number ");
750: message.append(i + 1);
751: message.append(" failed.");
752: if (i > 0) {
753: message.append(" ");
754: message.append(i);
755: message
756: .append(" prior sub batch(s) completed successfully, but will be rolled back.");
757: }
758: throw new BatchException(message.toString(), e,
759: answer, br.getStatementId(), br.getSql());
760: }
761: answer.add(br);
762: }
763: return answer;
764: }
765:
766: /**
767: * Close all the statements in the batch and clear all the statements
768: *
769: * @param session
770: */
771: public void cleanupBatch(SessionScope session) {
772: for (int i = 0, n = statementList.size(); i < n; i++) {
773: PreparedStatement ps = (PreparedStatement) statementList
774: .get(i);
775: closeStatement(session, ps);
776: }
777: currentSql = null;
778: statementList.clear();
779: batchResultList.clear();
780: size = 0;
781: }
782: }
783:
784: private void setupResultObjectFactory(RequestScope request) {
785: ExtendedSqlMapClient client = (ExtendedSqlMapClient) request
786: .getSession().getSqlMapClient();
787: ResultObjectFactoryUtil.setResultObjectFactory(client
788: .getResultObjectFactory());
789: ResultObjectFactoryUtil.setStatementId(request.getStatement()
790: .getId());
791: }
792: }
|