KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > jdo > spi > persistence > support > sqlstore > SQLStoreManager


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 /*
25  * SQLStoreManager.java
26  *
27  * Created on March 3, 2000
28  *
29  */

30
31 package com.sun.jdo.spi.persistence.support.sqlstore;
32
33 // use internal version: import com.sun.jdo.api.persistence.support.Transaction;
34

35 import com.sun.jdo.api.persistence.support.*;
36 import com.sun.jdo.spi.persistence.support.sqlstore.database.DBVendorType;
37 import com.sun.jdo.spi.persistence.support.sqlstore.model.*;
38 import com.sun.jdo.spi.persistence.support.sqlstore.sql.RetrieveDescImpl;
39 import com.sun.jdo.spi.persistence.support.sqlstore.sql.UpdateObjectDescImpl;
40 import com.sun.jdo.spi.persistence.support.sqlstore.sql.concurrency.Concurrency;
41 import com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.*;
42 import com.sun.jdo.spi.persistence.utility.I18NHelper;
43 import com.sun.jdo.spi.persistence.utility.StringHelper;
44 import com.sun.jdo.spi.persistence.utility.logging.Logger;
45
46 import java.sql.*;
47 import java.util.*;
48
49 /**
50  * <P>This class connects to a persistent store. It supports
51  * relational databases such as Oracle and MS SQLServer. This class
52  * knows how to generate SQL statements to access and manipulate
53  * objects stored in a relational database.
54  */

55 public class SQLStoreManager implements PersistenceStore {
56
57     /** Cache holding SQLStore model information. */
58     private ConfigCache configCache;
59
60     /** Encapsulates database type. */
61     private DBVendorType vendorType;
62
63     /** The logger. */
64     private static Logger logger = LogHelperSQLStore.getLogger();
65
66     /** The sql logger. */
67     private static Logger sqlLogger = LogHelperSQLStore.getSqlLogger();
68
69     /** I18N message handler. */
70     private final static ResourceBundle messages = I18NHelper.loadBundle(
71             SQLStoreManager.class);
72
73     /** Fetch size for query statements. */
74     private static int fetchSize =
75       Integer.getInteger("com.sun.jdo.spi.persistence.support.sqlstore.SQLStoreManager.fetchSize", // NOI18N
76
-1).intValue(); // -1 not set
77

78     /**
79      * Returns the sqlstore model for class <code>classType</code>.
80      * Sqlstore model information is cached. If the model cache does
81      * not already hold a model instance for the particular class,
82      * a new instance is created, initialized and put into the cache.
83      * The access to the model cache is synchronized.
84      */

85     public PersistenceConfig getPersistenceConfig(Class JavaDoc classType) {
86         if (logger.isLoggable(Logger.FINER)) {
87             logger.finer("sqlstore.sqlstoremanager.getpersistenceconfig",
88                     classType.getName()); // NOI18N
89
}
90         return configCache.getPersistenceConfig(classType);
91     }
92
93     /**
94      * @inheritDoc
95      */

96     public ConfigCache getConfigCache() {
97         return configCache;
98     }
99
100     /**
101      * Executes the list of SQL requests contained in <code>actions</code>.
102      * Requests can be INSERT, UPDATE or DELETE operations.
103      *
104      * @exception JDODataStoreException
105      * Will be thrown in case of errors or if the affected rows are
106      * less than the minimum rows required.
107      */

108     public void execute(PersistenceManager pm, Collection actions) {
109         Iterator iter = actions.iterator();
110
111         while (iter.hasNext()) {
112             ActionDesc action = (ActionDesc) iter.next();
113
114             if (action instanceof UpdateObjectDescImpl) {
115                 UpdateObjectDescImpl request = (UpdateObjectDescImpl) action;
116                 UpdateQueryPlan plan = new UpdateQueryPlan(request, this);
117
118                 plan.build();
119
120                 for (int i = 0, size = plan.statements.size(); i < size; i++) {
121                     UpdateStatement s = (UpdateStatement) plan.statements.get(i);
122
123                     if (s != null) {
124                         executeUpdate(pm, s, request);
125                     }
126                 }
127             } else {
128                 throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
129                                                     "core.generic.notinstanceof", // NOI18N
130
action.getClass().getName(),
131                                                     "UpdateObjectDescImpl")); // NOI18N
132
}
133         }
134     }
135
136     /**
137      *
138      */

139     private void rollbackXact(Transaction tran) {
140
141         try {
142             tran.setRollbackOnly();
143             //tran.rollback();
144
} catch (Exception JavaDoc e) {
145         }
146     }
147
148     /**
149      * Executes the SQL text contained in <code>updateStatement</code>
150      * against the database. Data used for placeholders in the
151      * updateStatement is passed in the <code>updateDesc</code> parameter
152      * and bound to the statement before execution. Can be used for
153      * delete, insert, or update SQL statements, but not for select
154      * SQL statements as these return result values with which
155      * executeUpdate is not prepared to deal.
156      *
157      * @param pm Persistence manager holding the current transaction
158      * and connection.
159      * @param updateStatement The INSERT, UPDATE or DELETE statement.
160      * @param updateDesc Update updateDesc holding the affected state
161      * manager.
162      * @exception JDODataStoreException Will be thrown in case of
163      * errors or if the affected rows are less than the minimum rows
164      * required.
165      */

166     private void executeUpdate(PersistenceManager pm,
167                                UpdateStatement updateStatement,
168                                UpdateObjectDescImpl updateDesc) {
169         int affectedRows = 0;
170         boolean debug = logger.isLoggable();
171
172         if (debug) {
173             logger.fine("sqlstore.sqlstoremanager.executeupdate"); // NOI18N
174
}
175
176         String JavaDoc sqlText = updateStatement.getText();
177         if (sqlText.length() > 0) {
178             if (sqlLogger.isLoggable()) {
179                 sqlLogger.fine(updateStatement.getFormattedSQLText());
180             }
181
182             Transaction tran = (Transaction) pm.currentTransaction();
183             Connection conn = tran.getConnection();
184             DBStatement s = null;
185             boolean preparationSuccessful = false;
186
187             try {
188                 // Statement preparation.
189
s = new DBStatement(conn, sqlText, tran.getUpdateTimeout());
190                 updateStatement.bindInputValues(s);
191                 preparationSuccessful = true;
192
193                 // Excecution.
194
affectedRows = s.executeUpdate();
195
196                 // If the affectedRows is less than the minimum rows required,
197
// we need to abort and throw an exception.
198
if (affectedRows < updateStatement.minAffectedRows) {
199                     // Mark the request failed.
200
updateDesc.setVerificationFailed();
201
202                     rollbackXact(tran);
203                     throwJDOConcurrentAccessException(sqlText);
204                 }
205             } catch (SQLException e) {
206                 // As we want to verify against the data store only,
207
// there is no invalidation necessary if the
208
// exception happened before statement execution.
209
if (preparationSuccessful) {
210                     updateDesc.setVerificationFailed();
211                 }
212
213                 rollbackXact(tran);
214                 throwJDOSqlException(e, updateStatement.getFormattedSQLText());
215             } finally {
216                 close(s);
217                 closeConnection(tran, conn);
218             }
219         }
220
221         if (debug) {
222             logger.fine("sqlstore.sqlstoremanager.executeupdate.exit", // NOI18N
223
new Integer JavaDoc(affectedRows));
224         }
225     }
226
227     /**
228      *
229      */

230     public Class JavaDoc getClassByOidClass(Class JavaDoc oidType) {
231         return configCache.getClassByOidClass(oidType);
232     }
233
234     /**
235      *
236      */

237     public StateManager getStateManager(Class JavaDoc classType) {
238         ClassDesc c = (ClassDesc) getPersistenceConfig(classType);
239
240         if (c != null) {
241             return c.newStateManagerInstance(this);
242         }
243
244         return null;
245     }
246
247     /**
248      * Returns a new retrieve descriptor for anexternal (user) query.
249      *
250      * @param classType Type of the persistence capable class to be queried.
251      * @return A new retrieve descriptor for anexternal (user) query.
252      */

253     public RetrieveDesc getRetrieveDesc(Class JavaDoc classType) {
254         return new RetrieveDescImpl(classType, (ClassDesc) getPersistenceConfig(classType));
255     }
256
257     /**
258      * Returns a new retrieve descriptor for anexternal (user) query.
259      * This retrieve descriptor can be used to query for the foreign
260      * field <code>name</code>.
261      *
262      * @param fieldName Name of the foreign field to be queried.
263      * @param classType Persistence capable class including <code>fieldName</code>.
264      * @return A new retrieve descriptor for anexternal (user) query.
265      */

266     public RetrieveDesc getRetrieveDesc(String JavaDoc fieldName, Class JavaDoc classType) {
267         ClassDesc c = (ClassDesc) getPersistenceConfig(classType);
268
269         if (c != null) {
270             FieldDesc f = c.getField(fieldName);
271
272             if (f instanceof ForeignFieldDesc) {
273                 ForeignFieldDesc ff = (ForeignFieldDesc) f;
274                 return getRetrieveDesc(ff.foreignConfig.getPersistenceCapableClass());
275             }
276         }
277
278         return null;
279     }
280
281     /**
282      */

283     public UpdateObjectDesc getUpdateObjectDesc(Class JavaDoc classType) {
284           return new UpdateObjectDescImpl(classType);
285     }
286
287     /**
288      * @param databaseMetaData Instance of DatabaseMetaData
289      * @param identifier identifier of the caller creating a new instance
290      * of SQLStoreManager. Typically this is identifier of
291      * PersistenceManagerFacory initializing this SQLStoreManager.
292      */

293     public SQLStoreManager(DatabaseMetaData databaseMetaData,
294         String JavaDoc identifier) {
295         super();
296         configCache = new ConfigCacheImpl();
297         setVendorType(databaseMetaData, identifier);
298     }
299
300     /**
301      * @param databaseMetaData Instance of DatabaseMetaData
302      * @param identifier identifier of the caller creating a new instance
303      * of SQLStoreManager.
304      * @see SQLStoreManager#SQLStoreManager(DatabaseMetaData, String)
305      */

306     private void setVendorType(DatabaseMetaData databaseMetaData,
307         String JavaDoc identifier) {
308         try {
309             vendorType = new DBVendorType(databaseMetaData, identifier);
310
311             if (logger.isLoggable()) {
312                 logger.fine("sqlstore.sqlstoremanager.vendortype",vendorType.getName()); // NOI18N
313

314             }
315
316         } catch (Exception JavaDoc e) {
317             if (e instanceof JDOException) {
318                 throw (JDOException) e;
319             } else {
320                 throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
321                         "core.configuration.getvendortypefailed"), e); // NOI18N
322
}
323         }
324     }
325
326     public DBVendorType getVendorType() {
327         return vendorType;
328     }
329
330     /**
331      * The retrieve method builds and executes the SQL query described by
332      * the action parameter.
333      *
334      * @param action
335      * The action parameter holds the RetrieveDesc describing what
336      * should be selected from the database.
337      *
338      * @param parameters
339      * Query parameters.
340      */

341     public Object JavaDoc retrieve(PersistenceManager pm, RetrieveDesc action, ValueFetcher parameters) {
342
343         if (action == null) {
344             throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
345                     "core.generic.nullparam", "action")); // NOI18N
346
}
347
348         if (!(action instanceof RetrieveDescImpl)) {
349             throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
350                     "core.generic.notinstanceof", // NOI18N
351
action.getClass().getName(),
352                     "RetrieveDescImpl")); // NOI18N
353
}
354
355         RetrieveDescImpl retrieveAction = ((RetrieveDescImpl) action);
356         ClassDesc config = retrieveAction.getConfig();
357         Concurrency concurrency = config.getConcurrency(pm.isOptimisticTransaction());
358         SelectQueryPlan plan = retrieveAction.buildQueryPlan(this, concurrency);
359         ArrayList statements = plan.getStatements();
360         Object JavaDoc result = null;
361
362         SelectStatement s = (SelectStatement) statements.get(0);
363         result = executeQuery(pm, s, concurrency, parameters);
364
365         if ((plan.options & RetrieveDescImpl.OPT_AGGREGATE) == 0) {
366             // This was a regular query, no aggregate.
367

368             if ((plan.options & RetrieveDescImpl.OPT_DISTINCT) > 0) {
369                 // Perform manual DISTINCT if required
370

371                 if (((plan.options & RetrieveDescImpl.OPT_FOR_UPDATE) > 0 &&
372                         !vendorType.isDistinctSupportedWithUpdateLock()) ) {
373
374                     HashSet hash = new HashSet();
375                     for (Iterator iter = ((Collection)result).iterator(); iter.hasNext(); ) {
376                         Object JavaDoc temp = iter.next();
377                         if (!hash.contains(temp)) {
378                             hash.add(temp);
379                         } else {
380                             iter.remove();
381                         }
382                     }
383                 }
384             }
385         }
386
387         return result;
388     }
389
390     /**
391      * The executeQuery method prepares and sends the SQL text contained in the
392      * <code>statement</code> to the DB. Data used for placeholders in the
393      * <code>statement</code> is passed in <code>parameters</code> and bound to
394      * the statement before execution. The SQL statement is run within
395      * a cursor and any result values returned are packaged into
396      * BusinessClasses of the appropriate sub-class and returned as the
397      * functional result.
398      *
399      * @param statement
400      * The statement contains the text of the SQL statement to be executed.
401      * @param parameters Query parameters.
402      * @return The result of this query.
403      */

404     private Object JavaDoc executeQuery(PersistenceManager pm,
405                                 SelectStatement statement,
406                                 Concurrency concurrency,
407                                 ValueFetcher parameters) {
408
409         Object JavaDoc result = null;
410         boolean debug = logger.isLoggable();
411         if (debug) {
412             logger.fine("sqlstore.sqlstoremanager.executeQuery"); // NOI18N
413
}
414
415         String JavaDoc sqlText = statement.getText();
416         if (sqlText.length() > 0) {
417             if (sqlLogger.isLoggable()) {
418                 sqlLogger.fine(statement.getFormattedSQLText(parameters));
419             }
420
421             Transaction tran = null;
422             if (concurrency != null) {
423                 // This is a no op currently as all Concurrency* classes
424
// have no code in this method and always returns null.
425
tran = concurrency.suspend();
426             }
427
428             if (tran == null) {
429                 tran = (Transaction) pm.currentTransaction();
430             }
431
432             ResultSet resultData = null;
433             DBStatement s = null;
434             Connection conn = tran.getConnection();
435             try {
436                 // prepare Statement including SELECT Statement timeout
437
s = new DBStatement(conn, sqlText, tran.getQueryTimeout());
438
439                 // Set the inputValues values (constraints in this case).
440
statement.bindInputValues(s, parameters);
441
442                 // Tests setting the fetch size with values 0, 16, 32, 64,
443
// showed degradations only.
444
//s.handle.setFetchSize(<fetch_size>);
445
//s.handle.setFetchDirection(ResultSet.FETCH_FORWARD);
446
if (fetchSize > -1) {
447                     s.getPreparedStatement().setFetchSize(fetchSize);
448                 }
449
450                 if (statement.isColumnTypeDefinitionNeeded()) {
451                     vendorType.getSpecialDBOperation().defineColumnTypeForResult(
452                         s.getPreparedStatement(), statement.getColumnRefs());
453                 }
454
455                 resultData = s.executeQuery();
456
457                 if (concurrency != null) {
458                     // This is a no op currently as all Concurrency* classes
459
// have no code in this method.
460
concurrency.resume(tran);
461                 }
462
463                 SelectQueryPlan plan = (SelectQueryPlan) statement.getQueryPlan();
464                 result = plan.getResult(pm, resultData);
465             } catch (SQLException e) {
466                 throwJDOSqlException(e, statement.getFormattedSQLText(parameters));
467             } finally {
468                 close(resultData);
469                 close(s);
470                 closeConnection(tran, conn);
471             }
472         }
473
474         if (debug) {
475             logger.fine("sqlstore.sqlstoremanager.executeQuery.exit"); // NOI18N
476
}
477
478         return result;
479     }
480
481     // -------------------------------------
482
// Methods added to support batch update
483
// -------------------------------------
484

485     /**
486      * Retrieves the update query plan for the specified request and
487      * calls executeUpdateBatch for all statements in this plan.
488      * @param pm the persistence manager
489      * @param request the request corresponding with the current state manager
490      * @param forceFlush all in the update query plan must be executed
491      */

492     public void executeBatch(PersistenceManager pm,
493                              UpdateObjectDesc request,
494                              boolean forceFlush)
495     {
496         boolean cleanup = true;
497         UpdateObjectDescImpl objectRequest = null;
498
499         if (request instanceof UpdateObjectDescImpl) {
500             objectRequest = (UpdateObjectDescImpl) request;
501         } else {
502             throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
503                 "core.generic.notinstanceof", // NOI18N
504
request.getClass().getName(),
505                 "UpdateObjectDescImpl")); // NOI18N
506
}
507
508         ClassDesc config = objectRequest.getConfig();
509         UpdateQueryPlan plan = config.getUpdateQueryPlan(objectRequest, this);
510         Transaction tran = (Transaction) pm.currentTransaction();
511         Connection conn = tran.getConnection();
512
513         // Flag 'doFlush' indicates that executeUpdateBatch should call
514
// executeBatch on the PreparedStatement. 'doFlush' is true, if
515
// - forceFlush is true, this means we cannot reuse the
516
// DBStatement for the next state manager, OR
517
// - the batch threshold is exeeceded.
518
boolean doFlush = forceFlush || plan.checkBatchThreshold(tran);
519
520         try {
521             for (int i = 0, size = plan.statements.size(); i < size; i++) {
522                 UpdateStatement s = (UpdateStatement) plan.statements.get(i);
523                 executeUpdateBatch(tran, conn, s, objectRequest, doFlush);
524             }
525
526             // At this point we know the batch update was successful.
527
// We close DBStatements and it's related PreparedStatement, if
528
// they are not going to be reused for flushing the next state
529
// manager. In this case the flag 'forceFlush' is true. So we
530
// can do the cleanup, if 'forceFlush' is true. We cannot use
531
// the flag 'doFlush', because this flag might be true, because
532
// we exceeded the batch threshold. In this case we want to
533
// keep the DBStatement.
534
cleanup = forceFlush;
535         } finally {
536             if (cleanup)
537                 closeDBStatements(plan, tran);
538             closeConnection(tran, conn);
539         }
540     }
541
542     /**
543      * Binds the specified update descriptor to the specified statement and
544      * calls method addBatch on this statement.
545      * @param tran the transaction
546      * @param conn the connection
547      * @param updateStatement the statement
548      * @param updateDesc the update descriptor
549      * @param doFlush determines if the statement must be executed
550      */

551     private void executeUpdateBatch(Transaction tran,
552                                     Connection conn,
553                                     UpdateStatement updateStatement,
554                                     UpdateObjectDescImpl updateDesc,
555                                     boolean doFlush)
556     {
557         int[] affectedRows = null;
558         boolean debug = logger.isLoggable();
559
560         if (debug) {
561             logger.fine("sqlstore.sqlstoremanager.executeupdatebatch"); // NOI18N
562
}
563
564         String JavaDoc sqlText = updateStatement.getText();
565         if (sqlText.length() > 0) {
566             if (sqlLogger.isLoggable()) {
567                 String JavaDoc formattedText = updateStatement.getFormattedSQLText(updateDesc);
568                 if (doFlush) {
569                     sqlLogger.fine("sqlstore.sqlstoremanager.executeupdatebatch.flushbatch", formattedText);
570                 } else {
571                     sqlLogger.fine("sqlstore.sqlstoremanager.executeupdatebatch.addbatch", formattedText);
572                 }
573             }
574
575             DBStatement s = null;
576
577             try {
578                 // Batch preparation.
579
s = updateStatement.getDBStatement(tran, conn);
580                 updateStatement.bindInputColumns(s, updateDesc);
581                 s.addBatch();
582
583                 if (doFlush) {
584                     // Execution.
585
affectedRows = s.executeBatch();
586
587                     // check affectedRows as returned by the database
588
for (int i = 0; i < affectedRows.length; i++) {
589                         // If the affectedRows is less than the minimum rows required,
590
// we need to abort and throw an exception.
591
if (affectedRows[i] < updateStatement.minAffectedRows &&
592                             affectedRows[i] != java.sql.Statement.SUCCESS_NO_INFO) {
593
594                             rollbackXact(tran);
595                             throwJDOConcurrentAccessException(sqlText);
596                         }
597                     }
598                 }
599             } catch (SQLException e) {
600                 rollbackXact(tran);
601                 throwJDOSqlException(e, sqlText);
602             }
603         }
604
605         if (debug) {
606             if (doFlush) {
607                 logger.fine("sqlstore.sqlstoremanager.executeupdatebatch.exit.flush", '[' + // NOI18N
608
StringHelper.intArrayToSeparatedList(affectedRows, ",") + ']'); //NOI18N
609
} else {
610                 logger.fine("sqlstore.sqlstoremanager.executeupdatebatch.exit"); //NOI18N
611
}
612         }
613     }
614
615     // -------------------------------------
616
// Static support methods
617
// -------------------------------------
618

619     /**
620      * Constructs the exception message including the executed SQL statement
621      * <code>sqlText</code> and throws a JDODataStoreException passing the
622      * original exception.
623      *
624      * @param e Exception from the data store.
625      * @param sqlText Executed SQL statement.
626      */

627     static private void throwJDOSqlException(SQLException e, String JavaDoc sqlText) {
628
629         String JavaDoc exceptionMessage = I18NHelper.getMessage(messages,
630             "core.persistencestore.jdbcerror", sqlText); // NOI18N
631

632         throw new JDODataStoreException(exceptionMessage, e);
633     }
634
635     /**
636      * Determines the SQL operation (update/delete) from the
637      * <code>sqlText</code> parameter and throws a JDODataStoreException.
638      *
639      * @param sqlText Executed SQL statement.
640      */

641     static private void throwJDOConcurrentAccessException(String JavaDoc sqlText) {
642         String JavaDoc operation = sqlText.substring(0, sqlText.indexOf(' ')); // NOI18N
643

644         throw new JDODataStoreException(I18NHelper.getMessage(messages,
645                       "core.store.concurrentaccess", operation)); // NOI18N
646
}
647
648     /**
649      * Closes the JDBC ResultSet <code>r</code>.
650      * SQLExceptions are catched and logged.
651      */

652     static private void close(ResultSet r) {
653         if (r != null) {
654             try {
655                 r.close();
656             } catch (SQLException ex) {
657                 // only log exception
658
logger.finest(I18NHelper.getMessage(messages,
659                         "sqlstore.sqlstoremanager.errorcloseresultset", // NOI18N
660
ex.getLocalizedMessage()));
661             }
662         }
663     }
664
665     /**
666      * Closes the JDBC Statement <code>s</code>.
667      * SQLExceptions are catched and logged.
668      */

669     static private void close(DBStatement s) {
670         if (s != null) {
671             try {
672                 s.close();
673             } catch (SQLException ex) {
674                 // only log exception
675
logger.finest(I18NHelper.getMessage(messages,
676                         "sqlstore.sqlstoremanager.errorclosestatement", // NOI18N
677
ex.getLocalizedMessage()));
678             }
679         }
680     }
681
682     /**
683      * Delegates the closure of the JDBC connection <code>c</code>
684      * to the transaction <code>t</code>.
685      */

686     static private void closeConnection(Transaction t, Connection c) {
687         if (t != null && c != null) {
688             t.releaseConnection();
689         }
690     }
691
692     /**
693      * Removes all DBStatements for specified plan and closes the JDBC Statement
694      * wrapped by the DBStatement.
695      */

696     static private void closeDBStatements(UpdateQueryPlan plan, Transaction tran) {
697         if ((plan != null) && (tran != null)) {
698             for (Iterator i = plan.getStatements().iterator(); i.hasNext(); ) {
699                 UpdateStatement updateStmt = (UpdateStatement)i.next();
700                 DBStatement s = updateStmt.removeDBStatement(tran);
701                 close(s);
702             }
703         }
704     }
705
706 }
707
Popular Tags