• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mybatis / ibatis-2 / 738

29 Dec 2025 12:36AM UTC coverage: 65.6% (+0.03%) from 65.571%
738

push

github

web-flow
Merge pull request #340 from hazendaz/master

More code cleanup and styling changes

1598 of 2797 branches covered (57.13%)

23 of 42 new or added lines in 2 files covered. (54.76%)

2 existing lines in 1 file now uncovered.

5042 of 7686 relevant lines covered (65.6%)

0.66 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

72.84
/src/main/java/com/ibatis/sqlmap/engine/execution/DefaultSqlExecutor.java
1
/*
2
 * Copyright 2004-2025 the original author or authors.
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
 *    https://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.config.SqlMapConfiguration;
19
import com.ibatis.sqlmap.engine.impl.SqlMapClientImpl;
20
import com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate;
21
import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMap;
22
import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMapping;
23
import com.ibatis.sqlmap.engine.mapping.result.ResultMap;
24
import com.ibatis.sqlmap.engine.mapping.result.ResultObjectFactoryUtil;
25
import com.ibatis.sqlmap.engine.mapping.statement.DefaultRowHandler;
26
import com.ibatis.sqlmap.engine.mapping.statement.MappedStatement;
27
import com.ibatis.sqlmap.engine.mapping.statement.RowHandlerCallback;
28
import com.ibatis.sqlmap.engine.scope.ErrorContext;
29
import com.ibatis.sqlmap.engine.scope.SessionScope;
30
import com.ibatis.sqlmap.engine.scope.StatementScope;
31

32
import java.sql.BatchUpdateException;
33
import java.sql.CallableStatement;
34
import java.sql.Connection;
35
import java.sql.PreparedStatement;
36
import java.sql.ResultSet;
37
import java.sql.SQLException;
38
import java.sql.Statement;
39
import java.sql.Types;
40
import java.util.ArrayList;
41
import java.util.List;
42
import java.util.Properties;
43

44
/**
45
 * Class responsible for executing the SQL.
46
 */
47
public class DefaultSqlExecutor implements SqlExecutor {
1✔
48

49
  /**
50
   * Execute an update
51
   *
52
   * @param statementScope
53
   *          - the request scope
54
   * @param conn
55
   *          - the database connection
56
   * @param sql
57
   *          - the sql statement to execute
58
   * @param parameters
59
   *          - the parameters for the sql statement
60
   *
61
   * @return - the number of records changed
62
   *
63
   * @throws SQLException
64
   *           - if the update fails
65
   */
66
  @Override
67
  public int executeUpdate(StatementScope statementScope, Connection conn, String sql, Object[] parameters)
68
      throws SQLException {
69
    ErrorContext errorContext = statementScope.getErrorContext();
1✔
70
    errorContext.setActivity("executing update");
1✔
71
    errorContext.setObjectId(sql);
1✔
72
    PreparedStatement ps = null;
1✔
73
    setupResultObjectFactory(statementScope);
1✔
74
    int rows = 0;
1✔
75
    try {
76
      errorContext.setMoreInfo("Check the SQL Statement (preparation failed).");
1✔
77
      ps = prepareStatement(statementScope.getSession(), conn, sql);
1✔
78
      setStatementTimeout(statementScope.getStatement(), ps);
1✔
79
      errorContext.setMoreInfo("Check the parameters (set parameters failed).");
1✔
80
      statementScope.getParameterMap().setParameters(statementScope, ps, parameters);
1✔
81
      errorContext.setMoreInfo("Check the statement (update failed).");
1✔
82
      ps.execute();
1✔
83
      rows = ps.getUpdateCount();
1✔
84
    } finally {
85
      closeStatement(statementScope.getSession(), ps);
1✔
86
      cleanupResultObjectFactory();
1✔
87
    }
88
    return rows;
1✔
89
  }
90

91
  /**
92
   * Adds a statement to a batch
93
   *
94
   * @param statementScope
95
   *          - the request scope
96
   * @param conn
97
   *          - the database connection
98
   * @param sql
99
   *          - the sql statement
100
   * @param parameters
101
   *          - the parameters for the statement
102
   *
103
   * @throws SQLException
104
   *           - if the statement fails
105
   */
106
  @Override
107
  public void addBatch(StatementScope statementScope, Connection conn, String sql, Object[] parameters)
108
      throws SQLException {
109
    Batch batch = (Batch) statementScope.getSession().getBatch();
1✔
110
    if (batch == null) {
1✔
111
      batch = new Batch();
1✔
112
      statementScope.getSession().setBatch(batch);
1✔
113
    }
114
    batch.addBatch(statementScope, conn, sql, parameters);
1✔
115
  }
1✔
116

117
  /**
118
   * Execute a batch of statements
119
   *
120
   * @param sessionScope
121
   *          - the session scope
122
   *
123
   * @return - the number of rows impacted by the batch
124
   *
125
   * @throws SQLException
126
   *           - if a statement fails
127
   */
128
  @Override
129
  public int executeBatch(SessionScope sessionScope) throws SQLException {
130
    int rows = 0;
1✔
131
    Batch batch = (Batch) sessionScope.getBatch();
1✔
132
    if (batch != null) {
1✔
133
      try {
134
        rows = batch.executeBatch();
1✔
135
      } finally {
136
        batch.cleanupBatch(sessionScope);
1✔
137
      }
138
    }
139
    return rows;
1✔
140
  }
141

142
  /**
143
   * Execute a batch of statements
144
   *
145
   * @param sessionScope
146
   *          - the session scope
147
   *
148
   * @return - a List of BatchResult objects (may be null if no batch has been initiated). There will be one BatchResult
149
   *         object in the list for each sub-batch executed
150
   *
151
   * @throws SQLException
152
   *           if a database access error occurs, or the drive does not support batch statements
153
   * @throws BatchException
154
   *           if the driver throws BatchUpdateException
155
   */
156
  @Override
157
  public List executeBatchDetailed(SessionScope sessionScope) throws SQLException, BatchException {
158
    List answer = null;
1✔
159
    Batch batch = (Batch) sessionScope.getBatch();
1✔
160
    if (batch != null) {
1!
161
      try {
162
        answer = batch.executeBatchDetailed();
1✔
163
      } finally {
164
        batch.cleanupBatch(sessionScope);
1✔
165
      }
166
    }
167
    return answer;
1✔
168
  }
169

170
  /**
171
   * Long form of the method to execute a query
172
   *
173
   * @param statementScope
174
   *          - the request scope
175
   * @param conn
176
   *          - the database connection
177
   * @param sql
178
   *          - the SQL statement to execute
179
   * @param parameters
180
   *          - the parameters for the statement
181
   * @param skipResults
182
   *          - the number of results to skip
183
   * @param maxResults
184
   *          - the maximum number of results to return
185
   * @param callback
186
   *          - the row handler for the query
187
   *
188
   * @throws SQLException
189
   *           - if the query fails
190
   */
191
  @Override
192
  public void executeQuery(StatementScope statementScope, Connection conn, String sql, Object[] parameters,
193
      int skipResults, int maxResults, RowHandlerCallback callback) throws SQLException {
194
    ErrorContext errorContext = statementScope.getErrorContext();
1✔
195
    errorContext.setActivity("executing query");
1✔
196
    errorContext.setObjectId(sql);
1✔
197
    PreparedStatement ps = null;
1✔
198
    ResultSet rs = null;
1✔
199
    setupResultObjectFactory(statementScope);
1✔
200
    try {
201
      errorContext.setMoreInfo("Check the SQL Statement (preparation failed).");
1✔
202
      Integer rsType = statementScope.getStatement().getResultSetType();
1✔
203
      if (rsType != null) {
1!
204
        ps = prepareStatement(statementScope.getSession(), conn, sql, rsType);
×
205
      } else {
206
        ps = prepareStatement(statementScope.getSession(), conn, sql);
1✔
207
      }
208
      setStatementTimeout(statementScope.getStatement(), ps);
1✔
209
      Integer fetchSize = statementScope.getStatement().getFetchSize();
1✔
210
      if (fetchSize != null) {
1!
211
        ps.setFetchSize(fetchSize.intValue());
×
212
      }
213
      errorContext.setMoreInfo("Check the parameters (set parameters failed).");
1✔
214
      statementScope.getParameterMap().setParameters(statementScope, ps, parameters);
1✔
215
      errorContext.setMoreInfo("Check the statement (query failed).");
1✔
216
      ps.execute();
1✔
217
      errorContext.setMoreInfo("Check the results (failed to retrieve results).");
1✔
218

219
      // Begin ResultSet Handling
220
      rs = handleMultipleResults(ps, statementScope, skipResults, maxResults, callback);
1✔
221
      // End ResultSet Handling
222
    } finally {
223
      try {
224
        closeResultSet(rs);
1✔
225
      } finally {
226
        closeStatement(statementScope.getSession(), ps);
1✔
227
        cleanupResultObjectFactory();
1✔
228
      }
229
    }
230

231
  }
1✔
232

233
  /**
234
   * Execute a stored procedure that updates data
235
   *
236
   * @param statementScope
237
   *          - the request scope
238
   * @param conn
239
   *          - the database connection
240
   * @param sql
241
   *          - the SQL to call the procedure
242
   * @param parameters
243
   *          - the parameters for the procedure
244
   *
245
   * @return - the rows impacted by the procedure
246
   *
247
   * @throws SQLException
248
   *           - if the procedure fails
249
   */
250
  @Override
251
  public int executeUpdateProcedure(StatementScope statementScope, Connection conn, String sql, Object[] parameters)
252
      throws SQLException {
253
    ErrorContext errorContext = statementScope.getErrorContext();
×
254
    errorContext.setActivity("executing update procedure");
×
255
    errorContext.setObjectId(sql);
×
256
    CallableStatement cs = null;
×
257
    setupResultObjectFactory(statementScope);
×
258
    int rows = 0;
×
259
    try {
260
      errorContext.setMoreInfo("Check the SQL Statement (preparation failed).");
×
261
      cs = prepareCall(statementScope.getSession(), conn, sql);
×
262
      setStatementTimeout(statementScope.getStatement(), cs);
×
263
      ParameterMap parameterMap = statementScope.getParameterMap();
×
264
      ParameterMapping[] mappings = parameterMap.getParameterMappings();
×
265
      errorContext.setMoreInfo("Check the output parameters (register output parameters failed).");
×
266
      registerOutputParameters(cs, mappings);
×
267
      errorContext.setMoreInfo("Check the parameters (set parameters failed).");
×
268
      parameterMap.setParameters(statementScope, cs, parameters);
×
269
      errorContext.setMoreInfo("Check the statement (update procedure failed).");
×
270
      cs.execute();
×
271
      rows = cs.getUpdateCount();
×
272
      errorContext.setMoreInfo("Check the output parameters (retrieval of output parameters failed).");
×
273
      retrieveOutputParameters(statementScope, cs, mappings, parameters, null);
×
274
    } finally {
275
      closeStatement(statementScope.getSession(), cs);
×
276
      cleanupResultObjectFactory();
×
277
    }
278
    return rows;
×
279
  }
280

281
  /**
282
   * Execute a stored procedure
283
   *
284
   * @param statementScope
285
   *          - the request scope
286
   * @param conn
287
   *          - the database connection
288
   * @param sql
289
   *          - the sql to call the procedure
290
   * @param parameters
291
   *          - the parameters for the procedure
292
   * @param skipResults
293
   *          - the number of results to skip
294
   * @param maxResults
295
   *          - the maximum number of results to return
296
   * @param callback
297
   *          - a row handler for processing the results
298
   *
299
   * @throws SQLException
300
   *           - if the procedure fails
301
   */
302
  @Override
303
  public void executeQueryProcedure(StatementScope statementScope, Connection conn, String sql, Object[] parameters,
304
      int skipResults, int maxResults, RowHandlerCallback callback) throws SQLException {
305
    ErrorContext errorContext = statementScope.getErrorContext();
1✔
306
    errorContext.setActivity("executing query procedure");
1✔
307
    errorContext.setObjectId(sql);
1✔
308
    CallableStatement cs = null;
1✔
309
    ResultSet rs = null;
1✔
310
    setupResultObjectFactory(statementScope);
1✔
311
    try {
312
      errorContext.setMoreInfo("Check the SQL Statement (preparation failed).");
1✔
313
      Integer rsType = statementScope.getStatement().getResultSetType();
1✔
314
      if (rsType != null) {
1!
315
        cs = prepareCall(statementScope.getSession(), conn, sql, rsType);
×
316
      } else {
317
        cs = prepareCall(statementScope.getSession(), conn, sql);
1✔
318
      }
319
      setStatementTimeout(statementScope.getStatement(), cs);
1✔
320
      Integer fetchSize = statementScope.getStatement().getFetchSize();
1✔
321
      if (fetchSize != null) {
1!
322
        cs.setFetchSize(fetchSize.intValue());
×
323
      }
324
      ParameterMap parameterMap = statementScope.getParameterMap();
1✔
325
      ParameterMapping[] mappings = parameterMap.getParameterMappings();
1✔
326
      errorContext.setMoreInfo("Check the output parameters (register output parameters failed).");
1✔
327
      registerOutputParameters(cs, mappings);
1✔
328
      errorContext.setMoreInfo("Check the parameters (set parameters failed).");
1✔
329
      parameterMap.setParameters(statementScope, cs, parameters);
1✔
330
      errorContext.setMoreInfo("Check the statement (update procedure failed).");
1✔
331
      cs.execute();
1✔
332
      errorContext.setMoreInfo("Check the results (failed to retrieve results).");
1✔
333

334
      // Begin ResultSet Handling
335
      rs = handleMultipleResults(cs, statementScope, skipResults, maxResults, callback);
1✔
336
      // End ResultSet Handling
337
      errorContext.setMoreInfo("Check the output parameters (retrieval of output parameters failed).");
1✔
338
      retrieveOutputParameters(statementScope, cs, mappings, parameters, callback);
1✔
339

340
    } finally {
341
      try {
342
        closeResultSet(rs);
1✔
343
      } finally {
344
        closeStatement(statementScope.getSession(), cs);
1✔
345
        cleanupResultObjectFactory();
1✔
346
      }
347
    }
348
  }
1✔
349

350
  @Override
351
  public void init(SqlMapConfiguration config, Properties globalProps) {
352
    // No implementation is required in DefaultSqlExecutor.
353
  }
×
354

355
  /**
356
   * Handle multiple results.
357
   *
358
   * @param ps
359
   *          the ps
360
   * @param statementScope
361
   *          the statement scope
362
   * @param skipResults
363
   *          the skip results
364
   * @param maxResults
365
   *          the max results
366
   * @param callback
367
   *          the callback
368
   *
369
   * @return the result set
370
   *
371
   * @throws SQLException
372
   *           the SQL exception
373
   */
374
  private ResultSet handleMultipleResults(PreparedStatement ps, StatementScope statementScope, int skipResults,
375
      int maxResults, RowHandlerCallback callback) throws SQLException {
376
    ResultSet rs = getFirstResultSet(statementScope, ps);
1✔
377
    if (rs != null) {
1!
378
      handleResults(statementScope, rs, skipResults, maxResults, callback);
1✔
379
    }
380

381
    // Multiple ResultSet handling
382
    if (callback.getRowHandler() instanceof DefaultRowHandler) {
1✔
383
      MappedStatement statement = statementScope.getStatement();
1✔
384
      DefaultRowHandler defaultRowHandler = (DefaultRowHandler) callback.getRowHandler();
1✔
385
      if (statement.hasMultipleResultMaps()) {
1✔
386
        List multipleResults = new ArrayList<>();
1✔
387
        multipleResults.add(defaultRowHandler.getList());
1✔
388
        ResultMap[] resultMaps = statement.getAdditionalResultMaps();
1✔
389
        int i = 0;
1✔
390
        while (moveToNextResultsSafely(statementScope, ps)) {
1✔
391
          if (i >= resultMaps.length) {
1!
392
            break;
×
393
          }
394
          ResultMap rm = resultMaps[i];
1✔
395
          statementScope.setResultMap(rm);
1✔
396
          rs = ps.getResultSet();
1✔
397
          DefaultRowHandler rh = new DefaultRowHandler();
1✔
398
          handleResults(statementScope, rs, skipResults, maxResults, new RowHandlerCallback(rm, null, rh));
1✔
399
          multipleResults.add(rh.getList());
1✔
400
          i++;
1✔
401
        }
1✔
402
        defaultRowHandler.setList(multipleResults);
1✔
403
        statementScope.setResultMap(statement.getResultMap());
1✔
404
      } else {
1✔
405
        while (moveToNextResultsSafely(statementScope, ps)) {
1!
406
          ;
407
        }
408
      }
409
    }
410
    // End additional ResultSet handling
411
    return rs;
1✔
412
  }
413

414
  /**
415
   * Gets the first result set.
416
   *
417
   * @param scope
418
   *          the scope
419
   * @param stmt
420
   *          the stmt
421
   *
422
   * @return the first result set
423
   *
424
   * @throws SQLException
425
   *           the SQL exception
426
   */
427
  private ResultSet getFirstResultSet(StatementScope scope, Statement stmt) throws SQLException {
428
    ResultSet rs = null;
1✔
429
    boolean hasMoreResults = true;
1✔
430
    while (hasMoreResults) {
1!
431
      rs = stmt.getResultSet();
1✔
432
      if (rs != null) {
1!
433
        break;
1✔
434
      }
435
      hasMoreResults = moveToNextResultsIfPresent(scope, stmt);
×
436
    }
437
    return rs;
1✔
438
  }
439

440
  /**
441
   * Move to next results if present.
442
   *
443
   * @param scope
444
   *          the scope
445
   * @param stmt
446
   *          the stmt
447
   *
448
   * @return true, if successful
449
   *
450
   * @throws SQLException
451
   *           the SQL exception
452
   */
453
  private boolean moveToNextResultsIfPresent(StatementScope scope, Statement stmt) throws SQLException {
454
    boolean moreResults;
455
    // This is the messed up JDBC approach for determining if there are more results
456
    boolean movedToNextResultsSafely = moveToNextResultsSafely(scope, stmt);
×
457
    int updateCount = stmt.getUpdateCount();
×
458

NEW
459
    moreResults = movedToNextResultsSafely || updateCount != -1;
×
460

461
    // ibatis-384: workaround for mysql not returning -1 for stmt.getUpdateCount()
NEW
462
    if (moreResults) {
×
NEW
463
      moreResults = movedToNextResultsSafely || isMultipleResultSetSupportPresent(scope, stmt);
×
464
    }
465

466
    return moreResults;
×
467
  }
468

469
  /**
470
   * Move to next results safely.
471
   *
472
   * @param scope
473
   *          the scope
474
   * @param stmt
475
   *          the stmt
476
   *
477
   * @return true, if successful
478
   *
479
   * @throws SQLException
480
   *           the SQL exception
481
   */
482
  private boolean moveToNextResultsSafely(StatementScope scope, Statement stmt) throws SQLException {
483
    if (isMultipleResultSetSupportPresent(scope, stmt)) {
1!
484
      return stmt.getMoreResults();
1✔
485
    }
486
    return false;
×
487
  }
488

489
  /**
490
   * checks whether multiple result set support is present - either by direct support of the database driver or by
491
   * forcing it.
492
   *
493
   * @param scope
494
   *          the scope
495
   * @param stmt
496
   *          the stmt
497
   *
498
   * @return true, if is multiple result set support present
499
   *
500
   * @throws SQLException
501
   *           the SQL exception
502
   */
503
  private boolean isMultipleResultSetSupportPresent(StatementScope scope, Statement stmt) throws SQLException {
504
    return forceMultipleResultSetSupport(scope) || stmt.getConnection().getMetaData().supportsMultipleResultSets();
1!
505
  }
506

507
  /**
508
   * Force multiple result set support.
509
   *
510
   * @param scope
511
   *          the scope
512
   *
513
   * @return true, if successful
514
   */
515
  private boolean forceMultipleResultSetSupport(StatementScope scope) {
516
    return ((SqlMapClientImpl) scope.getSession().getSqlMapClient()).getDelegate().isForceMultipleResultSetSupport();
1✔
517
  }
518

519
  /**
520
   * Handle results.
521
   *
522
   * @param statementScope
523
   *          the statement scope
524
   * @param rs
525
   *          the rs
526
   * @param skipResults
527
   *          the skip results
528
   * @param maxResults
529
   *          the max results
530
   * @param callback
531
   *          the callback
532
   *
533
   * @throws SQLException
534
   *           the SQL exception
535
   */
536
  private void handleResults(StatementScope statementScope, ResultSet rs, int skipResults, int maxResults,
537
      RowHandlerCallback callback) throws SQLException {
538
    try {
539
      statementScope.setResultSet(rs);
1✔
540
      ResultMap resultMap = statementScope.getResultMap();
1✔
541
      if (resultMap != null) {
1!
542
        // Skip Results
543
        if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {
1!
544
          if (skipResults > 0) {
×
545
            rs.absolute(skipResults);
×
546
          }
547
        } else {
548
          for (int i = 0; i < skipResults; i++) {
1✔
549
            if (!rs.next()) {
1✔
550
              return;
1✔
551
            }
552
          }
553
        }
554

555
        // Get Results
556
        int resultsFetched = 0;
1✔
557
        while ((maxResults == NO_MAXIMUM_RESULTS || resultsFetched < maxResults) && rs.next()) {
1✔
558
          Object[] columnValues = resultMap.resolveSubMap(statementScope, rs).getResults(statementScope, rs);
1✔
559
          callback.handleResultObject(statementScope, columnValues, rs);
1✔
560
          resultsFetched++;
1✔
561
        }
1✔
562
      }
563
    } finally {
564
      statementScope.setResultSet(null);
1✔
565
    }
566
  }
1✔
567

568
  /**
569
   * Retrieve output parameters.
570
   *
571
   * @param statementScope
572
   *          the statement scope
573
   * @param cs
574
   *          the cs
575
   * @param mappings
576
   *          the mappings
577
   * @param parameters
578
   *          the parameters
579
   * @param callback
580
   *          the callback
581
   *
582
   * @throws SQLException
583
   *           the SQL exception
584
   */
585
  private void retrieveOutputParameters(StatementScope statementScope, CallableStatement cs,
586
      ParameterMapping[] mappings, Object[] parameters, RowHandlerCallback callback) throws SQLException {
587
    for (int i = 0; i < mappings.length; i++) {
1✔
588
      ParameterMapping mapping = mappings[i];
1✔
589
      if (mapping.isOutputAllowed()) {
1!
590
        if ("java.sql.ResultSet".equalsIgnoreCase(mapping.getJavaTypeName())) {
×
591
          ResultSet rs = (ResultSet) cs.getObject(i + 1);
×
592
          ResultMap resultMap;
593
          if (mapping.getResultMapName() == null) {
×
594
            resultMap = statementScope.getResultMap();
×
595
            handleOutputParameterResults(statementScope, resultMap, rs, callback);
×
596
          } else {
597
            SqlMapClientImpl client = (SqlMapClientImpl) statementScope.getSession().getSqlMapClient();
×
598
            resultMap = client.getDelegate().getResultMap(mapping.getResultMapName());
×
599
            DefaultRowHandler rowHandler = new DefaultRowHandler();
×
600
            RowHandlerCallback handlerCallback = new RowHandlerCallback(resultMap, null, rowHandler);
×
601
            handleOutputParameterResults(statementScope, resultMap, rs, handlerCallback);
×
602
            parameters[i] = rowHandler.getList();
×
603
          }
604
          rs.close();
×
605
        } else {
×
606
          parameters[i] = mapping.getTypeHandler().getResult(cs, i + 1);
×
607
        }
608
      }
609
    }
610
  }
1✔
611

612
  /**
613
   * Register output parameters.
614
   *
615
   * @param cs
616
   *          the cs
617
   * @param mappings
618
   *          the mappings
619
   *
620
   * @throws SQLException
621
   *           the SQL exception
622
   */
623
  private void registerOutputParameters(CallableStatement cs, ParameterMapping[] mappings) throws SQLException {
624
    for (int i = 0; i < mappings.length; i++) {
1✔
625
      ParameterMapping mapping = mappings[i];
1✔
626
      if (mapping.isOutputAllowed()) {
1!
627
        if (null != mapping.getTypeName() && !mapping.getTypeName().equals("")) { // @added
×
628
          cs.registerOutParameter(i + 1, mapping.getJdbcType(), mapping.getTypeName());
×
NEW
629
        } else if (mapping.getNumericScale() != null
×
NEW
630
            && (mapping.getJdbcType() == Types.NUMERIC || mapping.getJdbcType() == Types.DECIMAL)) {
×
NEW
631
          cs.registerOutParameter(i + 1, mapping.getJdbcType(), mapping.getNumericScale().intValue());
×
632
        } else {
NEW
633
          cs.registerOutParameter(i + 1, mapping.getJdbcType());
×
634
        }
635
      }
636
    }
637
  }
1✔
638

639
  /**
640
   * Handle output parameter results.
641
   *
642
   * @param statementScope
643
   *          the statement scope
644
   * @param resultMap
645
   *          the result map
646
   * @param rs
647
   *          the rs
648
   * @param callback
649
   *          the callback
650
   *
651
   * @throws SQLException
652
   *           the SQL exception
653
   */
654
  private void handleOutputParameterResults(StatementScope statementScope, ResultMap resultMap, ResultSet rs,
655
      RowHandlerCallback callback) throws SQLException {
656
    ResultMap orig = statementScope.getResultMap();
×
657
    try {
658
      statementScope.setResultSet(rs);
×
659
      if (resultMap != null) {
×
660
        statementScope.setResultMap(resultMap);
×
661

662
        // Get Results
663
        while (rs.next()) {
×
664
          Object[] columnValues = resultMap.resolveSubMap(statementScope, rs).getResults(statementScope, rs);
×
665
          callback.handleResultObject(statementScope, columnValues, rs);
×
666
        }
×
667
      }
668
    } finally {
669
      statementScope.setResultSet(null);
×
670
      statementScope.setResultMap(orig);
×
671
    }
672
  }
×
673

674
  /**
675
   * Clean up any batches on the session
676
   *
677
   * @param sessionScope
678
   *          - the session to clean up
679
   */
680
  @Override
681
  public void cleanup(SessionScope sessionScope) {
682
    Batch batch = (Batch) sessionScope.getBatch();
1✔
683
    if (batch != null) {
1✔
684
      batch.cleanupBatch(sessionScope);
1✔
685
      sessionScope.setBatch(null);
1✔
686
    }
687
  }
1✔
688

689
  /**
690
   * Prepare statement.
691
   *
692
   * @param sessionScope
693
   *          the session scope
694
   * @param conn
695
   *          the conn
696
   * @param sql
697
   *          the sql
698
   * @param rsType
699
   *          the rs type
700
   *
701
   * @return the prepared statement
702
   *
703
   * @throws SQLException
704
   *           the SQL exception
705
   */
706
  private PreparedStatement prepareStatement(SessionScope sessionScope, Connection conn, String sql, Integer rsType)
707
      throws SQLException {
708
    SqlMapExecutorDelegate delegate = ((SqlMapClientImpl) sessionScope.getSqlMapExecutor()).getDelegate();
×
709
    if (sessionScope.hasPreparedStatementFor(sql)) {
×
NEW
710
      return sessionScope.getPreparedStatement(sql);
×
711
    }
NEW
712
    PreparedStatement ps = conn.prepareStatement(sql, rsType.intValue(), ResultSet.CONCUR_READ_ONLY);
×
NEW
713
    sessionScope.putPreparedStatement(delegate, sql, ps);
×
NEW
714
    return ps;
×
715
  }
716

717
  /**
718
   * Prepare call.
719
   *
720
   * @param sessionScope
721
   *          the session scope
722
   * @param conn
723
   *          the conn
724
   * @param sql
725
   *          the sql
726
   * @param rsType
727
   *          the rs type
728
   *
729
   * @return the callable statement
730
   *
731
   * @throws SQLException
732
   *           the SQL exception
733
   */
734
  private CallableStatement prepareCall(SessionScope sessionScope, Connection conn, String sql, Integer rsType)
735
      throws SQLException {
736
    SqlMapExecutorDelegate delegate = ((SqlMapClientImpl) sessionScope.getSqlMapExecutor()).getDelegate();
×
737
    if (sessionScope.hasPreparedStatementFor(sql)) {
×
NEW
738
      return (CallableStatement) sessionScope.getPreparedStatement(sql);
×
739
    }
NEW
740
    CallableStatement cs = conn.prepareCall(sql, rsType.intValue(), ResultSet.CONCUR_READ_ONLY);
×
NEW
741
    sessionScope.putPreparedStatement(delegate, sql, cs);
×
NEW
742
    return cs;
×
743
  }
744

745
  /**
746
   * Prepare statement.
747
   *
748
   * @param sessionScope
749
   *          the session scope
750
   * @param conn
751
   *          the conn
752
   * @param sql
753
   *          the sql
754
   *
755
   * @return the prepared statement
756
   *
757
   * @throws SQLException
758
   *           the SQL exception
759
   */
760
  private static PreparedStatement prepareStatement(SessionScope sessionScope, Connection conn, String sql)
761
      throws SQLException {
762
    SqlMapExecutorDelegate delegate = ((SqlMapClientImpl) sessionScope.getSqlMapExecutor()).getDelegate();
1✔
763
    if (sessionScope.hasPreparedStatementFor(sql)) {
1✔
764
      return sessionScope.getPreparedStatement(sql);
1✔
765
    }
766
    PreparedStatement ps = conn.prepareStatement(sql);
1✔
767
    sessionScope.putPreparedStatement(delegate, sql, ps);
1✔
768
    return ps;
1✔
769
  }
770

771
  /**
772
   * Prepare call.
773
   *
774
   * @param sessionScope
775
   *          the session scope
776
   * @param conn
777
   *          the conn
778
   * @param sql
779
   *          the sql
780
   *
781
   * @return the callable statement
782
   *
783
   * @throws SQLException
784
   *           the SQL exception
785
   */
786
  private CallableStatement prepareCall(SessionScope sessionScope, Connection conn, String sql) throws SQLException {
787
    SqlMapExecutorDelegate delegate = ((SqlMapClientImpl) sessionScope.getSqlMapExecutor()).getDelegate();
1✔
788
    if (sessionScope.hasPreparedStatementFor(sql)) {
1!
NEW
789
      return (CallableStatement) sessionScope.getPreparedStatement(sql);
×
790
    }
791
    CallableStatement cs = conn.prepareCall(sql);
1✔
792
    sessionScope.putPreparedStatement(delegate, sql, cs);
1✔
793
    return cs;
1✔
794
  }
795

796
  /**
797
   * Close statement.
798
   *
799
   * @param sessionScope
800
   *          the session scope
801
   * @param ps
802
   *          the ps
803
   */
804
  private static void closeStatement(SessionScope sessionScope, PreparedStatement ps) {
805
    if (ps != null && !sessionScope.hasPreparedStatement(ps)) {
1✔
806
      try {
807
        ps.close();
1✔
NEW
808
      } catch (SQLException e) {
×
809
        // ignore
810
      }
1✔
811
    }
812
  }
1✔
813

814
  /**
815
   * Close result set.
816
   *
817
   * @param rs
818
   *          the rs
819
   */
820
  private static void closeResultSet(ResultSet rs) {
821
    if (rs != null) {
1✔
822
      try {
823
        rs.close();
1✔
824
      } catch (SQLException e) {
×
825
        // ignore
826
      }
1✔
827
    }
828
  }
1✔
829

830
  /**
831
   * Sets the statement timeout.
832
   *
833
   * @param mappedStatement
834
   *          the mapped statement
835
   * @param statement
836
   *          the statement
837
   *
838
   * @throws SQLException
839
   *           the SQL exception
840
   */
841
  private static void setStatementTimeout(MappedStatement mappedStatement, Statement statement) throws SQLException {
842
    if (mappedStatement.getTimeout() != null) {
1!
843
      statement.setQueryTimeout(mappedStatement.getTimeout().intValue());
×
844
    }
845
  }
1✔
846

847
  /**
848
   * The Class Batch.
849
   */
850
  private static class Batch {
851

852
    /** The current sql. */
853
    private String currentSql;
854

855
    /** The statement list. */
856
    private List statementList = new ArrayList<>();
1✔
857

858
    /** The batch result list. */
859
    private List batchResultList = new ArrayList<>();
1✔
860

861
    /** The size. */
862
    private int size;
863

864
    /**
865
     * Create a new batch.
866
     */
867
    public Batch() {
1✔
868
      this.size = 0;
1✔
869
    }
1✔
870

871
    /**
872
     * Getter for the batch size.
873
     *
874
     * @return - the batch size
875
     */
876
    public int getSize() {
877
      return size;
×
878
    }
879

880
    /**
881
     * Add a prepared statement to the batch.
882
     *
883
     * @param statementScope
884
     *          - the request scope
885
     * @param conn
886
     *          - the database connection
887
     * @param sql
888
     *          - the SQL to add
889
     * @param parameters
890
     *          - the parameters for the SQL
891
     *
892
     * @throws SQLException
893
     *           - if the prepare for the SQL fails
894
     */
895
    public void addBatch(StatementScope statementScope, Connection conn, String sql, Object[] parameters)
896
        throws SQLException {
897
      PreparedStatement ps = null;
1✔
898
      if (currentSql != null && currentSql.equals(sql)) {
1✔
899
        int last = statementList.size() - 1;
1✔
900
        ps = (PreparedStatement) statementList.get(last);
1✔
901
      } else {
1✔
902
        ps = prepareStatement(statementScope.getSession(), conn, sql);
1✔
903
        setStatementTimeout(statementScope.getStatement(), ps);
1✔
904
        currentSql = sql;
1✔
905
        statementList.add(ps);
1✔
906
        batchResultList.add(new BatchResult(statementScope.getStatement().getId(), sql));
1✔
907
      }
908
      statementScope.getParameterMap().setParameters(statementScope, ps, parameters);
1✔
909
      ps.addBatch();
1✔
910
      size++;
1✔
911
    }
1✔
912

913
    /**
914
     * TODO (Jeff Butler) - maybe this method should be deprecated in some release, and then removed in some even later
915
     * release. executeBatchDetailed gives much more complete information.
916
     * <p>
917
     * Execute the current session's batch
918
     *
919
     * @return - the number of rows updated
920
     *
921
     * @throws SQLException
922
     *           - if the batch fails
923
     */
924
    public int executeBatch() throws SQLException {
925
      int totalRowCount = 0;
1✔
926
      for (Object element : statementList) {
1✔
927
        PreparedStatement ps = (PreparedStatement) element;
1✔
928
        int[] rowCounts = ps.executeBatch();
1✔
929
        for (int j = 0; j < rowCounts.length; j++) {
1✔
930
          if (rowCounts[j] == Statement.SUCCESS_NO_INFO) {
1!
931
            // do nothing
932
          } else if (rowCounts[j] == Statement.EXECUTE_FAILED) {
1!
933
            throw new SQLException("The batched statement at index " + j + " failed to execute.");
×
934
          } else {
935
            totalRowCount += rowCounts[j];
1✔
936
          }
937
        }
938
      }
1✔
939
      return totalRowCount;
1✔
940
    }
941

942
    /**
943
     * Batch execution method that returns all the information the driver has to offer.
944
     *
945
     * @return a List of BatchResult objects
946
     *
947
     * @throws SQLException
948
     *           if a database access error occurs, or the drive does not support batch statements
949
     * @throws BatchException
950
     *           if the driver throws BatchUpdateException
951
     */
952
    public List executeBatchDetailed() throws SQLException, BatchException {
953
      List answer = new ArrayList<>();
1✔
954
      for (int i = 0, n = statementList.size(); i < n; i++) {
1✔
955
        BatchResult br = (BatchResult) batchResultList.get(i);
1✔
956
        PreparedStatement ps = (PreparedStatement) statementList.get(i);
1✔
957
        try {
958
          br.setUpdateCounts(ps.executeBatch());
1✔
959
        } catch (BatchUpdateException e) {
1✔
960
          StringBuilder message = new StringBuilder();
1✔
961
          message.append("Sub batch number ");
1✔
962
          message.append(i + 1);
1✔
963
          message.append(" failed.");
1✔
964
          if (i > 0) {
1!
965
            message.append(" ");
1✔
966
            message.append(i);
1✔
967
            message.append(" prior sub batch(s) completed successfully, but will be rolled back.");
1✔
968
          }
969
          throw new BatchException(message.toString(), e, answer, br.getStatementId(), br.getSql());
1✔
970
        }
1✔
971
        answer.add(br);
1✔
972
      }
973
      return answer;
1✔
974
    }
975

976
    /**
977
     * Close all the statements in the batch and clear all the statements.
978
     *
979
     * @param sessionScope
980
     *          the session scope
981
     */
982
    public void cleanupBatch(SessionScope sessionScope) {
983
      for (Object element : statementList) {
1✔
984
        PreparedStatement ps = (PreparedStatement) element;
1✔
985
        closeStatement(sessionScope, ps);
1✔
986
      }
1✔
987
      currentSql = null;
1✔
988
      statementList.clear();
1✔
989
      batchResultList.clear();
1✔
990
      size = 0;
1✔
991
    }
1✔
992
  }
993

994
  /**
995
   * Sets the up result object factory.
996
   *
997
   * @param statementScope
998
   *          the new up result object factory
999
   */
1000
  private void setupResultObjectFactory(StatementScope statementScope) {
1001
    SqlMapClientImpl client = (SqlMapClientImpl) statementScope.getSession().getSqlMapClient();
1✔
1002
    ResultObjectFactoryUtil.setupResultObjectFactory(client.getResultObjectFactory(),
1✔
1003
        statementScope.getStatement().getId());
1✔
1004
  }
1✔
1005

1006
  /**
1007
   * Cleanup result object factory.
1008
   */
1009
  private void cleanupResultObjectFactory() {
1010
    ResultObjectFactoryUtil.cleanupResultObjectFactory();
1✔
1011
  }
1✔
1012
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc