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 = {};
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 errorContext.setMoreInfo("Check the parameter map.");
140 Object[] parameters = parameterMap.getParameterObjectValues(statementScope, parameterObject);
141
142 errorContext.setMoreInfo("Check the SQL statement.");
143 String sqlString = sql.getSql(statementScope, parameterObject);
144
145 errorContext.setActivity("executing mapped statement");
146 errorContext.setMoreInfo("Check the statement or the result map.");
147 int rows = sqlExecuteUpdate(statementScope, trans.getConnection(), sqlString, parameters);
148
149 errorContext.setMoreInfo("Check the output parameters.");
150 if (parameterObject != null) {
151 postProcessParameterObject(statementScope, parameterObject, parameters);
152 }
153
154 errorContext.reset();
155 sql.cleanup(statementScope);
156 notifyListeners();
157 return rows;
158 } catch (SQLException e) {
159 errorContext.setCause(e);
160 throw new NestedSQLException(errorContext.toString(), e.getSQLState(), e.getErrorCode(), e);
161 } catch (Exception e) {
162 errorContext.setCause(e);
163 throw new NestedSQLException(errorContext.toString(), e);
164 }
165 }
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184 public Object executeQueryForObject(StatementScope statementScope, Transaction trans, Object parameterObject,
185 Object resultObject) throws SQLException {
186 try {
187 Object object = null;
188
189 DefaultRowHandler rowHandler = new DefaultRowHandler();
190 executeQueryWithCallback(statementScope, trans.getConnection(), parameterObject, resultObject, rowHandler,
191 SqlExecutor.NO_SKIPPED_RESULTS, SqlExecutor.NO_MAXIMUM_RESULTS);
192 List list = rowHandler.getList();
193
194 if (list.size() > 1) {
195 throw new SQLException("Error: executeQueryForObject returned too many results.");
196 }
197 if (!list.isEmpty()) {
198 object = list.get(0);
199 }
200
201 return object;
202 } catch (TransactionException e) {
203 throw new NestedSQLException("Error getting Connection from Transaction. Cause: " + e, e);
204 }
205 }
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226 public List executeQueryForList(StatementScope statementScope, Transaction trans, Object parameterObject,
227 int skipResults, int maxResults) throws SQLException {
228 try {
229 DefaultRowHandler rowHandler = new DefaultRowHandler();
230 executeQueryWithCallback(statementScope, trans.getConnection(), parameterObject, null, rowHandler, skipResults,
231 maxResults);
232 return rowHandler.getList();
233 } catch (TransactionException e) {
234 throw new NestedSQLException("Error getting Connection from Transaction. Cause: " + e, e);
235 }
236 }
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253 public void executeQueryWithRowHandler(StatementScope statementScope, Transaction trans, Object parameterObject,
254 RowHandler rowHandler) throws SQLException {
255 try {
256 executeQueryWithCallback(statementScope, trans.getConnection(), parameterObject, null, rowHandler,
257 SqlExecutor.NO_SKIPPED_RESULTS, SqlExecutor.NO_MAXIMUM_RESULTS);
258 } catch (TransactionException e) {
259 throw new NestedSQLException("Error getting Connection from Transaction. Cause: " + e, e);
260 }
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 protected void executeQueryWithCallback(StatementScope statementScope, Connection conn, Object parameterObject,
289 Object resultObject, RowHandler rowHandler, int skipResults, int maxResults) throws SQLException {
290 ErrorContext errorContext = statementScope.getErrorContext();
291 errorContext.setActivity("preparing the mapped statement for execution");
292 errorContext.setObjectId(this.getId());
293 errorContext.setResource(this.getResource());
294
295 try {
296 parameterObject = validateParameter(parameterObject);
297
298 Sql sql = getSql();
299
300 errorContext.setMoreInfo("Check the parameter map.");
301 ParameterMap parameterMap = sql.getParameterMap(statementScope, parameterObject);
302
303 errorContext.setMoreInfo("Check the result map.");
304 ResultMap resultMap = sql.getResultMap(statementScope, parameterObject);
305
306 statementScope.setResultMap(resultMap);
307 statementScope.setParameterMap(parameterMap);
308
309 errorContext.setMoreInfo("Check the parameter map.");
310 Object[] parameters = parameterMap.getParameterObjectValues(statementScope, parameterObject);
311
312 errorContext.setMoreInfo("Check the SQL statement.");
313 String sqlString = sql.getSql(statementScope, parameterObject);
314
315 errorContext.setActivity("executing mapped statement");
316 errorContext.setMoreInfo("Check the SQL statement or the result map.");
317 RowHandlerCallback callback = new RowHandlerCallback(resultMap, resultObject, rowHandler);
318 sqlExecuteQuery(statementScope, conn, sqlString, parameters, skipResults, maxResults, callback);
319
320 errorContext.setMoreInfo("Check the output parameters.");
321 if (parameterObject != null) {
322 postProcessParameterObject(statementScope, parameterObject, parameters);
323 }
324
325 errorContext.reset();
326 sql.cleanup(statementScope);
327 notifyListeners();
328 } catch (SQLException e) {
329 errorContext.setCause(e);
330 throw new NestedSQLException(errorContext.toString(), e.getSQLState(), e.getErrorCode(), e);
331 } catch (Exception e) {
332 errorContext.setCause(e);
333 throw new NestedSQLException(errorContext.toString(), e);
334 }
335 }
336
337
338
339
340
341
342
343
344
345
346
347 protected void postProcessParameterObject(StatementScope statementScope, Object parameterObject,
348 Object[] parameters) {
349 }
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368 protected int sqlExecuteUpdate(StatementScope statementScope, Connection conn, String sqlString, Object[] parameters)
369 throws SQLException {
370 if (statementScope.getSession().isInBatch()) {
371 getSqlExecutor().addBatch(statementScope, conn, sqlString, parameters);
372 return 0;
373 }
374 return getSqlExecutor().executeUpdate(statementScope, conn, sqlString, parameters);
375 }
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398 protected void sqlExecuteQuery(StatementScope statementScope, Connection conn, String sqlString, Object[] parameters,
399 int skipResults, int maxResults, RowHandlerCallback callback) throws SQLException {
400 getSqlExecutor().executeQuery(statementScope, conn, sqlString, parameters, skipResults, maxResults, callback);
401 }
402
403
404
405
406
407
408
409
410
411
412
413
414 protected Object validateParameter(Object param) throws SQLException {
415 Object newParam = param;
416 Class parameterClass = getParameterClass();
417 if (newParam != null && parameterClass != null) {
418 if (DomTypeMarker.class.isAssignableFrom(parameterClass)) {
419 if (XmlTypeMarker.class.isAssignableFrom(parameterClass)) {
420 if (!(newParam instanceof String) && !(newParam instanceof Document)) {
421 throw new SQLException("Invalid parameter object type. Expected '" + String.class.getName() + "' or '"
422 + Document.class.getName() + "' but found '" + newParam.getClass().getName() + "'.");
423 }
424 if (!(newParam instanceof Document)) {
425 newParam = stringToDocument((String) newParam);
426 }
427 } else if (!Document.class.isAssignableFrom(newParam.getClass())) {
428 throw new SQLException("Invalid parameter object type. Expected '" + Document.class.getName()
429 + "' but found '" + newParam.getClass().getName() + "'.");
430 }
431 } else if (!parameterClass.isAssignableFrom(newParam.getClass())) {
432 throw new SQLException("Invalid parameter object type. Expected '" + parameterClass.getName() + "' but found '"
433 + newParam.getClass().getName() + "'.");
434 }
435 }
436 return newParam;
437 }
438
439
440
441
442
443
444
445
446
447 private Document stringToDocument(String s) {
448 try {
449 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
450 documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
451 documentBuilderFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
452 documentBuilderFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
453 DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
454 return documentBuilder.parse(new ReaderInputStream(new StringReader(s)));
455 } catch (Exception e) {
456 throw new RuntimeException("Error occurred. Cause: " + e, e);
457 }
458 }
459
460
461
462
463
464
465 public String getId() {
466 return id;
467 }
468
469
470
471
472
473
474 public Integer getResultSetType() {
475 return resultSetType;
476 }
477
478
479
480
481
482
483
484 public void setResultSetType(Integer resultSetType) {
485 this.resultSetType = resultSetType;
486 }
487
488
489
490
491
492
493 public Integer getFetchSize() {
494 return fetchSize;
495 }
496
497
498
499
500
501
502
503 public void setFetchSize(Integer fetchSize) {
504 this.fetchSize = fetchSize;
505 }
506
507
508
509
510
511
512
513 public void setId(String id) {
514 this.id = id;
515 }
516
517
518
519
520
521
522 public Sql getSql() {
523 return sql;
524 }
525
526
527
528
529
530
531
532 public void setSql(Sql sql) {
533 this.sql = sql;
534 }
535
536
537
538
539
540
541 public ResultMap getResultMap() {
542 return resultMap;
543 }
544
545
546
547
548
549
550
551 public void setResultMap(ResultMap resultMap) {
552 this.resultMap = resultMap;
553 }
554
555
556
557
558
559
560 public ParameterMap getParameterMap() {
561 return parameterMap;
562 }
563
564
565
566
567
568
569
570 public void setParameterMap(ParameterMap parameterMap) {
571 this.parameterMap = parameterMap;
572 }
573
574
575
576
577
578
579 public Class getParameterClass() {
580 return parameterClass;
581 }
582
583
584
585
586
587
588
589 public void setParameterClass(Class parameterClass) {
590 this.parameterClass = parameterClass;
591 }
592
593
594
595
596
597
598 public String getResource() {
599 return resource;
600 }
601
602
603
604
605
606
607
608 public void setResource(String resource) {
609 this.resource = resource;
610 }
611
612
613
614
615
616
617
618
619
620
621
622 public CacheKey getCacheKey(StatementScope statementScope, Object parameterObject) {
623 Sql sql = statementScope.getSql();
624 ParameterMap pmap = sql.getParameterMap(statementScope, parameterObject);
625 CacheKey cacheKey = pmap.getCacheKey(statementScope, parameterObject);
626 cacheKey.update(id);
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648 cacheKey.update(sql.getSql(statementScope, parameterObject));
649 return cacheKey;
650 }
651
652
653
654
655
656
657
658 public void setBaseCacheKey(int base) {
659 this.baseCacheKey = base;
660 }
661
662
663
664
665
666
667
668 public void addExecuteListener(ExecuteListener listener) {
669 executeListeners.add(listener);
670 }
671
672
673
674
675 public void notifyListeners() {
676 for (Object executeListener : executeListeners) {
677 ((ExecuteListener) executeListener).onExecuteStatement(this);
678 }
679 }
680
681
682
683
684
685
686 public SqlExecutor getSqlExecutor() {
687 return sqlMapClient.getSqlExecutor();
688 }
689
690
691
692
693
694
695 public SqlMapClient getSqlMapClient() {
696 return sqlMapClient;
697 }
698
699
700
701
702
703
704
705 public void setSqlMapClient(SqlMapClient sqlMapClient) {
706 this.sqlMapClient = (SqlMapClientImpl) sqlMapClient;
707 }
708
709
710
711
712
713
714
715 public void initRequest(StatementScope statementScope) {
716 statementScope.setStatement(this);
717 statementScope.setParameterMap(parameterMap);
718 statementScope.setResultMap(resultMap);
719 statementScope.setSql(sql);
720 }
721
722
723
724
725
726
727 public Integer getTimeout() {
728 return timeout;
729 }
730
731
732
733
734
735
736
737 public void setTimeout(Integer timeout) {
738 this.timeout = timeout;
739 }
740
741
742
743
744
745
746
747 public void addResultMap(ResultMap resultMap) {
748 List<ResultMap> resultMapList = Arrays.asList(additionalResultMaps);
749 resultMapList = new ArrayList<>(resultMapList);
750 resultMapList.add(resultMap);
751 additionalResultMaps = resultMapList.toArray(new ResultMap[resultMapList.size()]);
752 }
753
754
755
756
757
758
759 public boolean hasMultipleResultMaps() {
760 return additionalResultMaps.length > 0;
761 }
762
763
764
765
766
767
768 public ResultMap[] getAdditionalResultMaps() {
769 return additionalResultMaps;
770 }
771 }