1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.ibatis.sqlmap.engine.mapping.statement;
17
18 import com.ibatis.common.io.ReaderInputStream;
19 import com.ibatis.common.jdbc.exception.NestedSQLException;
20 import com.ibatis.sqlmap.client.SqlMapClient;
21 import com.ibatis.sqlmap.client.event.RowHandler;
22 import com.ibatis.sqlmap.engine.cache.CacheKey;
23 import com.ibatis.sqlmap.engine.execution.SqlExecutor;
24 import com.ibatis.sqlmap.engine.impl.SqlMapClientImpl;
25 import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMap;
26 import com.ibatis.sqlmap.engine.mapping.result.ResultMap;
27 import com.ibatis.sqlmap.engine.mapping.sql.Sql;
28 import com.ibatis.sqlmap.engine.scope.ErrorContext;
29 import com.ibatis.sqlmap.engine.scope.StatementScope;
30 import com.ibatis.sqlmap.engine.transaction.Transaction;
31 import com.ibatis.sqlmap.engine.transaction.TransactionException;
32 import com.ibatis.sqlmap.engine.type.DomTypeMarker;
33 import com.ibatis.sqlmap.engine.type.XmlTypeMarker;
34
35 import java.io.StringReader;
36 import java.sql.Connection;
37 import java.sql.SQLException;
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.List;
41
42 import javax.xml.XMLConstants;
43 import javax.xml.parsers.DocumentBuilder;
44 import javax.xml.parsers.DocumentBuilderFactory;
45
46 import org.w3c.dom.Document;
47
48
49
50
51 public class MappedStatement {
52
53
54 private String id;
55
56
57 private Integer resultSetType;
58
59
60 private Integer fetchSize;
61
62
63 private ResultMap resultMap;
64
65
66 private ParameterMap parameterMap;
67
68
69 private Class parameterClass;
70
71
72 private Sql sql;
73
74
75 private int baseCacheKey;
76
77
78 private SqlMapClientImpl sqlMapClient;
79
80
81 private Integer timeout;
82
83
84 private ResultMap[] additionalResultMaps = new ResultMap[0];
85
86
87 private List executeListeners = new ArrayList();
88
89
90 private String resource;
91
92
93
94
95
96
97 public StatementType getStatementType() {
98 return StatementType.UNKNOWN;
99 }
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116 public int executeUpdate(StatementScope statementScope, Transaction trans, Object parameterObject)
117 throws SQLException {
118 ErrorContext errorContext = statementScope.getErrorContext();
119 errorContext.setActivity("preparing the mapped statement for execution");
120 errorContext.setObjectId(this.getId());
121 errorContext.setResource(this.getResource());
122
123 statementScope.getSession().setCommitRequired(true);
124
125 try {
126 parameterObject = validateParameter(parameterObject);
127
128 Sql sql = getSql();
129
130 errorContext.setMoreInfo("Check the parameter map.");
131 ParameterMap parameterMap = sql.getParameterMap(statementScope, parameterObject);
132
133 errorContext.setMoreInfo("Check the result map.");
134 ResultMap resultMap = sql.getResultMap(statementScope, parameterObject);
135
136 statementScope.setResultMap(resultMap);
137 statementScope.setParameterMap(parameterMap);
138
139 int rows = 0;
140
141 errorContext.setMoreInfo("Check the parameter map.");
142 Object[] parameters = parameterMap.getParameterObjectValues(statementScope, parameterObject);
143
144 errorContext.setMoreInfo("Check the SQL statement.");
145 String sqlString = sql.getSql(statementScope, parameterObject);
146
147 errorContext.setActivity("executing mapped statement");
148 errorContext.setMoreInfo("Check the statement or the result map.");
149 rows = sqlExecuteUpdate(statementScope, trans.getConnection(), sqlString, parameters);
150
151 errorContext.setMoreInfo("Check the output parameters.");
152 if (parameterObject != null) {
153 postProcessParameterObject(statementScope, parameterObject, parameters);
154 }
155
156 errorContext.reset();
157 sql.cleanup(statementScope);
158 notifyListeners();
159 return rows;
160 } catch (SQLException e) {
161 errorContext.setCause(e);
162 throw new NestedSQLException(errorContext.toString(), e.getSQLState(), e.getErrorCode(), e);
163 } catch (Exception e) {
164 errorContext.setCause(e);
165 throw new NestedSQLException(errorContext.toString(), e);
166 }
167 }
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186 public Object executeQueryForObject(StatementScope statementScope, Transaction trans, Object parameterObject,
187 Object resultObject) throws SQLException {
188 try {
189 Object object = null;
190
191 DefaultRowHandler rowHandler = new DefaultRowHandler();
192 executeQueryWithCallback(statementScope, trans.getConnection(), parameterObject, resultObject, rowHandler,
193 SqlExecutor.NO_SKIPPED_RESULTS, SqlExecutor.NO_MAXIMUM_RESULTS);
194 List list = rowHandler.getList();
195
196 if (list.size() > 1) {
197 throw new SQLException("Error: executeQueryForObject returned too many results.");
198 } else if (list.size() > 0) {
199 object = list.get(0);
200 }
201
202 return object;
203 } catch (TransactionException e) {
204 throw new NestedSQLException("Error getting Connection from Transaction. Cause: " + e, e);
205 }
206 }
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227 public List executeQueryForList(StatementScope statementScope, Transaction trans, Object parameterObject,
228 int skipResults, int maxResults) throws SQLException {
229 try {
230 DefaultRowHandler rowHandler = new DefaultRowHandler();
231 executeQueryWithCallback(statementScope, trans.getConnection(), parameterObject, null, rowHandler, skipResults,
232 maxResults);
233 return rowHandler.getList();
234 } catch (TransactionException e) {
235 throw new NestedSQLException("Error getting Connection from Transaction. Cause: " + e, e);
236 }
237 }
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254 public void executeQueryWithRowHandler(StatementScope statementScope, Transaction trans, Object parameterObject,
255 RowHandler rowHandler) throws SQLException {
256 try {
257 executeQueryWithCallback(statementScope, trans.getConnection(), parameterObject, null, rowHandler,
258 SqlExecutor.NO_SKIPPED_RESULTS, SqlExecutor.NO_MAXIMUM_RESULTS);
259 } catch (TransactionException e) {
260 throw new NestedSQLException("Error getting Connection from Transaction. Cause: " + e, e);
261 }
262 }
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289 protected void executeQueryWithCallback(StatementScope statementScope, Connection conn, Object parameterObject,
290 Object resultObject, RowHandler rowHandler, int skipResults, int maxResults) throws SQLException {
291 ErrorContext errorContext = statementScope.getErrorContext();
292 errorContext.setActivity("preparing the mapped statement for execution");
293 errorContext.setObjectId(this.getId());
294 errorContext.setResource(this.getResource());
295
296 try {
297 parameterObject = validateParameter(parameterObject);
298
299 Sql sql = getSql();
300
301 errorContext.setMoreInfo("Check the parameter map.");
302 ParameterMap parameterMap = sql.getParameterMap(statementScope, parameterObject);
303
304 errorContext.setMoreInfo("Check the result map.");
305 ResultMap resultMap = sql.getResultMap(statementScope, parameterObject);
306
307 statementScope.setResultMap(resultMap);
308 statementScope.setParameterMap(parameterMap);
309
310 errorContext.setMoreInfo("Check the parameter map.");
311 Object[] parameters = parameterMap.getParameterObjectValues(statementScope, parameterObject);
312
313 errorContext.setMoreInfo("Check the SQL statement.");
314 String sqlString = sql.getSql(statementScope, parameterObject);
315
316 errorContext.setActivity("executing mapped statement");
317 errorContext.setMoreInfo("Check the SQL statement or the result map.");
318 RowHandlerCallback callback = new RowHandlerCallback(resultMap, resultObject, rowHandler);
319 sqlExecuteQuery(statementScope, conn, sqlString, parameters, skipResults, maxResults, callback);
320
321 errorContext.setMoreInfo("Check the output parameters.");
322 if (parameterObject != null) {
323 postProcessParameterObject(statementScope, parameterObject, parameters);
324 }
325
326 errorContext.reset();
327 sql.cleanup(statementScope);
328 notifyListeners();
329 } catch (SQLException e) {
330 errorContext.setCause(e);
331 throw new NestedSQLException(errorContext.toString(), e.getSQLState(), e.getErrorCode(), e);
332 } catch (Exception e) {
333 errorContext.setCause(e);
334 throw new NestedSQLException(errorContext.toString(), e);
335 }
336 }
337
338
339
340
341
342
343
344
345
346
347
348 protected void postProcessParameterObject(StatementScope statementScope, Object parameterObject,
349 Object[] parameters) {
350 }
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369 protected int sqlExecuteUpdate(StatementScope statementScope, Connection conn, String sqlString, Object[] parameters)
370 throws SQLException {
371 if (statementScope.getSession().isInBatch()) {
372 getSqlExecutor().addBatch(statementScope, conn, sqlString, parameters);
373 return 0;
374 } else {
375 return getSqlExecutor().executeUpdate(statementScope, conn, sqlString, parameters);
376 }
377 }
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400 protected void sqlExecuteQuery(StatementScope statementScope, Connection conn, String sqlString, Object[] parameters,
401 int skipResults, int maxResults, RowHandlerCallback callback) throws SQLException {
402 getSqlExecutor().executeQuery(statementScope, conn, sqlString, parameters, skipResults, maxResults, callback);
403 }
404
405
406
407
408
409
410
411
412
413
414
415
416 protected Object validateParameter(Object param) throws SQLException {
417 Object newParam = param;
418 Class parameterClass = getParameterClass();
419 if (newParam != null && parameterClass != null) {
420 if (DomTypeMarker.class.isAssignableFrom(parameterClass)) {
421 if (XmlTypeMarker.class.isAssignableFrom(parameterClass)) {
422 if (!(newParam instanceof String) && !(newParam instanceof Document)) {
423 throw new SQLException("Invalid parameter object type. Expected '" + String.class.getName() + "' or '"
424 + Document.class.getName() + "' but found '" + newParam.getClass().getName() + "'.");
425 }
426 if (!(newParam instanceof Document)) {
427 newParam = stringToDocument((String) newParam);
428 }
429 } else {
430 if (!Document.class.isAssignableFrom(newParam.getClass())) {
431 throw new SQLException("Invalid parameter object type. Expected '" + Document.class.getName()
432 + "' but found '" + newParam.getClass().getName() + "'.");
433 }
434 }
435 } else {
436 if (!parameterClass.isAssignableFrom(newParam.getClass())) {
437 throw new SQLException("Invalid parameter object type. Expected '" + parameterClass.getName()
438 + "' but found '" + newParam.getClass().getName() + "'.");
439 }
440 }
441 }
442 return newParam;
443 }
444
445
446
447
448
449
450
451
452
453 private Document stringToDocument(String s) {
454 try {
455 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
456 documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
457 documentBuilderFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
458 documentBuilderFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
459 DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
460 return documentBuilder.parse(new ReaderInputStream(new StringReader(s)));
461 } catch (Exception e) {
462 throw new RuntimeException("Error occurred. Cause: " + e, e);
463 }
464 }
465
466
467
468
469
470
471 public String getId() {
472 return id;
473 }
474
475
476
477
478
479
480 public Integer getResultSetType() {
481 return resultSetType;
482 }
483
484
485
486
487
488
489
490 public void setResultSetType(Integer resultSetType) {
491 this.resultSetType = resultSetType;
492 }
493
494
495
496
497
498
499 public Integer getFetchSize() {
500 return fetchSize;
501 }
502
503
504
505
506
507
508
509 public void setFetchSize(Integer fetchSize) {
510 this.fetchSize = fetchSize;
511 }
512
513
514
515
516
517
518
519 public void setId(String id) {
520 this.id = id;
521 }
522
523
524
525
526
527
528 public Sql getSql() {
529 return sql;
530 }
531
532
533
534
535
536
537
538 public void setSql(Sql sql) {
539 this.sql = sql;
540 }
541
542
543
544
545
546
547 public ResultMap getResultMap() {
548 return resultMap;
549 }
550
551
552
553
554
555
556
557 public void setResultMap(ResultMap resultMap) {
558 this.resultMap = resultMap;
559 }
560
561
562
563
564
565
566 public ParameterMap getParameterMap() {
567 return parameterMap;
568 }
569
570
571
572
573
574
575
576 public void setParameterMap(ParameterMap parameterMap) {
577 this.parameterMap = parameterMap;
578 }
579
580
581
582
583
584
585 public Class getParameterClass() {
586 return parameterClass;
587 }
588
589
590
591
592
593
594
595 public void setParameterClass(Class parameterClass) {
596 this.parameterClass = parameterClass;
597 }
598
599
600
601
602
603
604 public String getResource() {
605 return resource;
606 }
607
608
609
610
611
612
613
614 public void setResource(String resource) {
615 this.resource = resource;
616 }
617
618
619
620
621
622
623
624
625
626
627
628 public CacheKey getCacheKey(StatementScope statementScope, Object parameterObject) {
629 Sql sql = statementScope.getSql();
630 ParameterMap pmap = sql.getParameterMap(statementScope, parameterObject);
631 CacheKey cacheKey = pmap.getCacheKey(statementScope, parameterObject);
632 cacheKey.update(id);
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654 cacheKey.update(sql.getSql(statementScope, parameterObject));
655 return cacheKey;
656 }
657
658
659
660
661
662
663
664 public void setBaseCacheKey(int base) {
665 this.baseCacheKey = base;
666 }
667
668
669
670
671
672
673
674 public void addExecuteListener(ExecuteListener listener) {
675 executeListeners.add(listener);
676 }
677
678
679
680
681 public void notifyListeners() {
682 for (int i = 0, n = executeListeners.size(); i < n; i++) {
683 ((ExecuteListener) executeListeners.get(i)).onExecuteStatement(this);
684 }
685 }
686
687
688
689
690
691
692 public SqlExecutor getSqlExecutor() {
693 return sqlMapClient.getSqlExecutor();
694 }
695
696
697
698
699
700
701 public SqlMapClient getSqlMapClient() {
702 return sqlMapClient;
703 }
704
705
706
707
708
709
710
711 public void setSqlMapClient(SqlMapClient sqlMapClient) {
712 this.sqlMapClient = (SqlMapClientImpl) sqlMapClient;
713 }
714
715
716
717
718
719
720
721 public void initRequest(StatementScope statementScope) {
722 statementScope.setStatement(this);
723 statementScope.setParameterMap(parameterMap);
724 statementScope.setResultMap(resultMap);
725 statementScope.setSql(sql);
726 }
727
728
729
730
731
732
733 public Integer getTimeout() {
734 return timeout;
735 }
736
737
738
739
740
741
742
743 public void setTimeout(Integer timeout) {
744 this.timeout = timeout;
745 }
746
747
748
749
750
751
752
753 public void addResultMap(ResultMap resultMap) {
754 List resultMapList = Arrays.asList(additionalResultMaps);
755 resultMapList = new ArrayList(resultMapList);
756 resultMapList.add(resultMap);
757 additionalResultMaps = (ResultMap[]) resultMapList.toArray(new ResultMap[resultMapList.size()]);
758 }
759
760
761
762
763
764
765 public boolean hasMultipleResultMaps() {
766 return additionalResultMaps.length > 0;
767 }
768
769
770
771
772
773
774 public ResultMap[] getAdditionalResultMaps() {
775 return additionalResultMaps;
776 }
777 }