KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ibatis > sqlmap > engine > execution > SqlExecutor


1 /*
2  * Copyright 2004 Clinton Begin
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package com.ibatis.sqlmap.engine.execution;
17
18 import com.ibatis.sqlmap.engine.mapping.parameter.BasicParameterMapping;
19 import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMap;
20 import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMapping;
21 import com.ibatis.sqlmap.engine.mapping.result.ResultMap;
22 import com.ibatis.sqlmap.engine.mapping.statement.RowHandlerCallback;
23 import com.ibatis.sqlmap.engine.scope.ErrorContext;
24 import com.ibatis.sqlmap.engine.scope.RequestScope;
25 import com.ibatis.sqlmap.engine.scope.SessionScope;
26
27 import java.sql.*;
28 import java.util.ArrayList JavaDoc;
29 import java.util.List JavaDoc;
30
31 /**
32  * Class responsible for executing the SQL
33  */

34 public class SqlExecutor {
35
36   //
37
// Constants
38
//
39

40   /**
41    * Constant to let us know not to skip anything
42    */

43   public static final int NO_SKIPPED_RESULTS = 0;
44   
45   /**
46    * Constant to let us know to include all records
47    */

48   public static final int NO_MAXIMUM_RESULTS = -999999;
49
50   //
51
// Public Methods
52
//
53

54   /**
55    * Execute an update
56    *
57    * @param request - the request scope
58    * @param conn - the database connection
59    * @param sql - the sql statement to execute
60    * @param parameters - the parameters for the sql statement
61    *
62    * @return - the number of records changed
63    *
64    * @throws SQLException - if the update fails
65    */

66   public int executeUpdate(RequestScope request, Connection conn, String JavaDoc sql, Object JavaDoc[] parameters)
67       throws SQLException {
68     ErrorContext errorContext = request.getErrorContext();
69     errorContext.setActivity("executing update");
70     errorContext.setObjectId(sql);
71
72     PreparedStatement ps = null;
73     int rows = 0;
74
75     try {
76       errorContext.setMoreInfo("Check the SQL Statement (preparation failed).");
77       ps = conn.prepareStatement(sql);
78
79       errorContext.setMoreInfo("Check the parameters (set parameters failed).");
80       request.getParameterMap().setParameters(request, ps, parameters);
81
82       errorContext.setMoreInfo("Check the statement (update failed).");
83
84       ps.execute();
85       rows = ps.getUpdateCount();
86     }
87     finally {
88       closeStatement(ps);
89     }
90
91     return rows;
92   }
93
94   /**
95    * Adds a statement to a batch
96    *
97    * @param request - the request scope
98    * @param conn - the database connection
99    * @param sql - the sql statement
100    * @param parameters - the parameters for the statement
101    *
102    * @throws SQLException - if the statement fails
103    */

104   public void addBatch(RequestScope request, Connection conn, String JavaDoc sql, Object JavaDoc[] parameters)
105       throws SQLException {
106     Batch batch = (Batch) request.getSession().getBatch();
107     if (batch == null) {
108       batch = new Batch();
109       request.getSession().setBatch(batch);
110     }
111     batch.addBatch(request, conn, sql, parameters);
112   }
113
114   /**
115    * Execute a batch of statements
116    *
117    * @param session - the session scope
118    *
119    * @return - the number of rows impacted by the batch
120    *
121    * @throws SQLException - if a statement fails
122    */

123   public int executeBatch(SessionScope session)
124       throws SQLException {
125     int rows = 0;
126     Batch batch = (Batch) session.getBatch();
127     if (batch != null) {
128       try {
129         rows = batch.executeBatch();
130       } finally {
131         batch.cleanupBatch();
132       }
133     }
134     return rows;
135   }
136
137   /**
138    * Long form of the method to execute a query
139    *
140    * @param request - the request scope
141    * @param conn - the database connection
142    * @param sql - the SQL statement to execute
143    * @param parameters - the parameters for the statement
144    * @param skipResults - the number of results to skip
145    * @param maxResults - the maximum number of results to return
146    * @param callback - the row handler for the query
147    *
148    * @throws SQLException - if the query fails
149    */

150   public void executeQuery(RequestScope request, Connection conn, String JavaDoc sql, Object JavaDoc[] parameters,
151                            int skipResults, int maxResults, RowHandlerCallback callback)
152       throws SQLException {
153     ErrorContext errorContext = request.getErrorContext();
154     errorContext.setActivity("executing query");
155     errorContext.setObjectId(sql);
156
157     PreparedStatement ps = null;
158     ResultSet rs = null;
159
160     try {
161       errorContext.setMoreInfo("Check the SQL Statement (preparation failed).");
162
163       Integer JavaDoc rsType = request.getStatement().getResultSetType();
164       if (rsType != null) {
165         ps = conn.prepareStatement(sql, rsType.intValue(), ResultSet.CONCUR_READ_ONLY);
166       } else {
167         ps = conn.prepareStatement(sql);
168       }
169
170       Integer JavaDoc fetchSize = request.getStatement().getFetchSize();
171       if (fetchSize != null) {
172         ps.setFetchSize(fetchSize.intValue());
173       }
174
175       errorContext.setMoreInfo("Check the parameters (set parameters failed).");
176       request.getParameterMap().setParameters(request, ps, parameters);
177
178       errorContext.setMoreInfo("Check the statement (query failed).");
179
180       ps.execute();
181       rs = ps.getResultSet();
182
183       errorContext.setMoreInfo("Check the results (failed to retrieve results).");
184       handleResults(request, rs, skipResults, maxResults, callback);
185
186       // clear out remaining results
187
while (ps.getMoreResults());
188
189     } finally {
190       try {
191         closeResultSet(rs);
192       } finally {
193         closeStatement(ps);
194       }
195     }
196
197   }
198
199   /**
200    * Execute a stored procedure that updates data
201    *
202    * @param request - the request scope
203    * @param conn - the database connection
204    * @param sql - the SQL to call the procedure
205    * @param parameters - the parameters for the procedure
206    *
207    * @return - the rows impacted by the procedure
208    *
209    * @throws SQLException - if the procedure fails
210    */

211   public int executeUpdateProcedure(RequestScope request, Connection conn, String JavaDoc sql, Object JavaDoc[] parameters)
212       throws SQLException {
213     ErrorContext errorContext = request.getErrorContext();
214     errorContext.setActivity("executing update procedure");
215     errorContext.setObjectId(sql);
216
217     CallableStatement cs = null;
218     int rows = 0;
219
220     try {
221       errorContext.setMoreInfo("Check the SQL Statement (preparation failed).");
222       cs = conn.prepareCall(sql);
223
224       ParameterMap parameterMap = request.getParameterMap();
225
226       ParameterMapping[] mappings = parameterMap.getParameterMappings();
227
228       errorContext.setMoreInfo("Check the output parameters (register output parameters failed).");
229       registerOutputParameters(cs, mappings);
230
231       errorContext.setMoreInfo("Check the parameters (set parameters failed).");
232       parameterMap.setParameters(request, cs, parameters);
233
234       errorContext.setMoreInfo("Check the statement (update procedure failed).");
235
236       cs.execute();
237       rows = cs.getUpdateCount();
238
239       errorContext.setMoreInfo("Check the output parameters (retrieval of output parameters failed).");
240       retrieveOutputParameters(cs, mappings, parameters);
241     } finally {
242       closeStatement(cs);
243     }
244
245     return rows;
246   }
247
248   /**
249    * Execute a stored procedure
250    *
251    * @param request - the request scope
252    * @param conn - the database connection
253    * @param sql - the sql to call the procedure
254    * @param parameters - the parameters for the procedure
255    * @param skipResults - the number of results to skip
256    * @param maxResults - the maximum number of results to return
257    * @param callback - a row handler for processing the results
258    *
259    * @throws SQLException - if the procedure fails
260    */

261   public void executeQueryProcedure(RequestScope request, Connection conn, String JavaDoc sql, Object JavaDoc[] parameters,
262                                     int skipResults, int maxResults, RowHandlerCallback callback)
263       throws SQLException {
264     ErrorContext errorContext = request.getErrorContext();
265     errorContext.setActivity("executing query procedure");
266     errorContext.setObjectId(sql);
267
268     CallableStatement cs = null;
269     ResultSet rs = null;
270
271     try {
272       errorContext.setMoreInfo("Check the SQL Statement (preparation failed).");
273       cs = conn.prepareCall(sql);
274
275       ParameterMap parameterMap = request.getParameterMap();
276
277       ParameterMapping[] mappings = parameterMap.getParameterMappings();
278
279       errorContext.setMoreInfo("Check the output parameters (register output parameters failed).");
280       registerOutputParameters(cs, mappings);
281
282       errorContext.setMoreInfo("Check the parameters (set parameters failed).");
283       parameterMap.setParameters(request, cs, parameters);
284
285       errorContext.setMoreInfo("Check the statement (update procedure failed).");
286
287       cs.execute();
288       rs = cs.getResultSet();
289
290       errorContext.setMoreInfo("Check the results (failed to retrieve results).");
291       handleResults(request, rs, skipResults, maxResults, callback);
292
293       // consume additional results
294
while (cs.getMoreResults());
295
296       errorContext.setMoreInfo("Check the output parameters (retrieval of output parameters failed).");
297       retrieveOutputParameters(cs, mappings, parameters);
298
299     } finally {
300       try {
301         closeResultSet(rs);
302       } finally {
303         closeStatement(cs);
304       }
305     }
306
307   }
308
309   /**
310    * Clean up any batches on the session
311    *
312    * @param session - the session to clean up
313    */

314   public void cleanup(SessionScope session) {
315     Batch batch = (Batch) session.getBatch();
316     if (batch != null) {
317       batch.cleanupBatch();
318       session.setBatch(null);
319     }
320   }
321
322   //
323
// Private Methods
324
//
325

326   private void retrieveOutputParameters(CallableStatement cs, ParameterMapping[] mappings, Object JavaDoc[] parameters) throws SQLException {
327     for (int i = 0; i < mappings.length; i++) {
328       BasicParameterMapping mapping = ((BasicParameterMapping) mappings[i]);
329       if (mapping.isOutputAllowed()) {
330         Object JavaDoc o = mapping.getTypeHandler().getResult(cs, i + 1);
331         parameters[i] = o;
332       }
333     }
334   }
335
336   private void registerOutputParameters(CallableStatement cs, ParameterMapping[] mappings) throws SQLException {
337     for (int i = 0; i < mappings.length; i++) {
338       BasicParameterMapping mapping = ((BasicParameterMapping) mappings[i]);
339       if (mapping.isOutputAllowed()) {
340         if ( null != mapping.getTypeName() && !mapping.getTypeName().equals("") ) { //@added
341
cs.registerOutParameter(i + 1, mapping.getJdbcType(), mapping.getTypeName() );
342         } else {
343           cs.registerOutParameter(i + 1, mapping.getJdbcType());
344         }
345       }
346     }
347   }
348
349   private void handleResults(RequestScope request, ResultSet rs, int skipResults, int maxResults, RowHandlerCallback callback) throws SQLException {
350     try {
351       request.setResultSet(rs);
352       ResultMap resultMap = request.getResultMap();
353       if (resultMap != null) {
354         // Skip Results
355
if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {
356           if (skipResults > 0) {
357             rs.absolute(skipResults);
358           }
359         } else {
360           for (int i = 0; i < skipResults; i++) {
361             if (!rs.next()) {
362               break;
363             }
364           }
365         }
366
367         // Get Results
368
int resultsFetched = 0;
369         while ((maxResults == SqlExecutor.NO_MAXIMUM_RESULTS || resultsFetched < maxResults) && rs.next()) {
370           Object JavaDoc[] columnValues = resultMap.resolveSubMap(request, rs).getResults(request, rs);
371           callback.handleResultObject(request, columnValues, rs);
372           resultsFetched++;
373         }
374       }
375     } finally {
376       request.setResultSet(null);
377     }
378   }
379
380   /**
381    * @param ps
382    */

383   private static void closeStatement(PreparedStatement ps) {
384     if (ps != null) {
385       try {
386         ps.close();
387       } catch (SQLException e) {
388         // ignore
389
}
390     }
391   }
392
393   /**
394    * @param rs
395    */

396   private static void closeResultSet(ResultSet rs) {
397     if (rs != null) {
398       try {
399         rs.close();
400       } catch (SQLException e) {
401         // ignore
402
}
403     }
404   }
405
406   //
407
// Inner Classes
408
//
409

410   private static class Batch {
411     private String JavaDoc currentSql;
412     private List JavaDoc statementList = new ArrayList JavaDoc();
413     private int size;
414     private static final int SUCCESS_NO_INFO = -2;
415     private static final int EXECUTE_FAILED = -3;
416
417     /**
418      * Create a new batch
419      */

420     public Batch() {
421       this.size = 0;
422     }
423
424     /**
425      * Getter for the batch size
426      *
427      * @return - the batch size
428      */

429     public int getSize() {
430       return size;
431     }
432
433     /**
434      * Add a prepared statement to the batch
435      *
436      * @param request - the request scope
437      * @param conn - the database connection
438      * @param sql - the SQL to add
439      * @param parameters - the parameters for the SQL
440      *
441      * @throws SQLException - if the prepare for the SQL fails
442      */

443     public void addBatch(RequestScope request, Connection conn, String JavaDoc sql, Object JavaDoc[] parameters) throws SQLException {
444       PreparedStatement ps = null;
445       if (currentSql != null
446           && sql.hashCode() == currentSql.hashCode()
447           && sql.length() == currentSql.length()) {
448         int last = statementList.size() - 1;
449         ps = (PreparedStatement) statementList.get(last);
450       } else {
451         ps = conn.prepareStatement(sql);
452         currentSql = sql;
453         statementList.add(ps);
454       }
455       request.getParameterMap().setParameters(request, ps, parameters);
456       ps.addBatch();
457       size++;
458     }
459
460     /**
461      * Execute the current session's batch
462      *
463      * @return - the number of rows updated
464      *
465      * @throws SQLException - if the batch fails
466      */

467     public int executeBatch() throws SQLException {
468       int totalRowCount = 0;
469       for (int i = 0, n = statementList.size(); i < n; i++) {
470         PreparedStatement ps = (PreparedStatement) statementList.get(i);
471         int[] rowCounts = ps.executeBatch();
472         for (int j = 0; j < rowCounts.length; j++) {
473           if (rowCounts[j] == SUCCESS_NO_INFO) {
474             // do nothing
475
} else if (rowCounts[j] == EXECUTE_FAILED) {
476             throw new SQLException("The batched statement at index " + j + " failed to execute.");
477           } else {
478             totalRowCount += rowCounts[j];
479           }
480         }
481       }
482       return totalRowCount;
483     }
484
485     /**
486      * Close all the statements in the batch and clear all the statements
487      */

488     public void cleanupBatch() {
489       for (int i = 0, n = statementList.size(); i < n; i++) {
490         PreparedStatement ps = (PreparedStatement) statementList.get(i);
491         closeStatement(ps);
492       }
493       currentSql = null;
494       statementList.clear();
495       size = 0;
496     }
497   }
498
499 }
500
Popular Tags