KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > internal > databaseaccess > DatabaseAccessor


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
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
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 in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21 // Copyright (c) 1998, 2006, Oracle. All rights reserved.
22
package oracle.toplink.essentials.internal.databaseaccess;
23
24 import java.util.*;
25 import java.sql.*;
26 import java.io.*;
27 import oracle.toplink.essentials.internal.helper.*;
28 import oracle.toplink.essentials.queryframework.*;
29 import oracle.toplink.essentials.exceptions.*;
30 import oracle.toplink.essentials.sessions.DatabaseLogin;
31 import oracle.toplink.essentials.internal.localization.*;
32 import oracle.toplink.essentials.logging.SessionLog;
33 import oracle.toplink.essentials.sessions.Login;
34 import oracle.toplink.essentials.sessions.SessionProfiler;
35 import oracle.toplink.essentials.sessions.DatabaseRecord;
36 import oracle.toplink.essentials.internal.sessions.AbstractRecord;
37 import oracle.toplink.essentials.internal.sessions.AbstractSession;
38
39 /**
40  * INTERNAL:
41  * DatabaseAccessor is private to TopLink. It encapsulates low level database operations (such as executing
42  * SQL and reading data by row). Database accessor defines a protocol by which TopLink may invoke these
43  * operations. <p>
44  * DatabaseAccessor also defines a single reference through which all configuration dependent behaviour may
45  * be invoked. <p>
46  *
47  * DabaseAccessor implements the following behavior. <ul>
48  * <li> Connect and disconnect from the database.
49  * <li> Execute SQL statements on the database, returning results.
50  * <li> Handle auto-commit and transactions.
51  * </ul>
52  * DatabaseAccessor dispatches the following protocols to its platform reference. <ul>
53  * <li> Provision of database platform specific type names.
54  * </ul>
55  * DatabaseAccessor dispatches the following protocols to the schema object. <ul>
56  * <li> Creation and deletion of schema objects.
57  * </ul>
58  * @see DatabasePlatform
59  * @since TOPLink/Java 1.0
60  */

61 public class DatabaseAccessor extends DatasourceAccessor {
62
63     /** PERF: Backdoor to disabling dynamic statements. Reverts to old prepared statement usage if set. */
64     public static boolean shouldUseDynamicStatements = true;
65
66     /** Stores statement handles for common used prepared statements. */
67     protected Hashtable statementCache;
68
69     /** Cache of the connection's java.sql.DatabaseMetaData */
70     protected DatabaseMetaData metaData;
71
72     // Bug 2804663 - Each DatabaseAccessor holds on to its own LOBValueWriter instance
73
protected LOBValueWriter lobWriter;
74
75     /**
76      * PERF: Option to allow concurrent thread processing of result sets.
77      * This allows the objects to be built while the rows are being fetched.
78      */

79     protected boolean shouldUseThreadCursors;
80
81     /** PERF: Cache the statement object for dynamic SQL execution. */
82     protected Statement dynamicStatement;
83     protected boolean isDynamicStatementInUse;
84
85     public DatabaseAccessor() {
86         super();
87         this.statementCache = new Hashtable(50);
88         this.lobWriter = null;
89         this.shouldUseThreadCursors = false;
90         this.isDynamicStatementInUse = false;
91     }
92
93     /**
94      * Execute any deferred select calls stored in the LOBValueWriter instance.
95      * This method will typically be called by the CallQueryMechanism object.
96      * Bug 2804663.
97      *
98      * @see oracle.toplink.essentials.internal.helper.LOBValueWriter
99      * @see oracle.toplink.essentials.internal.queryframework.CallQueryMechanism#insertObject()
100      */

101     public void flushSelectCalls(AbstractSession session) {
102         if (lobWriter != null) {
103             lobWriter.buildAndExecuteSelectCalls(session);
104         }
105     }
106
107     /**
108      * Return the LOBValueWriter instance. Lazily initialize the instance.
109      * Bug 2804663.
110      *
111      * @see oracle.toplink.essentials.internal.helper.LOBValueWriter
112      */

113     public LOBValueWriter getLOBWriter() {
114         if (lobWriter == null) {
115             lobWriter = new LOBValueWriter(this);
116         }
117         return lobWriter;
118     }
119
120     /**
121      * Allocate a statement for dynamic SQL execution.
122      * Either return the cached dynamic statement, or a new statement.
123      * This statement must be released after execution.
124      */

125     public synchronized Statement allocateDynamicStatement() throws SQLException {
126         if (dynamicStatement == null) {
127             dynamicStatement = getConnection().createStatement();
128         }
129         if (isDynamicStatementInUse()) {
130             return getConnection().createStatement();
131         }
132         setIsDynamicStatementInUse(true);
133         return dynamicStatement;
134     }
135
136     /**
137      * Return the cached statement for dynamic SQL execution is in use.
138      * Used to handle concurrency for the dynamic statement, this
139      * method must only be called from within a synchronized method/block.
140      */

141     public boolean isDynamicStatementInUse() {
142         return isDynamicStatementInUse;
143     }
144
145     /**
146      * Set if the cached statement for dynamic SQL execution is in use.
147      * Used to handle concurrency for the dynamic statement.
148      */

149     public synchronized void setIsDynamicStatementInUse(boolean isDynamicStatementInUse) {
150         this.isDynamicStatementInUse = isDynamicStatementInUse;
151     }
152
153     /**
154      * Begin a transaction on the database. This means toggling the auto-commit option.
155      */

156     public void basicBeginTransaction(AbstractSession session) throws DatabaseException {
157         try {
158             if (getPlatform().supportsAutoCommit()) {
159                 getConnection().setAutoCommit(false);
160             } else {
161                 getPlatform().beginTransaction(this);
162             }
163         } catch (SQLException exception) {
164             throw DatabaseException.sqlException(exception, this, session);
165         }
166     }
167
168     /**
169      * If logging is turned on and the JDBC implementation supports meta data then display connection info.
170      */

171     protected void buildConnectLog(AbstractSession session) {
172         try {
173             // Log connection information.
174
if (session.shouldLog(SessionLog.CONFIG, SessionLog.CONNECTION)) {// Avoid printing if no logging required.
175
DatabaseMetaData metaData = getConnectionMetaData();
176                 Object JavaDoc[] args = { metaData.getURL(), metaData.getUserName(), metaData.getDatabaseProductName(), metaData.getDatabaseProductVersion(), metaData.getDriverName(), metaData.getDriverVersion(), Helper.cr() + "\t" };
177                 session.log(SessionLog.CONFIG, SessionLog.CONNECTION, "connected_user_database_driver", args, this);
178             }
179         } catch (SQLException exception) {
180             // Some databases do not support metadata, ignore exception.
181
session.warning("JDBC_driver_does_not_support_meta_data", SessionLog.CONNECTION);
182         }
183     }
184
185     /**
186      * Build a row from the output parameters of a sp call.
187      */

188     public AbstractRecord buildOutputRow(CallableStatement statement, DatabaseCall call, AbstractSession session) throws DatabaseException {
189         try {
190             return call.buildOutputRow(statement);
191         } catch (SQLException exception) {
192             throw DatabaseException.sqlException(exception, call, this, session);
193         }
194     }
195
196     /**
197      * Return the field sorted in the correct order coresponding to the result set.
198      * This is used for cursored selects where custom sql was provided.
199      * If the fields passed in are null, this means that the field are not known and should be
200      * built from the column names. This case occurs for DataReadQuery's.
201      */

202     public Vector buildSortedFields(Vector fields, ResultSet resultSet, AbstractSession session) throws DatabaseException {
203         Vector sortedFields;
204         try {
205             Vector columnNames = getColumnNames(resultSet, session);
206             if (fields == null) {// Means fields not known.
207
sortedFields = new Vector(columnNames.size());
208                 for (Enumeration columnNamesEnum = columnNames.elements();
209                          columnNamesEnum.hasMoreElements();) {
210                     sortedFields.addElement(new DatabaseField((String JavaDoc)columnNamesEnum.nextElement()));
211                 }
212             } else {
213                 sortedFields = sortFields(fields, columnNames);
214             }
215         } catch (SQLException exception) {
216             throw DatabaseException.sqlException(exception, this, session);
217         }
218         return sortedFields;
219     }
220
221     /**
222      * Connect to the database.
223      * Exceptions are caught and re-thrown as TopLink exceptions.
224      * Must set the transaction isolation.
225      */

226     protected void connect(Login login) throws DatabaseException {
227         super.connect(login);
228         checkTransactionIsolation();
229     }
230
231     /**
232      * Check to see if the transaction isolation needs to
233      * be set for the newly created connection. This must
234      * be done outside of a transaction.
235      * Exceptions are caught and re-thrown as TopLink exceptions.
236      */

237     protected void checkTransactionIsolation() throws DatabaseException {
238         if ((!isInTransaction()) && (getLogin() != null) && (((DatabaseLogin)getLogin()).getTransactionIsolation() != -1)) {
239             try {
240                 getConnection().setTransactionIsolation(((DatabaseLogin)getLogin()).getTransactionIsolation());
241             } catch (java.sql.SQLException JavaDoc sqlEx) {
242                 throw DatabaseException.sqlException(sqlEx, this, null);
243             }
244         }
245     }
246
247     /**
248      * Flush the statement cache.
249      * Each statement must first be closed.
250      */

251     public void clearStatementCache(AbstractSession session) {
252         if (hasStatementCache()) {
253             for (Enumeration statements = getStatementCache().elements();
254                      statements.hasMoreElements();) {
255                 Statement statement = (Statement)statements.nextElement();
256                 try {
257                     statement.close();
258                 } catch (SQLException exception) {
259                     // an exception can be raised if
260
// a statement is closed twice.
261
}
262             }
263             setStatementCache(null);
264         }
265
266         // Close cached dynamic statement.
267
if (this.dynamicStatement != null) {
268             try {
269                 this.dynamicStatement.close();
270             } catch (SQLException exception) {
271                 // an exception can be raised if
272
// a statement is closed twice.
273
}
274             this.dynamicStatement = null;
275             this.setIsDynamicStatementInUse(false);
276         }
277     }
278
279     /**
280      * Close the result set of the cursored stream.
281      */

282     public void closeCursor(ResultSet resultSet) throws DatabaseException {
283         try {
284             resultSet.close();
285         } catch (SQLException exception) {
286             throw DatabaseException.sqlException(exception, this, null);
287         }
288     }
289
290     /**
291      * INTERNAL:
292      * Closes a PreparedStatment (which is supposed to close it's current resultSet).
293      * Factored out to simplify coding and handle exceptions.
294      */

295     public void closeStatement(Statement statement, AbstractSession session) throws SQLException {
296         if (statement == null) {
297             decrementCallCount();
298             return;
299         }
300
301         try {
302             session.startOperationProfile(SessionProfiler.STATEMENT_EXECUTE);
303             statement.close();
304         } finally {
305             session.endOperationProfile(SessionProfiler.STATEMENT_EXECUTE);
306             decrementCallCount();
307             // If this is the cached dynamic statement, release it.
308
if (statement == this.dynamicStatement) {
309                 this.dynamicStatement = null;
310                 // The dynamic statement is cached and only closed on disconnect.
311
setIsDynamicStatementInUse(false);
312             }
313         }
314     }
315
316     /**
317      * Commit a transaction on the database. First flush any batched statements.
318      */

319     public void commitTransaction(AbstractSession session) throws DatabaseException {
320         this.writesCompleted(session);
321         super.commitTransaction(session);
322     }
323
324     /**
325      * Commit a transaction on the database. This means toggling the auto-commit option.
326      */

327     public void basicCommitTransaction(AbstractSession session) throws DatabaseException {
328         try {
329             if (getPlatform().supportsAutoCommit()) {
330                 getConnection().commit();
331                 getConnection().setAutoCommit(true);
332             } else {
333                 getPlatform().commitTransaction(this);
334             }
335         } catch (SQLException exception) {
336             throw DatabaseException.sqlException(exception, this, session);
337         }
338     }
339
340     /**
341      * Advance the result set and return a DatabaseRow populated
342      * with values from the next valid row in the result set. Intended solely
343      * for cursored stream support.
344      */

345     public AbstractRecord cursorRetrieveNextRow(Vector fields, ResultSet resultSet, AbstractSession session) throws DatabaseException {
346         try {
347             if (resultSet.next()) {
348                 return fetchRow(fields, resultSet, resultSet.getMetaData(), session);
349             } else {
350                 return null;
351             }
352         } catch (SQLException exception) {
353             throw DatabaseException.sqlException(exception, this, session);
354         }
355     }
356
357     /**
358      * Advance the result set and return a DatabaseRow populated
359      * with values from the next valid row in the result set. Intended solely
360      * for scrollable cursor support.
361      */

362     public AbstractRecord cursorRetrievePreviousRow(Vector fields, ResultSet resultSet, AbstractSession session) throws DatabaseException {
363         try {
364             if (resultSet.previous()) {
365                 return fetchRow(fields, resultSet, resultSet.getMetaData(), session);
366             } else {
367                 return null;
368             }
369         } catch (SQLException exception) {
370             throw DatabaseException.sqlException(exception, this, session);
371         }
372     }
373
374     /**
375      * Close the connection.
376      */

377     public void closeDatasourceConnection() throws DatabaseException {
378         try {
379             getConnection().close();
380         } catch (SQLException exception) {
381             throw DatabaseException.sqlException(exception, this, null);
382         }
383     }
384
385     /**
386      * Disconnect from the datasource.
387      * Added for bug 3046465 to ensure the statement cache is cleared
388      */

389     public void disconnect(AbstractSession session) throws DatabaseException {
390         clearStatementCache(session);
391         super.disconnect(session);
392     }
393
394     /**
395      * Close the accessor's connection.
396      * This is used only for external connection pooling
397      * when it is intended for the connection to be reconnected in the future.
398      */

399     public void closeConnection() {
400         // Unfortunately do not have the session to pass, fortunately it is not used.
401
clearStatementCache(null);
402         super.closeConnection();
403     }
404
405     /**
406      * Execute the TopLink dynamicly batch/concat statement.
407      */

408     protected void executeBatchedStatement(PreparedStatement statement, AbstractSession session) throws DatabaseException {
409         try {
410             executeDirectNoSelect(statement, null, session);
411         } catch (RuntimeException JavaDoc exception) {
412             try {// Ensure that the statement is closed, but still ensure that the real exception is thrown.
413
closeStatement(statement, session);
414             } catch (SQLException closeException) {
415             }
416
417             throw exception;
418         }
419
420         // This is in seperate try block to ensure that the real exception is not masked by the close exception.
421
try {
422             closeStatement(statement, session);
423         } catch (SQLException exception) {
424             throw DatabaseException.sqlException(exception, this, session);
425         }
426     }
427
428     /**
429      * Execute the call.
430      * The execution can differ slightly depending on the type of call.
431      * The call may be parameterized where the arguments are in the translation row.
432      * The row will be empty if there are no parameters.
433      * @return depending of the type either the row count, row or vector of rows.
434      */

435     public Object JavaDoc executeCall(Call call, AbstractRecord translationRow, AbstractSession session) throws DatabaseException {
436         // Keep complete implementation.
437
return basicExecuteCall(call, translationRow, session);
438     }
439
440     /**
441      * Execute the call.
442      * The execution can differ slightly depending on the type of call.
443      * The call may be parameterized where the arguments are in the translation row.
444      * The row will be empty if there are no parameters.
445      * @return depending of the type either the row count, row or vector of rows.
446      */

447     public Object JavaDoc basicExecuteCall(Call call, AbstractRecord translationRow, AbstractSession session) throws DatabaseException {
448         Statement statement = null;
449         Object JavaDoc result = null;
450         DatabaseCall dbCall = null;
451         ResultSet resultSet = null;// only used if this is a read query
452
try {
453             dbCall = (DatabaseCall)call;
454         } catch (ClassCastException JavaDoc e) {
455             throw QueryException.invalidDatabaseCall(call);
456         }
457
458         // If the login is null, then this accessor has never been connected.
459
if (getLogin() == null) {
460             throw DatabaseException.databaseAccessorNotConnected();
461         }
462
463         try {
464             incrementCallCount(session);
465             if (session.shouldLog(SessionLog.FINE, SessionLog.SQL)) {// Avoid printing if no logging required.
466
session.log(SessionLog.FINE, SessionLog.SQL, dbCall.getLogString(this), (Object JavaDoc[])null, this, false);
467             }
468             session.startOperationProfile(SessionProfiler.SQL_PREPARE);
469             try {
470                 statement = dbCall.prepareStatement(this, translationRow, session);
471             } finally {
472                 session.endOperationProfile(SessionProfiler.SQL_PREPARE);
473             }
474
475             // effectively this means that someone is executing an update type query.
476
if (dbCall.isNothingReturned()) {
477                 result = executeNoSelect(dbCall, statement, session);
478                 if (dbCall.isLOBLocatorNeeded()) {
479                     // add original (insert or update) call to the LOB locator
480
// Bug 2804663 - LOBValueWriter is no longer a singleton
481
getLOBWriter().addCall(dbCall);
482                 }
483             } else if (!dbCall.getReturnsResultSet() || (dbCall.getReturnsResultSet() && dbCall.shouldBuildOutputRow())) {
484                 result = session.getPlatform().executeStoredProcedure(dbCall, (PreparedStatement)statement, this, session);
485             } else {// not a stored procedure
486
resultSet = executeSelect(dbCall, statement, session);
487                 if (dbCall.getFirstResult() != 0) {
488                     resultSet.absolute(dbCall.getFirstResult());
489                 }
490                 ResultSetMetaData metaData = resultSet.getMetaData();
491                 dbCall.matchFieldOrder(resultSet, this, session);
492
493                 if (dbCall.isCursorReturned()) {
494                     dbCall.setStatement(statement);
495                     dbCall.setResult(resultSet);
496                     return dbCall;
497                 }
498
499                 session.startOperationProfile(SessionProfiler.ROW_FETCH);
500                 try {
501                     if (dbCall.isOneRowReturned()) {
502                         if (resultSet.next()) {
503                             if (dbCall.isLOBLocatorNeeded()) {
504                                 //if Oracle BLOB/CLOB field is being written, and the thin driver is used, the driver 4k
505
//limit bug prevent the call from directly writing to the table if the LOB value size exceeds 4k.
506
//Instead, a LOB locator is retrieved and value is then piped into the table through the locator.
507
// Bug 2804663 - LOBValueWriter is no longer a singleton
508
getLOBWriter().fetchLocatorAndWriteValue(dbCall, resultSet);
509                             } else {
510                                 result = fetchRow(dbCall.getFields(), resultSet, metaData, session);
511                             }
512                             if (resultSet.next()) {
513                                 // Raise more rows event, some apps may interpret as error or warning.
514
session.getEventManager().moreRowsDetected(dbCall);
515                             }
516                         } else {
517                             result = null;
518                         }
519                     } else {
520                         boolean hasNext = resultSet.next();
521                         Vector results = null;
522
523                         // PERF: Optimize out simple empty case.
524
if (hasNext) {
525                             if (shouldUseThreadCursors()) {
526                                 // If using threading return the cursored list,
527
// do not close the result or statement as the rows are being fetched by the thread.
528
return buildThreadCursoredResult(dbCall, resultSet, statement, metaData, session);
529                             } else {
530                                 results = new Vector(20);
531                                 while (hasNext) {
532                                     results.addElement(fetchRow(dbCall.getFields(), resultSet, metaData, session));
533                                     hasNext = resultSet.next();
534                                 }
535                             }
536                         } else {
537                             results = new Vector(0);
538                         }
539                         result = results;
540                     }
541                     resultSet.close();// This must be closed incase the statement is cached and not closed.
542
} finally {
543                     session.endOperationProfile(SessionProfiler.ROW_FETCH);
544                 }
545             }
546         } catch (SQLException exception) {
547             try {// Ensure that the statement is closed, but still ensure that the real exception is thrown.
548
closeStatement(statement, session);
549             } catch (Exception JavaDoc closeException) {
550             }
551             throw DatabaseException.sqlException(exception, dbCall, this, session);
552         } catch (RuntimeException JavaDoc exception) {
553             try {// Ensure that the statement is closed, but still ensure that the real exception is thrown.
554
closeStatement(statement, session);
555             } catch (Exception JavaDoc closeException) {
556             }
557             if (exception instanceof DatabaseException) {
558                 ((DatabaseException)exception).setCall(dbCall);
559             }
560             throw exception;
561         }
562
563         // This is in seperate try block to ensure that the real exception is not masked by the close exception.
564
try {
565             // Allow for caching of statement, forced closes are not cache as they failed execution so are most likely bad.
566
releaseStatement(statement, dbCall.getSQLString(), dbCall, session);
567         } catch (SQLException exception) {
568             throw DatabaseException.sqlException(exception, this, session);
569         }
570
571         return result;
572     }
573
574     protected Vector buildThreadCursoredResult(final DatabaseCall dbCall, final ResultSet resultSet, final Statement statement, final ResultSetMetaData metaData, final AbstractSession session) {
575         final ThreadCursoredList results = new ThreadCursoredList(20);
576         Thread JavaDoc thread = new Thread JavaDoc() {
577             public void run() {
578                 session.startOperationProfile(SessionProfiler.ROW_FETCH);
579                 try {
580                     // Initial next was already validated before this method is called.
581
boolean hasNext = true;
582                     while (hasNext) {
583                         results.addElement(fetchRow(dbCall.getFields(), resultSet, metaData, session));
584                         hasNext = resultSet.next();
585                     }
586                     resultSet.close();// This must be closed incase the statement is cached and not closed.
587
} catch (SQLException exception) {
588                     try {// Ensure that the statement is closed, but still ensure that the real exception is thrown.
589
closeStatement(statement, session);
590                     } catch (Exception JavaDoc closeException) {
591                     }
592                     results.throwException(DatabaseException.sqlException(exception, dbCall, DatabaseAccessor.this, session));
593                 } catch (RuntimeException JavaDoc exception) {
594                     try {// Ensure that the statement is closed, but still ensure that the real exception is thrown.
595
closeStatement(statement, session);
596                     } catch (Exception JavaDoc closeException) {
597                     }
598                     if (exception instanceof DatabaseException) {
599                         ((DatabaseException)exception).setCall(dbCall);
600                     }
601                     results.throwException(exception);
602                 } finally {
603                     session.endOperationProfile(SessionProfiler.ROW_FETCH);
604                 }
605
606                 // This is in seperate try block to ensure that the real exception is not masked by the close exception.
607
try {
608                     // Allow for caching of statement, forced closes are not cache as they failed execution so are most likely bad.
609
DatabaseAccessor.this.releaseStatement(statement, dbCall.getSQLString(), dbCall, session);
610                 } catch (SQLException exception) {
611                     results.throwException(DatabaseException.sqlException(exception, DatabaseAccessor.this, session));
612                 }
613                 results.setIsComplete(true);
614             }
615         };
616         thread.start();
617
618         return results;
619     }
620
621     /**
622      * Execute the statement.
623      */

624     public Integer JavaDoc executeDirectNoSelect(Statement statement, DatabaseCall call, AbstractSession session) throws DatabaseException {
625         int rowCount = 0;
626
627         try {
628             session.startOperationProfile(SessionProfiler.STATEMENT_EXECUTE);
629             if ((call != null) && call.isDynamicCall(session)) {
630                 rowCount = statement.executeUpdate(call.getSQLString());
631             } else {
632                 rowCount = ((PreparedStatement)statement).executeUpdate();
633             }
634             if ((!getPlatform().supportsAutoCommit()) && (!isInTransaction())) {
635                 getPlatform().autoCommit(this);
636             }
637         } catch (SQLException exception) {
638             if (!getPlatform().shouldIgnoreException(exception)) {
639                 throw DatabaseException.sqlException(exception, this, session);
640             }
641         } finally {
642             session.endOperationProfile(SessionProfiler.STATEMENT_EXECUTE);
643         }
644
645         return new Integer JavaDoc(rowCount);
646     }
647
648     /**
649      * Execute the batched statement through the JDBC2 API.
650      */

651     protected void executeJDK12BatchStatement(Statement statement, DatabaseCall dbCall, AbstractSession session) throws DatabaseException {
652         try {
653             statement.executeBatch();
654         } catch (SQLException exception) {
655             try {// Ensure that the statement is closed, but still ensure that the real exception is thrown.
656
closeStatement(statement, session);
657             } catch (SQLException closeException) {
658             }
659
660             throw DatabaseException.sqlException(exception, this, session);
661         } catch (RuntimeException JavaDoc exception) {
662             try {// Ensure that the statement is closed, but still ensure that the real exception is thrown.
663
closeStatement(statement, session);
664             } catch (SQLException closeException) {
665             }
666
667             throw exception;
668         }
669
670         // This is in seperate try block to ensure that the real exception is not masked by the close exception.
671
try {
672             // if we are called from the ParameterizedBatchWritingMechanism then dbCall will not be null
673
//and we should try an release the statement
674
if (dbCall != null) {
675                 releaseStatement((PreparedStatement)statement, dbCall.getSQLString(), dbCall, session);
676             } else {
677                 closeStatement(statement, session);
678             }
679         } catch (SQLException exception) {
680             throw DatabaseException.sqlException(exception, this, session);
681         }
682     }
683
684     /**
685      * Execute the statement.
686      */

687     protected Integer JavaDoc executeNoSelect(DatabaseCall call, Statement statement, AbstractSession session) throws DatabaseException {
688         Integer JavaDoc rowCount = executeDirectNoSelect(statement, call, session);
689
690         // Allow for procs with outputs to be raised as events for error handling.
691
if (call.shouldBuildOutputRow()) {
692             AbstractRecord outputRow = buildOutputRow((CallableStatement)statement, call, session);
693             call.getQuery().setProperty("output", outputRow);
694             session.getEventManager().outputParametersDetected(outputRow, call);
695         }
696
697         return rowCount;
698     }
699
700     /**
701      * Execute the statement.
702      */

703     protected ResultSet executeSelect(DatabaseCall call, Statement statement, AbstractSession session) throws SQLException {
704         ResultSet resultSet;
705
706         session.startOperationProfile(SessionProfiler.STATEMENT_EXECUTE);
707         try {
708             if (call.isDynamicCall(session)) {
709                 resultSet = statement.executeQuery(call.getSQLString());
710             } else {
711                 resultSet = ((PreparedStatement)statement).executeQuery();
712             }
713         } finally {
714             session.endOperationProfile(SessionProfiler.STATEMENT_EXECUTE);
715         }
716
717         // Allow for procs with outputs to be raised as events for error handling.
718
if (call.shouldBuildOutputRow()) {
719             AbstractRecord outputRow = buildOutputRow((CallableStatement)statement, call, session);
720             call.getQuery().setProperty("output", outputRow);
721             session.getEventManager().outputParametersDetected(outputRow, call);
722         }
723
724         return resultSet;
725     }
726
727     /**
728      * Return a new DatabaseRow.<p>
729      * Populate the row from the data in cursor. The fields representing the results
730      * and the order of the results are stored in fields.
731      * <p><b>NOTE</b>:
732      * Make sure that the field name is set. An empty field name placeholder is
733      * used in the sortFields() method when the number of fields defined does not
734      * match the number of column names available on the database.
735      */

736     protected AbstractRecord fetchRow(Vector fields, ResultSet resultSet, ResultSetMetaData metaData, AbstractSession session) throws DatabaseException {
737         Vector values = new Vector(fields.size());
738         // PERF: Pass platform and optimize data flag.
739
DatabasePlatform platform = getPlatform();
740         boolean optimizeData = platform.shouldOptimizeDataConversion();
741         int size = fields.size();
742         for (int index = 0; index < size; index++) {
743             DatabaseField field = (DatabaseField)fields.elementAt(index);
744             // Field can be null for fetch groups.
745
if (field != null) {
746                 values.add(getObject(resultSet, field, metaData, index + 1, platform, optimizeData, session));
747             } else {
748                 values.add(null);
749             }
750         }
751
752         // Row creation is optimized through sharing the same fields for the entire result set.
753
return new DatabaseRecord(fields, values);
754     }
755
756     /**
757      * Get a description of table columns available in a catalog.
758      *
759      * <P>Only column descriptions matching the catalog, schema, table
760      * and column name criteria are returned. They are ordered by
761      * TABLE_SCHEM, TABLE_NAME and ORDINAL_POSITION.
762      *
763      * <P>Each column description has the following columns:
764      * <OL>
765      * <LI><B>TABLE_CAT</B> String => table catalog (may be null)
766      * <LI><B>TABLE_SCHEM</B> String => table schema (may be null)
767      * <LI><B>TABLE_NAME</B> String => table name
768      * <LI><B>COLUMN_NAME</B> String => column name
769      * <LI><B>DATA_TYPE</B> short => SQL type from java.sql.Types
770      * <LI><B>TYPE_NAME</B> String => Data source dependent type name
771      * <LI><B>COLUMN_SIZE</B> int => column size. For char or date
772      * types this is the maximum number of characters, for numeric or
773      * decimal types this is precision.
774      * <LI><B>BUFFER_LENGTH</B> is not used.
775      * <LI><B>DECIMAL_DIGITS</B> int => the number of fractional digits
776      * <LI><B>NUM_PREC_RADIX</B> int => Radix (typically either 10 or 2)
777      * <LI><B>NULLABLE</B> int => is NULL allowed?
778      * <UL>
779      * <LI> columnNoNulls - might not allow NULL values
780      * <LI> columnNullable - definitely allows NULL values
781      * <LI> columnNullableUnknown - nullability unknown
782      * </UL>
783      * <LI><B>REMARKS</B> String => comment describing column (may be null)
784      * <LI><B>COLUMN_DEF</B> String => default value (may be null)
785      * <LI><B>SQL_DATA_TYPE</B> int => unused
786      * <LI><B>SQL_DATETIME_SUB</B> int => unused
787      * <LI><B>CHAR_OCTET_LENGTH</B> int => for char types the
788      * maximum number of bytes in the column
789      * <LI><B>ORDINAL_POSITION</B> int => index of column in table
790      * (starting at 1)
791      * <LI><B>IS_NULLABLE</B> String => "NO" means column definitely
792      * does not allow NULL values; "YES" means the column might
793      * allow NULL values. An empty string means nobody knows.
794      * </OL>
795      *
796      * @param catalog a catalog name; "" retrieves those without a
797      * catalog; null means drop catalog name from the selection criteria
798      * @param schemaPattern a schema name pattern; "" retrieves those
799      * without a schema
800      * @param tableNamePattern a table name pattern
801      * @param columnNamePattern a column name pattern
802      * @return a Vector of DatabaseRows.
803      */

804     public Vector getColumnInfo(String JavaDoc catalog, String JavaDoc schema, String JavaDoc tableName, String JavaDoc columnName, AbstractSession session) throws DatabaseException {
805         if (session.shouldLog(SessionLog.FINEST, SessionLog.QUERY)) {// Avoid printing if no logging required.
806
Object JavaDoc[] args = { catalog, schema, tableName, columnName };
807             session.log(SessionLog.FINEST, SessionLog.QUERY, "query_column_meta_data_with_column", args, this);
808         }
809         Vector result = new Vector();
810         ResultSet resultSet = null;
811         try {
812             incrementCallCount(session);
813             resultSet = getConnectionMetaData().getColumns(catalog, schema, tableName, columnName);
814             Vector fields = buildSortedFields(null, resultSet, session);
815             ResultSetMetaData metaData = resultSet.getMetaData();
816
817             while (resultSet.next()) {
818                 result.addElement(fetchRow(fields, resultSet, metaData, session));
819             }
820             resultSet.close();
821         } catch (SQLException sqlException) {
822             try {
823                 if (resultSet != null) {
824                     resultSet.close();
825                 }
826             } catch (SQLException closeException) {
827             }
828
829             // Ensure that real exception is thrown.
830
throw DatabaseException.sqlException(sqlException, this, session);
831         } finally {
832             decrementCallCount();
833         }
834         return result;
835     }
836
837     /**
838      * Return the column names from a result sets meta data.
839      * This is required for custom SQL execution only,
840      * as generated SQL already knows the fields returned.
841      */

842     protected Vector getColumnNames(ResultSet resultSet, AbstractSession session) throws SQLException {
843         ResultSetMetaData metaData = resultSet.getMetaData();
844         Vector columnNames = new Vector(metaData.getColumnCount());
845
846         for (int index = 0; index < metaData.getColumnCount(); index++) {
847             // Changed the following code to use metaData#getColumnLabel() instead of metaData.getColumnName()
848
// This is as required by JDBC spec to access metadata for queries using column aliases.
849
// Reconsider whether to migrate this change to other versions of Toplink with older native query support
850
String JavaDoc columnName = metaData.getColumnLabel(index + 1);
851             if ((columnName == null) || columnName.equals("")) {
852                 columnName = "C" + (index + 1);// Some column may be unnamed.
853
}
854
855             // Force field names to upper case is set.
856
if (getPlatform().shouldForceFieldNamesToUpperCase()) {
857                 columnName = columnName.toUpperCase();
858             }
859             columnNames.addElement(columnName);
860         }
861         return columnNames;
862     }
863
864     /**
865      * Return the receiver's connection to its data source. A connection is used to execute queries on,
866      * and retreive data from, a data source.
867      * @see java.sql.Connection
868      */

869     public Connection getConnection() throws DatabaseException {
870         return (Connection)getDatasourceConnection();
871     }
872
873     /**
874      * Return the platform.
875      */

876     public DatabasePlatform getPlatform() {
877         return (DatabasePlatform)platform;
878     }
879
880     /**
881      * return the cached metaData
882      */

883     public DatabaseMetaData getConnectionMetaData() throws SQLException {
884         return getConnection().getMetaData();
885     }
886
887     /**
888      * Return an object retrieved from resultSet with the getObject() method.
889      * Optimize the get for certain type to avoid double conversion.
890      * <b>NOTE</b>: This method handles a virtual machine error thrown when retrieving times & dates from Oracle or Sybase.
891      */

892     protected Object JavaDoc getObject(ResultSet resultSet, DatabaseField field, ResultSetMetaData metaData, int columnNumber, DatabasePlatform platform, boolean optimizeData, AbstractSession session) throws DatabaseException {
893         Object JavaDoc value = null;
894         try {
895             // PERF: Cache the JDBC type in the field to avoid JDBC call.
896
int type = field.sqlType;
897             if (type == -1) {
898                 type = metaData.getColumnType(columnNumber);
899                 field.setSqlType(type);
900             }
901
902             if (optimizeData) {
903                 try {
904                     value = getObjectThroughOptimizedDataConversion(resultSet, field, type, columnNumber, platform, session);
905                     // Since null cannot be distighighsed from no optimization done, this is return for no-op.
906
if (value == null) {
907                         return null;
908                     }
909                     if (value == this) {
910                         value = null;
911                     }
912                 } catch (SQLException exception) {
913                     // Log the exception and try non-optimized data conversion
914
if (session.shouldLog(SessionLog.WARNING, SessionLog.SQL)) {
915                         session.logThrowable(SessionLog.WARNING, SessionLog.SQL, exception);
916                     }
917                 }
918             }
919             if (value == null) {
920                 if ((type == Types.LONGVARBINARY) && platform.usesStreamsForBinding()) {
921                     //can read large binary data as a stream
922
InputStream tempInputStream;
923                     tempInputStream = resultSet.getBinaryStream(columnNumber);
924                     if (tempInputStream != null) {
925                         try {
926                             ByteArrayOutputStream tempOutputStream = new ByteArrayOutputStream();
927                             int tempInt = tempInputStream.read();
928                             while (tempInt != -1) {
929                                 tempOutputStream.write(tempInt);
930                                 tempInt = tempInputStream.read();
931                             }
932                             value = tempOutputStream.toByteArray();
933                         } catch (IOException exception) {
934                             throw DatabaseException.errorReadingBlobData();
935                         }
936                     } else {
937                         value = null;
938                     }
939                 } else {
940                     value = platform.getObjectFromResultSet(resultSet, columnNumber, type);
941                     // PERF: only perform blob check on non-optimized types.
942
// CR2943 - convert early if the type is a BLOB or a CLOB.
943
if (isBlob(type)) {
944                         value = platform.convertObject(value, ClassConstants.APBYTE);
945                     }
946                     if (isClob(type)) {
947                         value = getPlatform().convertObject(value, ClassConstants.STRING);
948                     }
949                 }
950             }
951             if (resultSet.wasNull()) {
952                 value = null;
953             }
954         } catch (SQLException exception) {
955             throw DatabaseException.sqlException(exception, this, session);
956         }
957
958         return value;
959     }
960
961     /**
962      * Handle the conversion into java optimially through calling the direct type API.
963      * If the type is not one that can be optimized return null.
964      */

965     protected Object JavaDoc getObjectThroughOptimizedDataConversion(ResultSet resultSet, DatabaseField field, int type, int columnNumber, DatabasePlatform platform, AbstractSession session) throws SQLException {
966         Object JavaDoc value = this;// Means no optimization, need to distighuuish from null.
967
Class JavaDoc fieldType = field.type;
968
969         // Optimize numeric values to avoid conversion into big-dec and back to primitives.
970
if ((fieldType == ClassConstants.PLONG) || (fieldType == ClassConstants.LONG)) {
971             value = new Long JavaDoc(resultSet.getLong(columnNumber));
972         } else if ((type == Types.VARCHAR) || (type == Types.CHAR)) {
973             // CUSTOM PATCH for oracle drivers because they don't respond to getObject() when using scrolling result sets.
974
// Chars may require blanks to be trimmed.
975
value = resultSet.getString(columnNumber);
976             if ((type == Types.CHAR) && (value != null) && platform.shouldTrimStrings()) {
977                 value = Helper.rightTrimString((String JavaDoc)value);
978             }
979         } else if ((fieldType == ClassConstants.INTEGER) || (fieldType == ClassConstants.PINT)) {
980             value = new Integer JavaDoc(resultSet.getInt(columnNumber));
981         } else if ((fieldType == ClassConstants.FLOAT) || (fieldType == ClassConstants.PFLOAT)) {
982             value = new Float JavaDoc(resultSet.getFloat(columnNumber));
983         } else if ((fieldType == ClassConstants.DOUBLE) || (fieldType == ClassConstants.PDOUBLE)) {
984             value = new Double JavaDoc(resultSet.getDouble(columnNumber));
985         } else if ((fieldType == ClassConstants.SHORT) || (fieldType == ClassConstants.PSHORT)) {
986             value = new Short JavaDoc(resultSet.getShort(columnNumber));
987         } else if (Helper.shouldOptimizeDates() && (fieldType != null) && ((type == Types.TIME) || (type == Types.DATE) || (type == Types.TIMESTAMP))) {
988             // Optimize dates by avoid conversion to timestamp then back to date or time or util.date.
989
String JavaDoc dateString = resultSet.getString(columnNumber);
990             value = platform.convertObject(dateString, fieldType);
991         } else if ((fieldType != null) && ((type == Types.TIME) || (type == Types.DATE) || (type == Types.TIMESTAMP))) {
992             // PERF: Optimize dates by calling direct get method if type is Date or Time,
993
// unfortunately the double conversion is unavoidable for Calendar and util.Date.
994
if (fieldType == ClassConstants.SQLDATE) {
995                 value = resultSet.getDate(columnNumber);
996             } else if (fieldType == ClassConstants.TIME) {
997                 value = resultSet.getTime(columnNumber);
998             } else if (fieldType == ClassConstants.TIMESTAMP) {
999                 value = resultSet.getTimestamp(columnNumber);
1000            }
1001        }
1002
1003        return value;
1004    }
1005
1006    /**
1007     * Return if the accessor has any cached statements.
1008     * This should be used to avoid lazy instantiation of the cache.
1009     */

1010    protected boolean hasStatementCache() {
1011        return (statementCache != null) && (!statementCache.isEmpty());
1012    }
1013
1014    /**
1015     * The statement cache stores a fixed sized number of prepared statements.
1016     */

1017    protected synchronized Hashtable getStatementCache() {
1018        if (statementCache == null) {
1019            statementCache = new Hashtable(50);
1020        }
1021        return statementCache;
1022    }
1023
1024    /**
1025     * Get a description of tables available in a catalog.
1026     *
1027     * <P>Only table descriptions matching the catalog, schema, table
1028     * name and type criteria are returned. They are ordered by
1029     * TABLE_TYPE, TABLE_SCHEM and TABLE_NAME.
1030     *
1031     * <P>Each table description has the following columns:
1032     * <OL>
1033     * <LI><B>TABLE_CAT</B> String => table catalog (may be null)
1034     * <LI><B>TABLE_SCHEM</B> String => table schema (may be null)
1035     * <LI><B>TABLE_NAME</B> String => table name
1036     * <LI><B>TABLE_TYPE</B> String => table type. Typical types are "TABLE",
1037     * "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY",
1038     * "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
1039     * <LI><B>REMARKS</B> String => explanatory comment on the table
1040     * </OL>
1041     *
1042     * <P><B>Note:</B> Some databases may not return information for
1043     * all tables.
1044     *
1045     * @param catalog a catalog name; "" retrieves those without a
1046     * catalog; null means drop catalog name from the selection criteria
1047     * @param schemaPattern a schema name pattern; "" retrieves those
1048     * without a schema
1049     * @param tableNamePattern a table name pattern
1050     * @param types a list of table types to include; null returns all types
1051     * @return a Vector of DatabaseRows.
1052     */

1053    public Vector getTableInfo(String JavaDoc catalog, String JavaDoc schema, String JavaDoc tableName, String JavaDoc[] types, AbstractSession session) throws DatabaseException {
1054        if (session.shouldLog(SessionLog.FINEST, SessionLog.QUERY)) {// Avoid printing if no logging required.
1055
Object JavaDoc[] args = { catalog, schema, tableName };
1056            session.log(SessionLog.FINEST, SessionLog.QUERY, "query_column_meta_data", args, this);
1057        }
1058        Vector result = new Vector();
1059        ResultSet resultSet = null;
1060        try {
1061            incrementCallCount(session);
1062            resultSet = getConnectionMetaData().getTables(catalog, schema, tableName, types);
1063            Vector fields = buildSortedFields(null, resultSet, session);
1064            ResultSetMetaData metaData = resultSet.getMetaData();
1065
1066            while (resultSet.next()) {
1067                result.addElement(fetchRow(fields, resultSet, metaData, session));
1068            }
1069            resultSet.close();
1070        } catch (SQLException sqlException) {
1071            try {
1072                if (resultSet != null) {
1073                    resultSet.close();
1074                }
1075            } catch (SQLException closeException) {
1076            }
1077
1078            // Ensure that real exception is thrown.
1079
throw DatabaseException.sqlException(sqlException, this, session);
1080        } finally {
1081            decrementCallCount();
1082        }
1083        return result;
1084    }
1085
1086    /**
1087     * Return true if the receiver is currently connected to a data source. Return false otherwise.
1088     */

1089    public boolean isDatasourceConnected() {
1090        try {
1091            return !getConnection().isClosed();
1092        } catch (SQLException exception) {
1093            throw DatabaseException.sqlException(exception, this, null);
1094        }
1095    }
1096
1097    /**
1098     * Return if thread cursors should be used for fetch the result row.
1099     * This allows the objects to be built while the rows are being fetched.
1100     */

1101    public boolean shouldUseThreadCursors() {
1102        return shouldUseThreadCursors;
1103    }
1104
1105    /**
1106     * Set if thread cursors should be used for fetch the result row.
1107     * This allows the objects to be built while the rows are being fetched.
1108     */

1109    public void setShouldUseThreadCursors(boolean shouldUseThreadCursors) {
1110        this.shouldUseThreadCursors = shouldUseThreadCursors;
1111    }
1112
1113    /**
1114     * Prepare the SQL statement for the call.
1115     * First check if the statement is cached before building a new one.
1116     * Currently the SQL string is used as the cache key, this may have to be switched if it becomes a performance problem.
1117     */

1118    public Statement prepareStatement(DatabaseCall call, AbstractSession session) throws SQLException {
1119        Statement statement = null;
1120        if (call.usesBinding(session) && call.shouldCacheStatement(session)) {
1121            // Check the cache by sql string, must syncronize check and removal.
1122
synchronized (getStatementCache()) {
1123                statement = (PreparedStatement)getStatementCache().get(call.getSQLString());
1124                if (statement != null) {
1125                    // Need to remove to allow concurrent statement execution.
1126
getStatementCache().remove(call.getSQLString());
1127                }
1128            }
1129        }
1130
1131        if (statement == null) {
1132            if (call.isCallableStatementRequired()) {
1133                // Callable statements are used for StoredProcedures and PLSQL blocks.
1134
if (call.isResultSetScrollable()) {
1135                    statement = getConnection().prepareCall(call.getSQLString(), call.getResultSetType(), call.getResultSetConcurrency());
1136                } else {
1137                    statement = getConnection().prepareCall(call.getSQLString());
1138                }
1139            } else if (call.isResultSetScrollable()) {
1140                // Scrollable statements are used for ScrollableCursors.
1141
statement = getConnection().prepareStatement(call.getSQLString(), call.getResultSetType(), call.getResultSetConcurrency());
1142            } else if (call.isDynamicCall(session)) {
1143                // PERF: Dynamic statements are used for dynamic SQL.
1144
statement = allocateDynamicStatement();
1145            } else {
1146                // Prepared statements are used if binding is used, or dynamic statements are turned off.
1147
statement = getConnection().prepareStatement(call.getSQLString());
1148            }
1149        }
1150
1151        return statement;
1152    }
1153
1154    /**
1155     * Attempt to save some of the cost associated with getting a fresh connection.
1156     * Assume the DatabaseDriver has been cached, if appropriate.
1157     * Note: Connections that are participating in transactions will not be refreshd.^M
1158     * Added for bug 3046465 to ensure the statement cache is cleared
1159     */

1160    protected void reconnect(AbstractSession session) {
1161        clearStatementCache(session);
1162        super.reconnect(session);
1163    }
1164
1165    /**
1166     * Release the statement through closing it or putting it back in the statement cache.
1167     */

1168    protected void releaseStatement(Statement statement, String JavaDoc sqlString, DatabaseCall call, AbstractSession session) throws SQLException {
1169        if (call.usesBinding(session) && call.shouldCacheStatement(session)) {
1170            synchronized (getStatementCache()) {
1171                PreparedStatement preparedStatement = (PreparedStatement)statement;
1172                if (!getStatementCache().containsKey(sqlString)) {// May already be there by other thread.
1173
preparedStatement.clearParameters();
1174                    if (getStatementCache().size() > getPlatform().getStatementCacheSize()) {
1175                        // Currently one is removed at random...
1176
PreparedStatement removedStatement = (PreparedStatement)getStatementCache().remove(getStatementCache().keys().nextElement());
1177                        closeStatement(removedStatement, session);
1178                    } else {
1179                        decrementCallCount();
1180                    }
1181                    getStatementCache().put(sqlString, preparedStatement);
1182                } else {
1183                    // CR... Must close the statement if not cached.
1184
closeStatement(statement, session);
1185                }
1186            }
1187        } else if (statement == this.dynamicStatement) {
1188            if (call.getMaxRows() > 0) {
1189                statement.setMaxRows(0);
1190            }
1191            setIsDynamicStatementInUse(false);
1192            decrementCallCount();
1193        } else {
1194            closeStatement(statement, session);
1195        }
1196    }
1197
1198    /**
1199     * Rollback a transaction on the database. This means toggling the auto-commit option.
1200     */

1201    public void basicRollbackTransaction(AbstractSession session) throws DatabaseException {
1202        try {
1203            if (getPlatform().supportsAutoCommit()) {
1204                getConnection().rollback();
1205                getConnection().setAutoCommit(true);
1206            } else {
1207                getPlatform().rollbackTransaction(this);
1208            }
1209        } catch (SQLException exception) {
1210            throw DatabaseException.sqlException(exception, this, session);
1211        }
1212    }
1213
1214    /**
1215     * The statement cache stores a fixed sized number of prepared statements.
1216     */

1217    protected void setStatementCache(Hashtable statementCache) {
1218        this.statementCache = statementCache;
1219    }
1220
1221    /**
1222     * This method will sort the fields in correct order based
1223     * on the column names.
1224     */

1225    protected Vector sortFields(Vector fields, Vector columnNames) {
1226        Vector sortedFields = new Vector(columnNames.size());
1227        Vector eligableFields = (Vector)fields.clone();// Must clone to allow removing to support the same field twice.
1228
Enumeration columnNamesEnum = columnNames.elements();
1229        boolean valueFound = false;
1230        while (columnNamesEnum.hasMoreElements()) {
1231            String JavaDoc columnName = (String JavaDoc)columnNamesEnum.nextElement();
1232
1233            DatabaseField field = null;
1234            Enumeration fieldEnum = eligableFields.elements();
1235            while (fieldEnum.hasMoreElements()) {
1236                field = (DatabaseField)fieldEnum.nextElement();
1237                if (DatabasePlatform.shouldIgnoreCaseOnFieldComparisons()) {
1238                    if (field.getName().equalsIgnoreCase(columnName)) {
1239                        valueFound = true;
1240                        sortedFields.addElement(field);
1241                        break;
1242                    }
1243                } else {
1244                    if (field.getName().equals(columnName)) {
1245                        valueFound = true;
1246                        sortedFields.addElement(field);
1247                        break;
1248                    }
1249                }
1250            }
1251
1252            if (valueFound) {
1253                // The eligable fields must be maintained as two field can have the same name, but different tables.
1254
eligableFields.removeElement(field);
1255            } else {
1256                // Need to add a place holder in case the column is not in the fiels vector
1257
sortedFields.addElement(new DatabaseField());
1258            }
1259            valueFound = false;
1260        }
1261
1262        return sortedFields;
1263    }
1264
1265    public String JavaDoc toString() {
1266        StringWriter writer = new StringWriter();
1267        writer.write("DatabaseAccessor(");
1268        if (isConnected()) {
1269            writer.write(ToStringLocalization.buildMessage("connected", (Object JavaDoc[])null));
1270        } else {
1271            writer.write(ToStringLocalization.buildMessage("disconnected", (Object JavaDoc[])null));
1272        }
1273        writer.write(")");
1274        return writer.toString();
1275    }
1276
1277    /**
1278     * Return if the JDBC type is a binary type such as blob.
1279     */

1280    private boolean isBlob(int type) {
1281        return (type == Types.BLOB) || (type == Types.LONGVARBINARY);
1282    }
1283
1284    /**
1285     * Return if the JDBC type is a large character type such as clob.
1286     */

1287    private boolean isClob(int type) {
1288        return (type == Types.CLOB) || (type == Types.LONGVARCHAR);
1289    }
1290
1291    /**
1292     * This method will be called after a series of writes have been issued to
1293     * mark where a particular set of writes has completed. It will be called
1294     * from commitTransaction and may be called from writeChanges. Its main
1295     * purpose is to ensure that the batched statements have been executed
1296     */

1297    public void writesCompleted(AbstractSession session) {
1298        // Place holder for batch writing.
1299
}
1300}
1301
Popular Tags