KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > jcorporate > expresso > core > dataobjects > jdbc > JDBCExecutor


1 /* ====================================================================
2 * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
3 *
4 * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 *
18 * 3. The end-user documentation included with the redistribution,
19 * if any, must include the following acknowledgment:
20 * "This product includes software developed by Jcorporate Ltd.
21 * (http://www.jcorporate.com/)."
22 * Alternately, this acknowledgment may appear in the software itself,
23 * if and wherever such third-party acknowledgments normally appear.
24 *
25 * 4. "Jcorporate" and product names such as "Expresso" must
26 * not be used to endorse or promote products derived from this
27 * software without prior written permission. For written permission,
28 * please contact info@jcorporate.com.
29 *
30 * 5. Products derived from this software may not be called "Expresso",
31 * or other Jcorporate product names; nor may "Expresso" or other
32 * Jcorporate product names appear in their name, without prior
33 * written permission of Jcorporate Ltd.
34 *
35 * 6. No product derived from this software may compete in the same
36 * market space, i.e. framework, without prior written permission
37 * of Jcorporate Ltd. For written permission, please contact
38 * partners@jcorporate.com.
39 *
40 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
41 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
42 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
43 * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
44 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
45 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
46 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
47 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
48 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
49 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
50 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 * SUCH DAMAGE.
52 * ====================================================================
53 *
54 * This software consists of voluntary contributions made by many
55 * individuals on behalf of the Jcorporate Ltd. Contributions back
56 * to the project(s) are encouraged when you make modifications.
57 * Please send them to support@jcorporate.com. For more information
58 * on Jcorporate Ltd. and its products, please see
59 * <http://www.jcorporate.com/>.
60 *
61 * Portions of this software are based upon other open source
62 * products and are subject to their respective licenses.
63  */

64
65 package com.jcorporate.expresso.core.dataobjects.jdbc;
66
67 import com.jcorporate.expresso.core.dataobjects.DataException;
68 import com.jcorporate.expresso.core.dataobjects.DataExecutorInterface;
69 import com.jcorporate.expresso.core.dataobjects.DataField;
70 import com.jcorporate.expresso.core.dataobjects.DataFieldMetaData;
71 import com.jcorporate.expresso.core.dataobjects.DataObject;
72 import com.jcorporate.expresso.core.dataobjects.DataObjectMetaData;
73 import com.jcorporate.expresso.core.dataobjects.DuplicateKeyException;
74 import com.jcorporate.expresso.core.db.DBConnection;
75 import com.jcorporate.expresso.core.db.DBConnectionPool;
76 import com.jcorporate.expresso.core.db.DBException;
77 import com.jcorporate.expresso.core.db.TypeMapper;
78 import com.jcorporate.expresso.core.dbobj.DBField;
79 import com.jcorporate.expresso.core.dbobj.DBObject;
80 import com.jcorporate.expresso.core.dbobj.NextNumber;
81 import com.jcorporate.expresso.core.misc.ConfigJdbc;
82 import com.jcorporate.expresso.core.misc.ConfigManager;
83 import com.jcorporate.expresso.core.misc.ConfigurationException;
84 import com.jcorporate.expresso.core.misc.StringUtil;
85 import com.jcorporate.expresso.kernel.util.FastStringBuffer;
86 import org.apache.log4j.Logger;
87
88 import java.io.ByteArrayInputStream JavaDoc;
89 import java.io.InputStream JavaDoc;
90 import java.io.StringReader JavaDoc;
91 import java.sql.BatchUpdateException JavaDoc;
92 import java.sql.CallableStatement JavaDoc;
93 import java.sql.Date JavaDoc;
94 import java.sql.SQLException JavaDoc;
95 import java.sql.SQLWarning JavaDoc;
96 import java.sql.Timestamp JavaDoc;
97 import java.util.ArrayList JavaDoc;
98 import java.util.HashMap JavaDoc;
99 import java.util.Iterator JavaDoc;
100 import java.util.List JavaDoc;
101 import java.util.Map JavaDoc;
102
103 /**
104  * Initial separation of DBObjects from the underlying JDBC code that gets executed. This is
105  * part number 1 where we move a lot of the JDBC code over to this helper class. For round
106  * #1 iteration, we're assuming that the valueObject is actually a DBObject that implements
107  * the DataObject interface (which it does). This is because we're interested in
108  * getting something working and demonstratable, and then slowly flesh out the DataObject
109  * interface so that we can eventually completely prune this class completely
110  * away from the DBObject class and work strictly with the DataObject Interface.
111  *
112  * @author Michael Rimov
113  * @author Yves Henri AMAIZO <amy_amaizo@compuserve.com>
114  * @since Expresso 5.0
115  */

116
117 public class JDBCExecutor implements DataExecutorInterface {
118     private static final String JavaDoc myName = JDBCExecutor.class.getName() + ".";
119     private static Logger log =
120             Logger.getLogger(JDBCExecutor.class);
121
122     transient public static final String JavaDoc LONGVARBINARY_TYPE = "longvarbinary";
123     transient public static final String JavaDoc VARBINARY_TYPE = "varbinary";
124     transient public static final String JavaDoc LONGVARCHAR_TYPE = "longvarchar";
125
126     public static int LONGBINARY_READ_DEFAULT_SIZE = 262144;
127
128     public JDBCExecutor() {
129     }
130
131     /**
132      * Takes a <code>DataObject</code> and adds it to the underlying data source
133      *
134      * @param valueObject the <code>DataObject</code> to add.
135      * @throws DataException upon error adding the object to the data source
136      * @throws DuplicateKeyException if the object already existed in the data
137      * source.
138      * <p/>
139      * Modify by Yves Henri AMAIZO <amy_amaizo@compuserve.com>
140      * @since $DatabaseSchema $Date: 2004/11/18 02:03:27 $
141      */

142     public void add(DataObject valueObject) throws DataException, DuplicateKeyException {
143         DBConnection myConnection = null;
144         DBConnectionPool myPool = null;
145         DBConnection localConnection = null;
146
147         try {
148             if (valueObject == null) {
149                 throw new IllegalArgumentException JavaDoc(myName + "add(DataObject): valueObject was null");
150             }
151
152             DBObject theObject = (DBObject) valueObject;
153             JDBCObjectMetaData metadata = (JDBCObjectMetaData) valueObject.getMetaData();
154
155             boolean needComma = false;
156
157             //
158
//The names of the database fiels that require prepared statements
159
//to Add
160
//
161
List JavaDoc lobFieldOrder = null;
162             List JavaDoc lobFieldType = null;
163
164             //
165
//The list of Strings to add to the file
166
//
167
List JavaDoc lobAdds = null;
168
169             if (!haveAllKeysExceptAutoInc(theObject)) {
170                 throw new DataException("All key fields not present - " +
171                         "cannot add new record");
172             }
173
174             //
175
//If myPool isn't set yet, then we need to use getDBName to
176
//reset. FIXME: Have the system throw exceptions if DBName isn't
177
//set instead.
178
//
179
myPool = DBConnectionPool.getInstance(theObject.getMappedDataContext());
180             localConnection = theObject.getLocalConnection();
181
182             theObject.checkAllRefsPublic();
183
184             DBField oneField = null;
185
186             /**
187              * sqlCommand will eventually = sqlCommand + valuesCommand. The two
188              * are assembled in parallel in the loop below.
189              */

190             FastStringBuffer sqlCommand = FastStringBuffer.getInstance();
191             FastStringBuffer valuesCommand = FastStringBuffer.getInstance();
192             String JavaDoc theSqlCommand = null;
193             try {
194
195                 sqlCommand.append("INSERT INTO ");
196                 sqlCommand.append(metadata.getTargetSQLTable(theObject.getDataContext()));
197                 sqlCommand.append(" (");
198
199                 valuesCommand.append(") VALUES (");
200
201                 boolean needCommaValues = false;
202                 for (Iterator JavaDoc i = metadata.getAllFieldsMap().values().iterator(); i.hasNext();) {
203                     oneField = (DBField) i.next();
204
205                     if (!oneField.isVirtual()) {
206                         theObject.checkField(oneField.getName(), theObject.getField(oneField.getName()));
207
208                         if (oneField.isBinaryObjectType()) {
209                             if (log.isDebugEnabled()) {
210                                 log.debug("Skipping BINARY Object: " + oneField.getName());
211                             }
212                             continue;
213                         }
214
215                         if (needComma) {
216                             sqlCommand.append(", ");
217                         }
218
219                         sqlCommand.append(oneField.getName());
220                         needComma = true;
221
222                         if (needCommaValues) {
223                             valuesCommand.append(", ");
224                         }
225                         if (oneField.isDateType()) {
226                             Object JavaDoc tmpData = valueObject.get(oneField.getName());
227                             String JavaDoc data;
228                             //
229
//FIXME allow for appropriate support of other data types.
230
//
231
if (tmpData == null) {
232                                 data = null;
233                             } else if (tmpData instanceof String JavaDoc) {
234                                 data = (String JavaDoc) tmpData;
235                             } else {
236                                 data = tmpData.toString();
237                             }
238
239                             if (data == null || (data.length() == 0)) {
240                                 valuesCommand.append("null");
241                             } else {
242                                 valuesCommand.append(JDBCUtil.getInstance()
243                                         .formatDateTime(valueObject, oneField.getName()));
244                             }
245                         } else if (oneField.isAutoIncremented()) {
246                             String JavaDoc nextNumValue = Long.toString(NextNumber.getInstance().getNext(
247                                     theObject.getDataContext(),
248                                     theObject,
249                                     oneField.getName()));
250                             valueObject.set(oneField.getName(), nextNumValue);
251                             valuesCommand.append(theObject.quoteIfNeeded(oneField.getName(),
252                                     null));
253                         } else if (oneField.isCharacterLongObjectType() || oneField.isLongBinaryType()) {
254                             Object JavaDoc tmpData = valueObject.get(oneField.getName());
255                             String JavaDoc data;
256                             //
257
//FIXME allow for appropriate support of other data types.
258
//
259
if (tmpData == null) {
260                                 data = null;
261                             } else if (tmpData instanceof String JavaDoc) {
262                                 data = (String JavaDoc) tmpData;
263                             } else {
264                                 data = tmpData.toString();
265                             }
266                             if (data != null) {
267                                 if (lobAdds == null) {
268                                     lobAdds = new ArrayList JavaDoc();
269                                     lobFieldOrder = new ArrayList JavaDoc();
270                                     lobFieldType = new ArrayList JavaDoc();
271                                 }
272                                 lobAdds.add(tmpData);
273                                 lobFieldOrder.add(oneField.getName());
274                                 lobFieldType.add(oneField.getTypeString());
275                                 valuesCommand.append("?");
276                             } else {
277                                 valuesCommand.append("null");
278                             }
279                         } else {
280                             valuesCommand.append(theObject.quoteIfNeeded(oneField.getName(),
281                                     null));
282                         }
283
284                         needCommaValues = true;
285                     } /* if field is not virtual */
286
287                 } /* for each field */
288
289
290                 //Now we merge the values of the parallel loops
291
sqlCommand.append(valuesCommand);
292                 sqlCommand.append(")");
293                 theSqlCommand = sqlCommand.toString();
294             } catch (NullPointerException JavaDoc npe) {
295                 log.error("NPE", npe);
296                 throw new DataException("Null Pointer Exception", npe);
297             } catch (DBException dbe) {
298                 log.error("DBException", dbe);
299                 throw dbe;
300             } finally {
301                 sqlCommand.release();
302                 sqlCommand = null;
303                 valuesCommand.release();
304                 valuesCommand = null;
305             }
306
307
308             if (localConnection != null) {
309                 myConnection = localConnection;
310             } else {
311                 try {
312                     myConnection = myPool.getConnection(getClass().getName());
313                 } catch (java.util.ConcurrentModificationException JavaDoc cme) {
314                     cme.printStackTrace();
315                     log.error(cme);
316                     throw new DataException("JDBCExecutor.add() ConcurrentModificationException"
317                             , cme);
318                 }
319             }
320
321             if (lobAdds != null) {
322                 java.sql.PreparedStatement JavaDoc prepStatement = myConnection.createPreparedStatement(theSqlCommand);
323                 if (prepStatement == null) {
324                     try {
325                         SQLWarning JavaDoc sqlWarnings = myConnection.getConnection().getWarnings();
326                         while (sqlWarnings != null) {
327                             log.warn("SQL Warning creating prepared statement: " + sqlWarnings.toString());
328                             sqlWarnings = sqlWarnings.getNextWarning();
329                         }
330                     } catch (SQLException JavaDoc ex) {
331                         log.debug("Error getting warnings when prepared statement was null");
332                     }
333
334
335                     throw new DataException("Returned Prepared Statement for "
336                             + theSqlCommand + " was null");
337                 }
338
339                 int size = lobFieldOrder.size();
340                 TypeMapper typeMapper = TypeMapper.getInstance(myConnection.getDataContext());
341                 for (int i = 0; i < size; i++) {
342                     String JavaDoc fieldName = (String JavaDoc) lobFieldOrder.get(i);
343                     DataFieldMetaData metaData = valueObject.getFieldMetaData(fieldName);
344                     Object JavaDoc nullValue = lobAdds.get(i);
345                     String JavaDoc myType = (String JavaDoc) lobFieldType.get(i);
346                     if (nullValue == null || "null".equals(nullValue) || (nullValue.toString().length() == 0
347                             && (metaData.isNumericType() || metaData.isDateType()))) {
348                         int typeCode = typeMapper.getJavaSQLType(metaData.getTypeString());
349                         prepStatement.setNull(i + 1, typeCode);
350                     } else {
351                         if (!myType.equalsIgnoreCase(LONGVARBINARY_TYPE) && !myType.equalsIgnoreCase(VARBINARY_TYPE) && !myType.equalsIgnoreCase(
352                                 LONGVARCHAR_TYPE)) {
353                             String JavaDoc value = (String JavaDoc) lobAdds.get(i);
354                             prepStatement.setString(i + 1, value);
355                         } else {
356                             if (myType.equalsIgnoreCase(LONGVARBINARY_TYPE) || myType.equalsIgnoreCase(VARBINARY_TYPE)) {
357                                 byte[] data = (byte[]) lobAdds.get(i);
358                                 ByteArrayInputStream JavaDoc theData = new ByteArrayInputStream JavaDoc(data);
359                                 prepStatement.setBinaryStream(i + 1, theData, data.length);
360                             } else {
361                                 if (myType.equalsIgnoreCase(LONGVARCHAR_TYPE)) {
362                                     if (("oracle.jdbc.driver.OracleDriver".equals(myConnection.getDBDriver()))) {
363                                         String JavaDoc value = (String JavaDoc) lobAdds.get(i);
364                                         java.io.Reader JavaDoc theData = new StringReader JavaDoc(value);
365                                         prepStatement.setCharacterStream(i + 1, theData, value.length());
366                                     } else {
367                                         if ("interbase.interclient.Driver".equals(myConnection.getDBDriver())) {
368                                             String JavaDoc value = (String JavaDoc) lobAdds.get(i);
369                                             byte[] data = value.getBytes();
370                                             java.io.ByteArrayInputStream JavaDoc theData = new java.io.ByteArrayInputStream JavaDoc(
371                                                     data);
372                                             prepStatement.setAsciiStream(i + 1, theData, data.length);
373                                         } else {
374                                             String JavaDoc value = (String JavaDoc) lobAdds.get(i);
375                                             prepStatement.setString(i + 1, value);
376                                         }
377                                     }
378                                 } else {
379                                     String JavaDoc value = (String JavaDoc) lobAdds.get(i);
380                                     prepStatement.setString(i + 1, value);
381                                 }
382                             }
383                         }
384
385                     }
386 // if ("interbase.interclient.Driver".equals(myConnection.getDBDriver())) {
387
//
388
//Workaround, interclient 2 doesn't support setCharacterStream()
389
//
390
// byte[] data = value.getBytes();
391
// java.io.ByteArrayInputStream bis = new java.io.ByteArrayInputStream(data);
392
// prepStatement.setAsciiStream(1,bis,data.length);
393
// } else {
394
// java.io.Reader r = new java.io.StringReader(value);
395
// prepStatement.setCharacterStream(i + 1,r, value.length());
396
// }
397

398                 }
399                 myConnection.executeUpdate(null);
400                 myConnection.clearPreparedStatement();
401
402             } else {
403                 myConnection.executeUpdate(theSqlCommand);
404             }
405
406         } catch (NullPointerException JavaDoc npe) {
407             log.error("NPE", npe);
408             throw new DataException("Null Pointer Exception", npe);
409         } catch (SQLException JavaDoc ex) {
410             log.error("Error executing LOB set Character Stream", ex);
411             throw new DataException("Error setting character stream for for DBObject: "
412                     + getClass().getName(), ex);
413         } catch (DBException ex) {
414             String JavaDoc msg = myName + "add(DataObject) error: ";
415             log.error(msg, ex);
416             throw new DataException(ex.getMessage());
417         } finally {
418             if (localConnection == null) {
419                 if (myPool != null && myConnection != null) {
420                     myPool.release(myConnection);
421                 }
422             }
423         }
424
425     }
426
427     /**
428      * Takes a <code>DataObject</code> and deletes it from the underlying data source.
429      * <b>Note:</b> The current implementation only expects a <code>DBObject</code>
430      * and actually routes the call back to that object. Will be fixed in the future
431      * as the interface becomes more rich.
432      *
433      * @param valueObject the <code>DataObject</code> to delete.
434      * @throws DataException upon error deleting the object to the data source
435      */

436     public void delete(DataObject valueObject) throws DataException {
437         if (valueObject == null) {
438             throw new IllegalArgumentException JavaDoc(myName + "delete(DataObject): valueObject was null");
439         }
440         DBObject theObject = (DBObject) valueObject;
441         try {
442             theObject.delete(true);
443         } catch (DBException ex) {
444             String JavaDoc msg = myName + "delete(DataObject) error";
445             log.error(msg, ex);
446             throw new DataException(msg, ex);
447         }
448     }
449
450     /**
451      * Takes a <code>DataObject</code> and updates it to the underlying data source
452      *
453      * @param valueObject the <code>DataObject</code> to update.
454      * @param updateChangedFieldsOnly if true only modified fields (isChanged = true)
455      * will be included in the update
456      * @throws DataException upon error updating the object to the data source
457      * <p/>
458      * Modify by Yves Henri AMAIZO <amy_amaizo@compuserve.com>
459      * @since $DatabaseSchema $Date: 2004/11/18 02:03:27 $
460      */

461     public void update(DataObject valueObject, boolean updateChangedFieldsOnly) throws DataException {
462         if (valueObject == null) {
463             throw new IllegalArgumentException JavaDoc(myName + "update(DataObject): valueObject was null");
464         }
465         DBObject theObject = (DBObject) valueObject;
466
467         boolean needComma = false;
468
469         try {
470             //
471
//If myPool isn't set yet, then we need to use getDBName to
472
//reset. FIXME: Have the system throw exceptions if DBName isn't
473
//set instead.
474
//
475
DBConnectionPool myPool = DBConnectionPool.getInstance(theObject.getMappedDataContext());
476             DBConnection localConnection = theObject.getLocalConnection();
477
478             /* build an update statement - be sure we have all of the keys */
479             if (!theObject.haveAllKeys()) {
480                 throw new DataException("(" + getClass().getName() +
481                         ") All key fields not present - cannot update record");
482             }
483
484             theObject.checkAllRefsPublic();
485
486             List JavaDoc lobFieldOrder = null;
487             List JavaDoc lobFieldType = null;
488             List JavaDoc lobUpdates = null;
489             DataFieldMetaData oneField = null;
490             FastStringBuffer sqlCommand = FastStringBuffer.getInstance();
491             String JavaDoc theSqlString = null;
492             boolean fieldsUpdated = false;
493             try {
494                 sqlCommand.append("UPDATE ");
495                 sqlCommand.append(theObject.getJDBCMetaData().getTargetSQLTable(theObject.getDataContext()));
496                 sqlCommand.append(" SET ");
497
498
499                 for (Iterator JavaDoc i = valueObject.getMetaData().getFieldListArray().iterator(); i.hasNext();) {
500                     String JavaDoc oneFieldName = (String JavaDoc) i.next();
501                     oneField = theObject.getFieldMetaData(oneFieldName);
502
503                     /* We skip any key fields in the update part (not allowed to */
504                     /* update them). Also skip any virtual fields */
505                     if ((!oneField.isKey()) && (!oneField.isVirtual()) &&
506                             (!oneField.isAutoIncremented()) && (!oneField.isBinaryObjectType())) {
507
508                         if (updateChangedFieldsOnly) {
509                             // Only include changed fields in the update if required
510
if (valueObject.getDataField(oneFieldName).isValueSet() &&
511                                     theObject.getStatus().equals(DataObject.STATUS_NEW)) {
512                                 ; // noop
513
} else {
514                                 if (!valueObject.getDataField(oneFieldName).isChanged()) {
515                                     continue;
516                                 }
517                             }
518                         }
519                         theObject.checkField(oneFieldName, theObject.getField(oneFieldName));
520
521                         if (needComma) {
522                             sqlCommand.append(", ");
523                         }
524                         if (!oneField.isKey()) {
525                             fieldsUpdated = true;
526                             sqlCommand.append(oneField.getName());
527                             sqlCommand.append(" = ");
528
529                             if (oneField.isDateType()) {
530                                 Object JavaDoc tmpData = valueObject.get(oneField.getName());
531                                 String JavaDoc data;
532                                 //
533
//FIXME allow for appropriate support of other data types.
534
//
535
if (tmpData == null) {
536                                     data = null;
537                                 } else if (tmpData instanceof String JavaDoc) {
538                                     data = (String JavaDoc) tmpData;
539                                 } else {
540                                     data = tmpData.toString();
541                                 }
542                                 if (data == null || data.length() == 0) {
543                                     sqlCommand.append("null");
544                                 } else {
545                                     sqlCommand.append(JDBCUtil.getInstance()
546                                             .formatDateTime(theObject, oneField.getName()));
547                                 }
548                             } else if (oneField.isCharacterLongObjectType() || oneField.isLongObjectType()) {
549                                 //
550
//If we have a CLOB object, then we will go ahead and process
551
//it, but we execute it in a separate update
552
//
553
if (lobUpdates == null) {
554                                     lobUpdates = new ArrayList JavaDoc();
555                                     lobFieldOrder = new ArrayList JavaDoc();
556                                     lobFieldType = new ArrayList JavaDoc();
557                                 }
558                                 Object JavaDoc tmpData = valueObject.get(oneField.getName());
559                                 String JavaDoc data;
560                                 //
561
//FIXME allow for appropriate support of other data types.
562
//
563
if (tmpData == null) {
564                                     data = null;
565                                 } else if (tmpData instanceof String JavaDoc) {
566                                     data = (String JavaDoc) tmpData;
567                                 } else {
568                                     data = tmpData.toString();
569                                 }
570
571                                 lobUpdates.add(tmpData);
572                                 lobFieldOrder.add(oneFieldName);
573                                 lobFieldType.add(oneField.getTypeString());
574
575                                 sqlCommand.append("?");
576
577                             } else {
578                                 sqlCommand.append(theObject.quoteIfNeeded(oneField.getName(),
579                                         null));
580                             }
581
582                             sqlCommand.append(" ");
583                             needComma = true;
584                         }
585                     } /* if it's not a key field */
586
587                 }
588
589                 if (!fieldsUpdated) {
590                     return;
591                 }
592                 sqlCommand.append(theObject.buildWhereClause(false));
593                 theSqlString = sqlCommand.toString();
594             } finally {
595                 sqlCommand.release();
596                 sqlCommand = null;
597             }
598
599             DBConnection myConnection = null;
600
601             try {
602                 if (localConnection != null) {
603                     myConnection = localConnection;
604                 } else {
605                     myConnection = myPool.getConnection(getClass().getName());
606                 }
607
608
609                 if (lobUpdates != null) {
610
611                     java.sql.PreparedStatement JavaDoc prepStatement = null;
612                     try {
613                         prepStatement = myConnection.createPreparedStatement(theSqlString);
614
615                         int size = lobFieldOrder.size();
616                         String JavaDoc value = "";
617                         for (int i = 0; i < size; i++) {
618                             String JavaDoc myType = (String JavaDoc) lobFieldType.get(i);
619                             try {
620                                 if (!myType.equalsIgnoreCase(LONGVARBINARY_TYPE) && !myType.equalsIgnoreCase(
621                                         VARBINARY_TYPE) && !myType.equalsIgnoreCase(LONGVARCHAR_TYPE)) {
622                                     value = (String JavaDoc) lobUpdates.get(i);
623                                     prepStatement.setString(i + 1, value);
624                                 } else {
625                                     if (myType.equalsIgnoreCase(LONGVARBINARY_TYPE) || myType.equalsIgnoreCase(
626                                             VARBINARY_TYPE)) {
627                                         byte[] data = (byte[]) lobUpdates.get(i);
628                                         ByteArrayInputStream JavaDoc theData = new ByteArrayInputStream JavaDoc(data);
629                                         prepStatement.setBinaryStream(i + 1, theData, data.length);
630                                     } else {
631                                         value = (String JavaDoc) lobUpdates.get(i);
632                                         if (myType.equalsIgnoreCase(LONGVARCHAR_TYPE)) {
633                                             if (("oracle.jdbc.driver.OracleDriver".equals(myConnection.getDBDriver()))) {
634                                                 java.io.Reader JavaDoc theData = new StringReader JavaDoc(value);
635                                                 prepStatement.setCharacterStream(i + 1, theData, value.length());
636                                             } else {
637                                                 if ("interbase.interclient.Driver".equals(myConnection.getDBDriver())) {
638                                                     byte[] data = value.getBytes();
639                                                     java.io.ByteArrayInputStream JavaDoc theData = new java.io.ByteArrayInputStream JavaDoc(
640                                                             data);
641                                                     prepStatement.setAsciiStream(i + 1, theData, data.length);
642                                                 } else {
643                                                     prepStatement.setString(i + 1, value);
644                                                 }
645                                             }
646                                         } else {
647                                             prepStatement.setString(i + 1, value);
648                                         }
649                                     }
650                                 }
651
652                             } catch (SQLException JavaDoc ex) {
653                                 String JavaDoc key = (String JavaDoc) lobFieldOrder.get(i);
654                                 log.error("Error executing LOB set Character Stream", ex);
655                                 throw new DataException("Error setting character stream for field: "
656                                         + key + " with value: " + value + " for DBObject: "
657                                         + getClass().getName(), ex);
658                             } catch (Throwable JavaDoc t) {
659                                 String JavaDoc key = (String JavaDoc) lobFieldOrder.get(i);
660                                 log.error("Error executing LOB set Character Stream. SQL=" + theSqlString, t);
661                                 throw new DataException("Error setting character stream for field: "
662                                         + key + " with value: " + value + " for DBObject: "
663                                         + getClass().getName() + " SQL=" + theSqlString, t);
664                             }
665                         }
666                         myConnection.executeUpdate(null);
667                     } finally {
668                         myConnection.clearPreparedStatement();
669                     }
670                 } else {
671                     myConnection.executeUpdate(theSqlString);
672                 }
673
674                 if ((myConnection.getUpdateCount() == 0) &&
675                         (theObject.checkZeroUpdate())) {
676                     log.error("No record updated for SQL '" +
677                             theSqlString + "'");
678                     throw new DataException("(" + getClass().getName() +
679                             ") No records updated for" + theObject.forKey());
680                 }
681                 if (theObject.isCached()) {
682                     theObject.removeFromCache(theObject);
683                 }
684             } catch (NullPointerException JavaDoc npe) {
685                 npe.printStackTrace();
686                 throw new DataException(npe);
687             } finally {
688                 if (localConnection == null) {
689                     if (myPool != null && myConnection != null) {
690                         myPool.release(myConnection);
691                     }
692                 }
693             }
694         } catch (DBException ex) {
695             String JavaDoc msg = myName + "update(DataObject) error";
696             log.error(msg, ex);
697             throw new DataException(ex.getMessage());
698         }
699     }
700
701     /**
702      * Retrieves the object with keys specified by the valueObject parameter.
703      * This has the same semantics as <code>DBObject</code>'s retrieve method.
704      *
705      * @param valueObject the DataObject who's keys are already set to retrieve
706      * @return true if the data object was successfully retrieved
707      * @throws DataException Modify by Yves Henri AMAIZO <amy_amaizo@compuserve.com>
708      * @since $DatabaseSchema $Date: 2004/11/18 02:03:27 $
709      */

710     public boolean retrieve(DataObject valueObject) throws DataException {
711         if (valueObject == null) {
712             throw new IllegalArgumentException JavaDoc(myName + "retrieve(DataObject): valueObject was null");
713         }
714         DBObject theObject = (DBObject) valueObject;
715         JDBCObjectMetaData metadata = (JDBCObjectMetaData) valueObject.getMetaData();
716
717         boolean needComma = false;
718         DataFieldMetaData oneField = null;
719
720         boolean anyFieldsDistinct = false;
721         try {
722             ArrayList JavaDoc distinctFields = theObject.getDistinctFieldArrayList();
723             anyFieldsDistinct = (distinctFields.size() > 0);
724             if (!theObject.haveAllKeys() && !anyFieldsDistinct) {
725                 throw new DataException("(" + getClass().getName() +
726                         ") All key fields not present - cannot retrieve record");
727             }
728             if (theObject.retrieveFromCache()) {
729                 return true;
730             }
731
732 // FastStringBuffer myStatement = new FastStringBuffer(128);
733
FastStringBuffer myStatement = FastStringBuffer.getInstance();
734             String JavaDoc theSqlStatement = null;
735             try {
736                 myStatement.append("SELECT ");
737
738                 if (theObject.getFieldsToRetrieveCount() > 0) {
739                     String JavaDoc oneFieldName = null;
740                     Map JavaDoc retrieveFieldNames = new HashMap JavaDoc(10);
741
742                     for (Iterator JavaDoc i = theObject.getFieldsToRetrieveIterator(); i.hasNext();) {
743                         oneFieldName = (String JavaDoc) i.next();
744                         retrieveFieldNames.put(oneFieldName, null);
745
746                         if (needComma) {
747                             myStatement.append(", ");
748                         }
749
750                         myStatement.append(theObject.selectFieldString(oneFieldName));
751                         needComma = true;
752                     } /* for each field */
753
754                     for (Iterator JavaDoc i = theObject.getMetaData().getKeyFieldListArray().iterator();
755                          i.hasNext();) {
756                         String JavaDoc curFieldName = (String JavaDoc) i.next();
757                         oneField = theObject.getFieldMetaData(curFieldName);
758
759                         if (!retrieveFieldNames.containsKey(curFieldName)) {
760                             if (needComma) {
761                                 myStatement.append(", ");
762                             }
763
764                             myStatement.append(theObject.selectFieldString(curFieldName));
765                             needComma = true;
766                         }
767                     }
768                 } else { /* for each key field */
769                     for (Iterator JavaDoc i = metadata.getAllFieldsMap().values().iterator(); i.hasNext();) {
770                         oneField = (DBField) i.next();
771                         //We aren't retrieving long objects
772
if (oneField.isBinaryObjectType()) {
773                             continue;
774                         }
775
776                         if (!oneField.isVirtual()) {
777                             if (needComma) {
778                                 myStatement.append(", ");
779                             }
780
781                             myStatement.append(theObject.selectFieldString(oneField.getName()));
782                             needComma = true;
783                         } /* if field is not virtual */
784
785                     } /* for */
786
787                 } /* if anyFieldsToRetrieve */
788
789
790                 myStatement.append(" FROM ");
791                 myStatement.append(theObject.getJDBCMetaData().getTargetSQLTable(theObject.getDataContext()));
792
793
794                 String JavaDoc customWhereClause = theObject.getCustomWhereClause();
795
796                 if (customWhereClause != null) {
797                     log.warn("Custom Where clauses don't make sense for " +
798                             "DataObject.retrieve(), since it's based upon key fields. Ignoring:" +
799                             customWhereClause);
800                 }
801
802                 myStatement.append(theObject.buildWhereClause(false));
803                 theSqlStatement = myStatement.toString();
804             } finally {
805                 myStatement.release();
806                 myStatement = null;
807             }
808
809             DBConnection myConnection = null;
810
811             //
812
//If myPool isn't set yet, then we need to use getDBName to
813
//reset. FIXME: Have the system throw exceptions if DBName isn't
814
//set instead.
815
//
816
DBConnectionPool myPool = DBConnectionPool.getInstance(theObject.getMappedDataContext());
817             DBConnection localConnection = theObject.getLocalConnection();
818             if (localConnection != null) {
819                 myConnection = localConnection;
820             } else {
821                 myConnection = myPool.getConnection(getClass().getName());
822             }
823
824             try {
825
826                 myConnection.execute(theSqlStatement);
827
828                 FastStringBuffer oneKeyString = FastStringBuffer.getInstance();
829                 try {
830                     String JavaDoc oneFieldValue = "";
831                     Object JavaDoc tmpData = null;
832                     if (myConnection.next()) {
833                         //Clear all non-key fields
834
for (Iterator JavaDoc allFields = theObject.getMetaData().getFieldListArray().iterator();
835                              allFields.hasNext();) {
836                             String JavaDoc oneFieldName = (String JavaDoc) allFields.next();
837                             DataFieldMetaData fieldMetaData = theObject.getFieldMetaData(oneFieldName);
838                             if (!fieldMetaData.isKey() && !fieldMetaData.isBinaryObjectType() && !fieldMetaData.isVirtual()) {
839                                 theObject.set(oneFieldName, null);
840                             }
841                         }
842
843                         int i = 1;
844
845                         Iterator JavaDoc it;
846                         if (theObject.getFieldsToRetrieveCount() > 0) {
847                             //
848
//We have to load up a metadata array based upon the
849
//order of the field names as specified in the the
850
//getFieldsToRetrieveIterator() function.
851
//
852
ArrayList JavaDoc dbFieldArray = new ArrayList JavaDoc(theObject.getFieldsToRetrieveCount());
853                             for (Iterator JavaDoc j = theObject.getFieldsToRetrieveIterator(); j.hasNext();) {
854                                 String JavaDoc theFieldName = (String JavaDoc) j.next();
855                                 dbFieldArray.add(theObject.getFieldMetaData(theFieldName));
856                             }
857
858                             it = dbFieldArray.iterator();
859
860                         } else {
861                             it = metadata.getAllFieldsMap().values().iterator();
862                         }
863
864                         while (it.hasNext()) {
865                             oneField = (DBField) it.next();
866
867                             if (!oneField.isVirtual()) {
868                                 if (oneField.isBinaryObjectType()) {
869                                     continue;
870                                 }
871
872                                 try {
873                                     // * @author Yves Henri AMAIZO
874
// Handle correctly date from resultSet data retrieve from Database
875
if (oneField.isDateType()) {
876                                         tmpData = theObject.getCustomStringFieldValue(myConnection, oneField.getName());
877                                     } else {
878                                         if (!oneField.isLongBinaryType() && !oneField.isLongCharacterType()) {
879                                             if (myConnection.isStringNotTrim()) {
880                                                 tmpData = myConnection.getStringNoTrim(i);
881                                             } else {
882                                                 tmpData = myConnection.getString(i);
883                                             }
884                                         } else {
885                                             if (oneField.isLongBinaryType()) {
886                                                 tmpData = null;
887                                                 InputStream JavaDoc is = myConnection.getBinaryStream(i);
888                                                 if (is != null) {
889                                                     byte[] bstr = new byte[LONGBINARY_READ_DEFAULT_SIZE];
890                                                     int j = is.read(bstr);
891                                                     if (j > 0) {
892                                                         byte[] content = new byte[j];
893                                                         System.arraycopy(bstr, 0, content, 0, j);
894                                                         tmpData = content;
895                                                     }
896                                                 }
897                                             } else {
898                                                 tmpData = myConnection.getStringNoTrim(i);
899                                             }
900
901                                         }
902                                     }
903                                 } catch (DBException de1) {
904                                     throw new DataException("(" + getClass().getName() +
905                                             ") Error retrieving field '" +
906                                             oneField.getName() +
907                                             "' index " + i + ":" +
908                                             de1.getMessage(),
909                                             de1.getDBMessage());
910                                 } catch (Exception JavaDoc de1) {
911                                     throw new DataException("Not DBException(" + getClass().getName() +
912                                             ") Error retrieving field '" +
913                                             oneField.getName() +
914                                             "' index " + i + ":" +
915                                             de1.getMessage(),
916                                             de1.getMessage());
917                                 }
918
919                                 i++;
920 // theObject.set(oneField.getName(), oneFieldValue);
921
theObject.set(oneField.getName(), tmpData);
922                             }
923
924                             if (oneField.isKey()) {
925                                 if (i > 1) {
926                                     oneKeyString.append("/");
927                                 }
928
929                                 oneKeyString.append(oneFieldValue);
930                             }
931                         }
932                         theObject.addFoundKeys(oneKeyString.toString());
933                     } else {
934                         //There were zero results returned by the retrieve() call.
935
return false;
936                     }
937                 } finally {
938                     oneKeyString.release();
939                     oneKeyString = null;
940                 }
941
942             } finally {
943                 if (localConnection == null) {
944                     if (myPool != null && myConnection != null) {
945                         myPool.release(myConnection);
946                     }
947                 }
948             }
949         } catch (DBException ex) {
950             String JavaDoc msg = myName + "retrieve(DataObject) error";
951             log.error(msg, ex);
952             throw new DataException(msg, ex);
953         }
954
955         return true;
956     }
957
958
959     /**
960      * Adds an entire batch of <code>DataObject</code>s to the underlying JDBC data source
961      *
962      * @param valueObjectList A list of <code>DataObject</code>s to add to the underlying
963      * data source <b>NOTE:</b> you will get best performance if valueObjectList is
964      * all one dataobject underneath.
965      * <p/>
966      * WARNING: I DON'T UNDERSTAND WHY LOOP VAR ISN'T USED BELOW, AND SUSPECT THIS METHOD ISN'T DOING ALL IT PURPORTS TO DO; SEE "todo" (Larry Hamel, 3/03)
967      * @throws DataException upon error communicating with the underlying data source
968      * @throws DuplicateKeyException if one of the records was already in the
969      * data source
970      */

971     public void addBatch(List JavaDoc valueObjectList) throws DataException, DuplicateKeyException {
972         if (valueObjectList == null) {
973             throw new IllegalArgumentException JavaDoc(myName + "addBatch(List): valueObjectArray was null");
974         }
975         addBatch(valueObjectList, false);
976     }
977
978     /**
979      * Updates an entire batch of <code>DataObject</code>s
980      *
981      * @param valueObjectList A list of <code>DataObject</code>s to update to the underlying
982      * data source
983      * @throws DataException upon error updating the data source
984      */

985     public void updateBatch(List JavaDoc valueObjectList) throws DataException {
986         if (valueObjectList == null) {
987             throw new IllegalArgumentException JavaDoc(myName + "updateBatch(List): valueObjectArray was null");
988         }
989         updateBatch(valueObjectList, false);
990
991     }
992
993     /**
994      * Helper function to build a prepared update statement for batch updates.
995      *
996      * @param oneObjectType A single <code>DataObject</code> that is used to model the prepared
997      * statement. Only metadata about the <code>DataObject</code> is used.
998      * @param updateChangedFieldsOnly true if the changed fields should be the
999      * only ones sent through the SQL query.
1000     * @return A <code>FastStringBuffer</code> containing the proper SQL to create
1001     * a preparedStatement
1002     * @throws DBException upon error
1003     * <p/>
1004     * Modify by Yves Henri AMAIZO <amy_amaizo@compuserve.com>
1005     * @since $DatabaseSchema $Date: 2004/11/18 02:03:27 $
1006     */

1007    protected String JavaDoc buildPreparedUpdateSQL(DataObject oneObjectType, boolean updateChangedFieldsOnly) throws DBException {
1008        DBObject theObject = (DBObject) oneObjectType;
1009
1010        FastStringBuffer sqlCommand = FastStringBuffer.getInstance();
1011        FastStringBuffer whereClause = FastStringBuffer.getInstance();
1012        String JavaDoc returnValue = null;
1013        try {
1014            sqlCommand.append("UPDATE ");
1015            sqlCommand.append(theObject.getJDBCMetaData().getTargetSQLTable(theObject.getDataContext()));
1016            sqlCommand.append(" SET ");
1017
1018            whereClause.append(" WHERE ");
1019
1020            DataFieldMetaData oneField = null;
1021            boolean needComma = false;
1022            boolean needWhereComma = false;
1023
1024            for (Iterator JavaDoc i = theObject.getMetaData().getFieldListArray().iterator(); i.hasNext();) {
1025                String JavaDoc oneFieldName = (String JavaDoc) i.next();
1026                oneField = theObject.getFieldMetaData(oneFieldName);
1027
1028                // Only include changed fields in the update if required
1029
if (updateChangedFieldsOnly) {
1030                    if (theObject.getDataField(oneFieldName).isValueSet() && theObject.getStatus().equals(
1031                            DataObject.STATUS_NEW)) {
1032                        ;
1033                    } else {
1034                        if (!theObject.getDataField(oneFieldName).isChanged()) {
1035                            continue;
1036                        }
1037                    }
1038                }
1039
1040                /* We skip any key fields in the update part (not allowed to */
1041                /* upate them). Also skip any virtual fields */
1042                if ((!oneField.isKey()) && (!oneField.isVirtual()) &&
1043                        (!oneField.isAutoIncremented()) && (!oneField.isBinaryObjectType())) {
1044
1045                    if (needComma) {
1046                        sqlCommand.append(", ");
1047                    }
1048
1049                    sqlCommand.append(oneField.getName());
1050                    sqlCommand.append(" = ? ");
1051                    needComma = true;
1052                } else if (oneField.isKey()) {
1053                    if (needWhereComma) {
1054// whereClause.append(", ");
1055
whereClause.append(" AND ");
1056                    }
1057
1058                    whereClause.append(oneField.getName());
1059                    whereClause.append(" = ? ");
1060                    needWhereComma = true;
1061                }
1062
1063            }
1064
1065            sqlCommand.append(whereClause);
1066            returnValue = sqlCommand.toString();
1067        } finally {
1068            whereClause.release();
1069            sqlCommand.release();
1070            whereClause = null;
1071            sqlCommand = null;
1072        }
1073
1074        return returnValue;
1075    }
1076
1077
1078    /**
1079     * Helper function to build a prepared delete statement for batch deletes.
1080     *
1081     * @param oneObjectType A single <code>DataObject</code> that is used to model the prepared
1082     * statement. Only metadata about the <code>DataObject</code> is used.
1083     * @return A <code>FastStringBuffer</code> containing the proper SQL to create
1084     * a preparedStatement
1085     * @throws DBException upon error
1086     * <p/>
1087     * Modify by Yves Henri AMAIZO <amy_amaizo@compuserve.com>
1088     * @since $DatabaseSchema $Date: 2004/11/18 02:03:27 $
1089     */

1090    protected String JavaDoc buildPreparedDeleteSQL(DataObject oneObjectType, boolean deleteWithSetFieldsOnly) throws DBException {
1091        DBObject theObject = (DBObject) oneObjectType;
1092
1093        FastStringBuffer sqlCommand = FastStringBuffer.getInstance();
1094        FastStringBuffer whereClause = FastStringBuffer.getInstance();
1095        String JavaDoc returnValue = null;
1096        try {
1097            sqlCommand.append("DELETE FROM ");
1098            sqlCommand.append(theObject.getJDBCMetaData().getTargetSQLTable(theObject.getDataContext()));
1099
1100            whereClause.append(" WHERE ");
1101
1102            DataFieldMetaData oneField = null;
1103            boolean needComma = false;
1104            boolean needWhereComma = false;
1105
1106            for (Iterator JavaDoc i = theObject.getMetaData().getFieldListArray().iterator(); i.hasNext();) {
1107                String JavaDoc oneFieldName = (String JavaDoc) i.next();
1108                oneField = theObject.getFieldMetaData(oneFieldName);
1109
1110                // Only include changed fields in the update if required
1111
if (deleteWithSetFieldsOnly) {
1112                    if (theObject.getDataField(oneFieldName).isValueSet() && theObject.getStatus().equals(
1113                            DataObject.STATUS_NEW)) {
1114                        ;
1115                    } else {
1116                        if (!theObject.getDataField(oneFieldName).isChanged()) {
1117                            continue;
1118                        }
1119                    }
1120                }
1121
1122                /* We skip any key fields in the update part (not allowed to */
1123                /* upate them). Also skip any virtual fields */
1124                if ((!oneField.isKey()) && (!oneField.isVirtual()) &&
1125                        (!oneField.isAutoIncremented()) && (!oneField.isBinaryObjectType())) {
1126
1127                    if (needComma) {
1128                        sqlCommand.append(", ");
1129                    }
1130
1131                    sqlCommand.append(oneField.getName());
1132                    sqlCommand.append(" = ? ");
1133                    needComma = true;
1134                } else if (oneField.isKey()) {
1135                    if (needWhereComma) {
1136                        whereClause.append(" AND ");
1137                    }
1138
1139                    whereClause.append(oneField.getName());
1140                    whereClause.append(" = ? ");
1141                    needWhereComma = true;
1142                }
1143
1144            }
1145
1146            sqlCommand.append(whereClause);
1147            returnValue = sqlCommand.toString();
1148        } finally {
1149            whereClause.release();
1150            sqlCommand.release();
1151            whereClause = null;
1152            sqlCommand = null;
1153        }
1154
1155        return returnValue;
1156    }
1157
1158
1159    /**
1160     * Helper Function to build a prepared statement's SQL for an ADD statement.
1161     *
1162     * @param oneObjectType A single <code>DataObject</code> that is used to model the prepared
1163     * statement. Only metadata about the <code>DataObject</code> is used.
1164     * @param addChangedFieldsOnly flag to signify if only fields whose value
1165     * has changed should be included in the add.
1166     * @return a FastStringBuffer containing the build sql statement
1167     * @throws DBException upon error
1168     * <p/>
1169     * Modify by Yves Henri AMAIZO <amy_amaizo@compuserve.com>
1170     * @since $DatabaseSchema $Date: 2004/11/18 02:03:27 $
1171     */

1172    protected String JavaDoc buildPreparedAddSQL(DataObject oneObjectType, boolean addChangedFieldsOnly) throws DBException {
1173        DBObject theObject = (DBObject) oneObjectType;
1174        /**
1175         * sqlCommand will eventually = sqlCommand + valuesCommand. The two
1176         * are assembled in parallel in the loop below.
1177         */

1178        FastStringBuffer sqlCommand = FastStringBuffer.getInstance();
1179        FastStringBuffer valuesCommand = FastStringBuffer.getInstance();
1180        String JavaDoc returnValue = null;
1181        try {
1182            sqlCommand.append("INSERT INTO ");
1183            sqlCommand.append(theObject.getJDBCMetaData().getTargetSQLTable(theObject.getDataContext()));
1184            sqlCommand.append(" (");
1185
1186            valuesCommand.append(") VALUES (");
1187
1188            DataFieldMetaData oneField = null;
1189            boolean needCommaValues = false;
1190            for (Iterator JavaDoc i = theObject.getMetaData().getFieldListArray().iterator(); i.hasNext();) {
1191                String JavaDoc oneFieldName = (String JavaDoc) i.next();
1192                oneField = theObject.getFieldMetaData(oneFieldName);
1193
1194
1195                // Only include changed fields in the add if required
1196
if (addChangedFieldsOnly) {
1197                    if (theObject.getDataField(oneFieldName).isValueSet() && theObject.getStatus().equals(
1198                            DataObject.STATUS_NEW)) {
1199                        ;
1200                    } else {
1201                        if (!theObject.getDataField(oneFieldName).isChanged()) {
1202                            continue;
1203                        }
1204                    }
1205                }
1206
1207                if (!oneField.isVirtual() && !oneField.isBinaryObjectType()) {
1208                    if (needCommaValues) {
1209                        sqlCommand.append(", ");
1210                        valuesCommand.append(", ");
1211                    }
1212                    sqlCommand.append(oneField.getName());
1213                    valuesCommand.append(" ? ");
1214                    needCommaValues = true;
1215                }
1216
1217            } /* for each field */
1218
1219
1220            //Now we merge the values of the parallel loops
1221
sqlCommand.append(valuesCommand);
1222            sqlCommand.append(")");
1223            returnValue = sqlCommand.toString();
1224        } finally {
1225            sqlCommand.release();
1226            valuesCommand.release();
1227            sqlCommand = null;
1228            valuesCommand = null;
1229        }
1230
1231        return returnValue;
1232
1233    }
1234
1235
1236    /**
1237     * Format the field for storage into a prepared statement. This is similar
1238     * to the old <code>DBObject.quoteIfNeeded()</code> but it does not insert
1239     * quotes around the values since the prepared statements will take care
1240     * of special characters like that
1241     *
1242     * @param oneField The metadata of the field to retrieve
1243     * @param theObj The <code>DBObject</code> that contains the data to store.
1244     * @return java.lang.String for the appropriate data value.
1245     */

1246    protected String JavaDoc prepareForStorage(DataFieldMetaData oneField, DBObject theObj)
1247            throws DBException {
1248        return prepareForStorage(oneField, theObj, true);
1249    }
1250
1251    /**
1252     * Format the field for storage into a prepared statement. This is similar
1253     * to the old <code>DBObject.quoteIfNeeded()</code> but it does not insert
1254     * quotes around the values since the prepared statements will take care
1255     * of special characters like that
1256     *
1257     * @param oneField The metadata of the field to retrieve
1258     * @param theObj The <code>DBObject</code> that contains the data to store.
1259     * @return java.lang.String for the appropriate data value.
1260     */

1261    protected String JavaDoc prepareForStorage(DataFieldMetaData oneField, DBObject theObj, boolean dateFormatted)
1262            throws DBException {
1263        //String fieldName = oneField.getName();
1264
String JavaDoc fieldValue = theObj.getSerializedForm((DBField) oneField);
1265
1266        /* if the field is null, we don't need to worry about quotes */
1267        if (fieldValue == null) {
1268            return null;
1269        }
1270
1271        if (oneField.isNumericType()) {
1272            if (fieldValue.equals("")) {
1273                return "0";
1274            }
1275
1276            return fieldValue.trim();
1277        } /* if a numeric type */
1278
1279
1280        if (oneField.isDateType()) {
1281            if (dateFormatted) {
1282                return JDBCUtil.getInstance().formatDateTime(theObj, oneField.getName(), false);
1283            }
1284            return fieldValue.trim();
1285        } else if (oneField.isBooleanType()) {
1286            try {
1287                boolean nativeBoolean = ConfigManager.getContext(theObj.getDataContext()).getJdbc().isNativeBool();
1288
1289                if (!nativeBoolean) {
1290                    FastStringBuffer returnValue = FastStringBuffer.getInstance();
1291                    String JavaDoc returnString = null;
1292                    try {
1293                        returnValue.append(fieldValue.trim());
1294                        returnString = returnValue.toString();
1295                    } finally {
1296                        returnValue.release();
1297                        returnValue = null;
1298                    }
1299                    return returnString;
1300                }
1301            } catch (ConfigurationException ce) {
1302                throw new DBException(ce);
1303            }
1304        }
1305
1306        return fieldValue.trim();
1307    } /* quoteIfNeeded(String) */
1308
1309    private boolean haveAllKeysExceptAutoInc(DBObject valueObject) throws DBException {
1310        DBField oneField = null;
1311
1312        for (Iterator JavaDoc i = valueObject.getJDBCMetaData().getAllKeysMap().values().iterator(); i.hasNext();) {
1313            oneField = (DBField) i.next();
1314            DataField df = valueObject.getDataField(oneField.getName());
1315            if (df == null || (df.isNull() && !df.getFieldMetaData().isAutoIncremented())) {
1316                return false;
1317            }
1318        }
1319
1320        return true;
1321    }
1322
1323    /**
1324     * Takes a <code>DataObject</code> and updates all to the underlying data source
1325     *
1326     * @param valueObject the <code>DataObject</code> to update.
1327     * @param updateChangedCache if true only modified fields (isChanged = true)
1328     * will be included in the update
1329     * @throws DataException upon error updating the object to the data source
1330     * <p/>
1331     * Modify by Yves Henri AMAIZO <amy_amaizo@compuserve.com>
1332     * @since $DatabaseSchema $Date: 2004/11/18 02:03:27 $
1333     */

1334    public void updateAll(DataObject valueObject, boolean updateChangedCache)
1335            throws DataException {
1336        if (valueObject == null) {
1337            throw new IllegalArgumentException JavaDoc(myName + "updateAll(DataObject): valueObject was null");
1338        }
1339        DBObject theObject = (DBObject) valueObject;
1340
1341        try {
1342            theObject.updateAll(false);
1343        } catch (DBException ex) {
1344            String JavaDoc msg = myName + "updateAll(DataObject) error";
1345            log.error(msg, ex);
1346            throw new DataException(msg, ex);
1347        }
1348
1349    }
1350
1351    /**
1352     * Takes a <code>DataObject</code> and deletes it from the underlying data source.
1353     * <b>Note:</b> The current implementation only expects a <code>DBObject</code>
1354     * and actually routes the call back to that object. Will be fixed in the future
1355     * as the interface becomes more rich.
1356     *
1357     * @param valueObject the <code>DataObject</code> to delete.
1358     * @throws DataException upon error deleting the object to the data source
1359     */

1360    public void deleteAll(DataObject valueObject, boolean deleteChangedCache) throws DataException {
1361        if (valueObject == null) {
1362            throw new IllegalArgumentException JavaDoc(myName + "deleteAll(DataObject): valueObject was null");
1363        }
1364        DBObject theObject = (DBObject) valueObject;
1365        try {
1366            theObject.deleteAll(false);
1367        } catch (DBException ex) {
1368            String JavaDoc msg = myName + "deleteAll(DataObject) error";
1369            log.error(msg, ex);
1370            throw new DataException(msg, ex);
1371        }
1372
1373    }
1374
1375
1376    /**
1377     * Helper Function to build a prepared statement's SQL for running STore Procedure statement.
1378     *
1379     * @param oneObjectType A single <code>DataObject</code> that is used to model the prepared
1380     * statement. Only metadata about the <code>DataObject</code> is used.
1381     * @return a FastStringBuffer containing the build sql statement
1382     * @throws DBException upon error
1383     */

1384    protected String JavaDoc buildPreparedStoreProcedureSQL(DataObject oneObjectType) throws DBException {
1385        DBObject theObject = (DBObject) oneObjectType;
1386        /**
1387         * sqlCommand
1388         *
1389         */

1390        FastStringBuffer sqlCommand = FastStringBuffer.getInstance();
1391        FastStringBuffer valuesCommand = FastStringBuffer.getInstance();
1392        String JavaDoc returnValue = null;
1393        try {
1394            int nbParams = theObject.getDef().getFieldListArray().size();
1395
1396            if (theObject.getDef().isReturningValue()) {
1397                sqlCommand.append("{? = call ");
1398                nbParams--;
1399            } else {
1400                sqlCommand.append("{call ");
1401            }
1402            sqlCommand.append(theObject.getJDBCMetaData().getTargetTable());
1403
1404            if (nbParams > 0) {
1405                sqlCommand.append("(?");
1406                for (int i = 1; i < nbParams; i++) {
1407                    sqlCommand.append(", ?");
1408                }
1409                sqlCommand.append(")");
1410            }
1411            sqlCommand.append("}");
1412
1413            returnValue = sqlCommand.toString();
1414        } finally {
1415            sqlCommand.release();
1416            valuesCommand.release();
1417            sqlCommand = null;
1418            valuesCommand = null;
1419        }
1420
1421        return returnValue;
1422
1423    }
1424
1425    /**
1426     * Build and return a FastStringBuffer ring consisting of an SQL 'where' clause
1427     * using the current field values as criteria for the search. See
1428     * setCustomWhereClause for information on specifying a more complex where clause.
1429     *
1430     * @param criteria the JDBCDataObject to build from
1431     * @param myCallableStatement the statement
1432     * @return A FastStringBuffer containing the "where" clause for the SQL statement
1433     * @throws DataException upon error
1434     */

1435    protected void buildStoreProcedureCallableStatement(DBObject criteria, CallableStatement JavaDoc myCallableStatement)
1436            throws DataException {
1437        Iterator JavaDoc fieldsToUse = null;
1438        FastStringBuffer myStatement = FastStringBuffer.getInstance();
1439
1440        fieldsToUse = criteria.getMetaData().getFieldListArray().iterator();
1441
1442        /* Now go thru each field - if it is non-empty, add it's criteria */
1443
1444        DataFieldMetaData oneField = null;
1445        String JavaDoc oneFieldName = null;
1446        String JavaDoc oneFieldValue = null;
1447        boolean postgresql = false;
1448        boolean skipText = false;
1449        boolean skipField = false;
1450        boolean inField = false;
1451        boolean outField = false;
1452        TypeMapper typeMapper = null;
1453
1454        try {
1455            ConfigJdbc myConfig = ConfigManager.getJdbcRequired(criteria.getMappedDataContext());
1456            skipText = myConfig.skipText();
1457            //We have to do this because postgres won't be smart enough to
1458
//cast floating point literals to truly a floating point value. :(
1459
if ("org.postgresql.Driver".equals(myConfig.getDriver())) {
1460                postgresql = true;
1461            }
1462            typeMapper = TypeMapper.getInstance(criteria.getDataContext());
1463        } catch (ConfigurationException ce) {
1464            throw new DataException(ce);
1465        } catch (DBException de) {
1466            throw new DataException(de);
1467        }
1468
1469        try {
1470            while (fieldsToUse.hasNext()) {
1471                oneFieldName = (String JavaDoc) fieldsToUse.next();
1472                oneField = criteria.getFieldMetaData(oneFieldName);
1473                skipField = false;
1474                skipText = false;
1475                inField = false;
1476                outField = false;
1477                if (oneField.isVirtual()) {
1478                    skipField = true;
1479                }
1480                if (criteria.getDef().isInField(oneField.getName())) {
1481                    inField = true;
1482                }
1483                if (criteria.getDef().isOutField(oneField.getName())) {
1484                    outField = true;
1485                }
1486                try {
1487                    oneFieldValue = StringUtil.notNull(criteria.getDataField(oneField.getName()).asString());
1488                } catch (DBException ex) {
1489                    if (ex instanceof DataException) {
1490                        throw ((DataException) ex);
1491                    } else {
1492                        throw new DataException("Error getting field value", ex);
1493                    }
1494                }
1495
1496                if (oneField.isNumericType() || oneField.isFloatingPointType() || oneField.isDateType()) {
1497                    if ((oneFieldValue == null || "null".equals(oneFieldValue) || oneFieldValue.length() == 0)
1498                            && inField) {
1499                        myCallableStatement.setNull(Integer.parseInt(oneFieldName),
1500                                typeMapper.getJavaSQLType(oneField.getTypeString()));
1501                    } else {
1502                        if (oneField.isNumericType()) {
1503                            if (inField) {
1504// myCallableStatement.setInt(Integer.parseInt(oneFieldName), Integer.parseInt(oneFieldValue));
1505
if (oneField.getTypeString().equalsIgnoreCase("integer") ||
1506                                        oneField.getTypeString().equalsIgnoreCase("numeric") ||
1507                                        oneField.getTypeString().equalsIgnoreCase("tinyint") ||
1508                                        oneField.getTypeString().equalsIgnoreCase("smallint")) {
1509                                    myCallableStatement.setInt(Integer.parseInt(oneFieldName),
1510                                            Integer.parseInt(oneFieldValue));
1511                                } else if (oneField.getTypeString().equalsIgnoreCase("float") ||
1512                                        oneField.getTypeString().equalsIgnoreCase("real")) {
1513                                    myCallableStatement.setFloat(Integer.parseInt(oneFieldName),
1514                                            Float.parseFloat(oneFieldValue));
1515                                } else if (oneField.getTypeString().equalsIgnoreCase("bigint") ||
1516                                        oneField.getTypeString().equalsIgnoreCase("decimal")) {
1517                                    myCallableStatement.setLong(Integer.parseInt(oneFieldName),
1518                                            Long.parseLong(oneFieldValue));
1519                                } else if (oneField.getTypeString().equalsIgnoreCase("double")) {
1520                                    myCallableStatement.setDouble(Integer.parseInt(oneFieldName),
1521                                            Double.parseDouble(oneFieldValue));
1522                                }
1523                            } else {
1524                                myCallableStatement.registerOutParameter(Integer.parseInt(oneFieldName),
1525                                        typeMapper.getJavaSQLType(oneField.getTypeString()));
1526                            }
1527                        } else if (oneField.isDateTimeType()) {
1528                            if (inField) {
1529                                if (oneField.isDateOnlyType()) {
1530                                    myCallableStatement.setDate(Integer.parseInt(oneFieldName),
1531                                            java.sql.Date.valueOf(oneFieldValue));
1532                                }
1533                                if (oneField.isDateTimeType()) {
1534                                    myCallableStatement.setTimestamp(Integer.parseInt(oneFieldName),
1535                                            java.sql.Timestamp.valueOf(oneFieldValue));
1536                                }
1537                            } else {
1538                                myCallableStatement.registerOutParameter(Integer.parseInt(oneFieldName),
1539                                        typeMapper.getJavaSQLType(oneField.getTypeString()));
1540                            }
1541                        } else if (oneField.isFloatingPointType()) {
1542                            if (inField) {
1543                                myCallableStatement.setFloat(Integer.parseInt(oneFieldName),
1544                                        Float.parseFloat(oneFieldValue));
1545                            } else {
1546                                myCallableStatement.registerOutParameter(Integer.parseInt(oneFieldName),
1547                                        typeMapper.getJavaSQLType(oneField.getTypeString()), oneField.getPrecision());
1548                            }
1549                        }
1550                    }
1551                } else if (oneField.isBooleanType()) {
1552                    ;
1553                } else {
1554                    if (oneField.getTypeString().equalsIgnoreCase("text")) {
1555                        if (oneFieldValue.indexOf("\n") > 0) {
1556                            oneFieldValue = StringUtil.replace(oneFieldValue, "\n", "");
1557                        }
1558                        if (oneFieldValue.indexOf("\r") > 0) {
1559                            oneFieldValue = StringUtil.replace(oneFieldValue, "\r", "");
1560                        }
1561                    }
1562                    if (inField) {
1563                        myCallableStatement.setString(Integer.parseInt(oneFieldName), oneFieldValue);
1564                    }
1565                    if (outField) {
1566                        myCallableStatement.registerOutParameter(Integer.parseInt(oneFieldName),
1567                                typeMapper.getJavaSQLType(oneField.getTypeString()));
1568                    }
1569                }
1570            } /* end of while(fieldsToUse.hasNext() */
1571            /* for each field */
1572        } catch (DBException e) {
1573            throw new DataException(e);
1574        } catch (SQLException JavaDoc ce) {
1575            throw new DataException(ce);
1576        } finally {
1577            myStatement.release();
1578            myStatement = null;
1579        }
1580        if (log.isDebugEnabled()) {
1581            log.debug("Built callable statement for store procedure ");
1582        }
1583    } /* buildStoreProcedureCallableStatement(DBObject, boolean, CallableStatement) */
1584
1585    /**
1586     * Run a store procedure identify by the object with keys specified by the
1587     * valueObject parameter.
1588     *
1589     * @param valueObject the DataObject who's keys are already set to retrieve
1590     * @return true if the data object was successfully retrieved
1591     */

1592    public void runStoreProcedure(DataObject valueObject)
1593            throws DataException {
1594        if (valueObject == null) {
1595            throw new IllegalArgumentException JavaDoc(myName + "run(DataObject): valueObject was null");
1596        }
1597        DBObject theObject = (DBObject) valueObject;
1598        DataFieldMetaData oneField = null;
1599
1600        try {
1601            String JavaDoc theSqlStatement = buildPreparedStoreProcedureSQL(valueObject);
1602
1603            DBConnection myConnection = null;
1604
1605            DBConnectionPool myPool = DBConnectionPool.getInstance(theObject.getMappedDataContext());
1606            DBConnection localConnection = theObject.getLocalConnection();
1607            if (localConnection != null) {
1608                myConnection = localConnection;
1609            } else {
1610                myConnection = myPool.getConnection(getClass().getName());
1611            }
1612
1613            try {
1614                CallableStatement JavaDoc myStatement = myConnection.createCallableStatement(theSqlStatement);
1615                buildStoreProcedureCallableStatement(theObject, myStatement);
1616                String JavaDoc oneFieldValue = null;
1617                String JavaDoc oneFieldName = null;
1618                myConnection.executeProcedure();
1619                try {
1620                    if (myConnection.getResultSet() != null) {
1621                        //Clear all non-key fields
1622
for (Iterator JavaDoc allFields = theObject.getMetaData().getFieldListArray().iterator(); allFields.hasNext();) {
1623                            oneFieldName = (String JavaDoc) allFields.next();
1624                            DataFieldMetaData fieldMetaData = theObject.getFieldMetaData(oneFieldName);
1625                            if (!fieldMetaData.isKey() && !fieldMetaData.isBinaryObjectType() && !fieldMetaData.isVirtual()) {
1626                                theObject.set(oneFieldName, null);
1627                            }
1628                        }
1629                        int fieldNum = 0;
1630                        Iterator JavaDoc it;
1631                        if (theObject.getDef().getOutParamFieldsCount() > 0) {
1632                            //
1633
//We have to load up a metadata array based upon the
1634
//order of the field names as specified in the the
1635
//getOutParamFieldsIterator() function.
1636
//
1637
ArrayList JavaDoc dbFieldArray = new ArrayList JavaDoc(theObject.getDef().getOutParamFieldsCount());
1638                            for (Iterator JavaDoc j = theObject.getDef().getOutParamFieldListIterator(); j.hasNext();) {
1639                                String JavaDoc theFieldName = (String JavaDoc) j.next();
1640                                dbFieldArray.add(theObject.getFieldMetaData(theFieldName));
1641                            }
1642                            it = dbFieldArray.iterator();
1643                            while (it.hasNext()) {
1644                                oneField = (DBField) it.next();
1645                                fieldNum = Integer.parseInt(oneField.getName());
1646                                if (!oneField.isVirtual()) {
1647                                    if (oneField.isBinaryObjectType()) {
1648                                        continue;
1649                                    }
1650                                    try {
1651                                        // * @author Yves Henri AMAIZO
1652
// Handle correctly date from resultSet data retrieve from Database
1653
if (oneField.isDateType()) {
1654                                            oneFieldValue = theObject.getCustomStringFieldValue(myConnection,
1655                                                    oneField.getName());
1656                                        } else {
1657                                            if (myConnection.isStringNotTrim()) {
1658                                                oneFieldValue = myConnection.getStringNoTrim(fieldNum);
1659                                            } else {
1660                                                oneFieldValue = myConnection.getString(fieldNum);
1661                                            }
1662                                        }
1663                                    } catch (DBException de1) {
1664                                        throw new DataException("(" + getClass().getName() + ") Error retrieving field '" +
1665                                                oneField.getName() + "' index " + fieldNum + ":" + de1.getMessage(),
1666                                                de1.getDBMessage());
1667                                    }
1668                                    theObject.set(oneField.getName(), oneFieldValue);
1669                                }
1670                            }
1671                        }
1672                    } else {
1673                        //There were zero results returned by the retrieve() call.
1674
return;
1675                    }
1676                } finally {
1677                    ;
1678                }
1679            } finally {
1680                if (localConnection == null) {
1681                    if (myPool != null && myConnection != null) {
1682                        myPool.release(myConnection);
1683                    }
1684                }
1685            }
1686        } catch (DBException ex) {
1687            String JavaDoc msg = myName + "run(DataObject) error";
1688            log.error(msg, ex);
1689            throw new DataException(msg, ex);
1690        }
1691    } /* runStoreProcedure(DataObject) */
1692
1693
1694    /**
1695     * Adds an entire batch of <code>DataObject</code>s to the underlying JDBC data source
1696     *
1697     * @param valueObjectList A list of <code>DataObject</code>s to add to the underlying
1698     * data source <b>NOTE:</b> you will get best performance if valueObjectList is
1699     * all one dataobject underneath.
1700     * @param addChangedFieldsOnly flag to signify if only fields whose value
1701     * has changed should be included in the add.
1702     * <p/>
1703     * WARNING: I DON'T UNDERSTAND WHY LOOP VAR ISN'T USED BELOW, AND SUSPECT THIS METHOD ISN'T DOING ALL IT PURPORTS TO DO; SEE "todo" (Larry Hamel, 3/03)
1704     * @throws DataException upon error communicating with the underlying data source
1705     * @throws DuplicateKeyException if one of the records was already in the
1706     * data source
1707     */

1708    public void addBatch(List JavaDoc valueObjectList, boolean addChangedFieldsOnly) throws DataException,
1709            DuplicateKeyException {
1710        if (valueObjectList == null) {
1711            throw new IllegalArgumentException JavaDoc(myName + "addBatch(List): valueObjectArray was null");
1712        }
1713
1714
1715        DBObject checkObject = null;
1716        DBConnectionPool myPool = null;
1717        DBConnection localConnection = null;
1718        java.sql.PreparedStatement JavaDoc prepStatement = null;
1719        DataObjectMetaData metadata = null;
1720
1721        ArrayList JavaDoc fieldData = new ArrayList JavaDoc(6);
1722        ArrayList JavaDoc fieldDataMetaData = new ArrayList JavaDoc(6);
1723        ArrayList JavaDoc keyData = new ArrayList JavaDoc(3);
1724        ArrayList JavaDoc keyDataMetaData = new ArrayList JavaDoc(3);
1725        FastStringBuffer valuesCommand = FastStringBuffer.getInstance();
1726        String JavaDoc theStatementString = "";
1727
1728        try {
1729            for (Iterator JavaDoc i = valueObjectList.iterator(); i.hasNext();) {
1730                DBObject oneObj = (DBObject) i.next();
1731                //
1732
//If we're on the first object, then we need to build the prepared statement
1733
//
1734
if (checkObject == null) {
1735                    localConnection = oneObj.getLocalConnection();
1736                    if (localConnection == null) {
1737                        myPool = DBConnectionPool.getInstance(oneObj.getMappedDataContext());
1738                        localConnection = myPool.getConnection("Batch Add");
1739                    }
1740                    localConnection.clear();
1741                    if (localConnection.supportsTransactions()) {
1742                        if (!localConnection.getImmortal()) {
1743                            localConnection.setAutoCommit(false);
1744                        }
1745                    }
1746
1747                    //
1748
//If the database doesn't explicitly support batch updates,
1749
//then we call add multiple times.
1750
//
1751
java.sql.DatabaseMetaData JavaDoc md = localConnection.getConnection().getMetaData();
1752                    if (!md.supportsBatchUpdates()) {
1753                        for (Iterator JavaDoc l = valueObjectList.iterator(); l.hasNext();) {
1754                            DataObject oneDataObject = (DataObject) l.next();
1755                            oneDataObject.add();
1756                        }
1757                        if (localConnection.supportsTransactions()) {
1758                            if (!localConnection.getImmortal()) {
1759                                localConnection.commit();
1760                                localConnection.setAutoCommit(true);
1761                            }
1762                        }
1763                        return;
1764                    }
1765                    theStatementString = buildPreparedAddSQL(oneObj, addChangedFieldsOnly);
1766                    prepStatement = localConnection.createPreparedStatement(theStatementString);
1767                    checkObject = oneObj;
1768                    metadata = checkObject.getMetaData();
1769                }
1770
1771                boolean needCommaValues = false;
1772                valuesCommand.append(" VALUES (");
1773
1774                //
1775
//we have to make sure that the classes are the same time or
1776
//we're in trouble.
1777
//
1778
if (!(checkObject.getClass().getName().equals(oneObj.getClass().getName()))) {
1779                    throw new IllegalArgumentException JavaDoc("JDBC Excecutor.addBatch()" +
1780                            " all objects in the valueObjectList must be the same type.");
1781                }
1782
1783                //
1784
//Now we iterate through and set all the parameters
1785
//
1786
for (Iterator JavaDoc j = metadata.getFieldListArray().iterator(); j.hasNext();) {
1787                    String JavaDoc oneFieldName = (String JavaDoc) j.next();
1788
1789                    // Only include changed fields in the update if required
1790
if (addChangedFieldsOnly) {
1791                        if (oneObj.getDataField(oneFieldName).isValueSet() && oneObj.getStatus().equals(
1792                                DataObject.STATUS_NEW)) {
1793                            ;
1794                        } else {
1795                            if (!oneObj.getDataField(oneFieldName).isChanged()) {
1796                                continue;
1797                            }
1798                        }
1799                    }
1800
1801                    DataFieldMetaData oneField = oneObj.getFieldMetaData(oneFieldName);
1802                    oneObj.checkField(oneField.getName(), oneObj.getField(oneField.getName()));
1803
1804                    //Sematics . if oneStringValue == null then
1805
//we skip the field.
1806
//if oneStringValue.equals("null"); then we add a nullable
1807
//section to the PreparedStatement.
1808
String JavaDoc oneStringValue = null;
1809
1810                    oneStringValue = prepareForStorage(oneField, oneObj, false);
1811
1812                    if (oneStringValue == null) {
1813                        oneStringValue = "null";
1814                    }
1815
1816                    if (log.isDebugEnabled()) {
1817                        if (needCommaValues) {
1818                            valuesCommand.append(", ");
1819                        }
1820                        valuesCommand.append(oneStringValue);
1821                        needCommaValues = true;
1822                    }
1823
1824                    if (oneField.isKey()) {
1825                        keyDataMetaData.add(oneField);
1826                        keyData.add(oneStringValue);
1827                    } else {
1828                        //We don't mess with auto-inc fields, virtual fields, or
1829
//binary fields.
1830
if (oneField.isVirtual() || oneField.isBinaryObjectType() || oneField.isAutoIncremented()) {
1831                            continue;
1832                        }
1833                    }
1834                    fieldDataMetaData.add(oneField);
1835                    fieldData.add(oneStringValue);
1836                }
1837
1838
1839                //We're done iterating through paramters/
1840

1841                int size = fieldData.size();
1842// try {
1843
// prepStatement.clearParameters();
1844
// } catch (NullPointerException ex) {
1845
// //
1846
// //Workaround for known Oracle bug. Clear parameters
1847
// //throws NPE's
1848
// //
1849
// if (log.isDebugEnabled()) {
1850
// log.debug("NPE. Oracle Driver?", ex);
1851
// }
1852
// }
1853

1854                TypeMapper typeMapper = TypeMapper.getInstance(localConnection.getDataContext());
1855                for (int j = 0; j < size; j++) {
1856                    String JavaDoc stringValue = (String JavaDoc) fieldData.get(j);
1857
1858                    DBField singleFieldMeta = (DBField) fieldDataMetaData.get(j);
1859
1860                    int typeCode = typeMapper.getJavaSQLType(singleFieldMeta.getTypeString());
1861                    if ("null".equals(stringValue)) {
1862                        prepStatement.setNull(j + 1, typeCode);
1863                    } else if (singleFieldMeta.isNumericType()) {
1864                        if (singleFieldMeta.getTypeString().equalsIgnoreCase("integer") ||
1865                                singleFieldMeta.getTypeString().equalsIgnoreCase("tinyint") ||
1866                                singleFieldMeta.getTypeString().equalsIgnoreCase("smallint")) {
1867                            prepStatement.setInt(j + 1, Integer.parseInt(stringValue));
1868                        } else if (singleFieldMeta.getTypeString().equalsIgnoreCase("float") ||
1869                                singleFieldMeta.getTypeString().equalsIgnoreCase("real")) {
1870                            prepStatement.setFloat(j + 1, Float.parseFloat(stringValue));
1871                        } else if (singleFieldMeta.getTypeString().equalsIgnoreCase("bigint") ||
1872                                singleFieldMeta.getTypeString().equalsIgnoreCase("numeric") ||
1873                                singleFieldMeta.getTypeString().equalsIgnoreCase("decimal")) {
1874                            prepStatement.setLong(j + 1, Long.parseLong(stringValue));
1875                        } else if (singleFieldMeta.getTypeString().equalsIgnoreCase("double")) {
1876                            prepStatement.setDouble(j + 1, Double.parseDouble(stringValue));
1877                        }
1878                    } else if (singleFieldMeta.isDateType()) {
1879                        if (singleFieldMeta.isDateOnlyType()) {
1880                            Date JavaDoc dtOnly = java.sql.Date.valueOf(stringValue);
1881                            prepStatement.setDate(j + 1, dtOnly);
1882                        }
1883                        if (singleFieldMeta.isDateTimeType()) {
1884                            Timestamp JavaDoc dts = Timestamp.valueOf(stringValue);
1885                            prepStatement.setTimestamp(j + 1, dts);
1886                        }
1887                    } else if (singleFieldMeta.isFloatingPointType()) {
1888                        prepStatement.setFloat(j + 1, Float.parseFloat(stringValue));
1889                    } else {
1890                        if (singleFieldMeta.getTypeString().equalsIgnoreCase("text")) {
1891                            if (stringValue.indexOf("\n") > 0) {
1892                                stringValue = StringUtil.replace(stringValue, "\n", "");
1893                            }
1894                            if (stringValue.indexOf("\r") > 0) {
1895                                stringValue = StringUtil.replace(stringValue, "\r", "");
1896                            }
1897                        }
1898                        prepStatement.setString(j + 1, stringValue);
1899
1900                    }
1901                }
1902
1903                //Ok, we're set, now it's time to add the batch
1904

1905                prepStatement.addBatch();
1906                if (log.isDebugEnabled()) {
1907                    valuesCommand.append(") ");
1908                    log.debug("Batch Add '" + theStatementString + " " + valuesCommand +
1909                            " request in (" + localConnection.getDescription() +
1910                            ", db/context '" + localConnection.getDataContext() + "')");
1911                    valuesCommand.clear();
1912                }
1913                fieldData.clear();
1914                fieldDataMetaData.clear();
1915                keyData.clear();
1916                keyDataMetaData.clear();
1917            }
1918
1919            prepStatement.executeBatch();
1920            localConnection.clearPreparedStatement();
1921            if (!localConnection.getImmortal()) {
1922                localConnection.commit();
1923            }
1924            valuesCommand.release();
1925        } catch (BatchUpdateException JavaDoc ex) {
1926            log.error("Batch Add Exception", ex);
1927            try {
1928                if (!localConnection.getImmortal()) {
1929                    localConnection.rollback();
1930                }
1931            } catch (DBException ex1) {
1932                log.error("Error rolling back transaction on local connection", ex1);
1933            }
1934            String JavaDoc msg = myName + "addBatch(DataObject) BatchUpdateException. ";
1935            log.error(msg, ex);
1936            throw new DataException(msg, ex);
1937        } catch (java.lang.ClassCastException JavaDoc cce) {
1938            cce.printStackTrace();
1939            throw cce;
1940        } catch (NullPointerException JavaDoc npe) {
1941            npe.printStackTrace();
1942            throw npe;
1943        } catch (SQLException JavaDoc ex) {
1944            ex.printStackTrace();
1945            try {
1946                if (!localConnection.getImmortal()) {
1947                    localConnection.rollback();
1948                }
1949            } catch (DBException ex1) {
1950                log.error("Error rolling back transaction on local connection", ex1);
1951            }
1952            String JavaDoc msg = myName + "addBatch(DataObject) SQLException. ";
1953            log.error(msg, ex);
1954            throw new DataException(msg, ex);
1955        } catch (DBException ex) {
1956            try {
1957                if (!localConnection.getImmortal()) {
1958                    localConnection.rollback();
1959                }
1960            } catch (DBException ex1) {
1961                log.error("Error rolling back transaction on local connection", ex1);
1962            }
1963            String JavaDoc msg = myName + "addBatch(DataObject) error";
1964            log.error(msg, ex);
1965            throw new DataException(msg, ex);
1966        } finally {
1967            if (prepStatement != null) {
1968                try {
1969                    if (!localConnection.getImmortal()) {
1970                        prepStatement.close();
1971                    }
1972                } catch (SQLException JavaDoc ex) {
1973                    log.error("Error closing prepared statement", ex);
1974                }
1975            }
1976
1977            if (localConnection != null) {
1978                localConnection.clearPreparedStatement();
1979            }
1980
1981            if (myPool != null) {
1982                if (localConnection != null) {
1983                    //Auto-commit is automatically turned back on by
1984
//release
1985
if (!localConnection.getImmortal()) {
1986                        myPool.release(localConnection);
1987                    }
1988                }
1989            }
1990        }
1991    }
1992
1993
1994    /**
1995     * Updates an entire batch of <code>DataObject</code>s
1996     *
1997     * @param valueObjectList A list of <code>DataObject</code>s to update to the underlying
1998     * data source
1999     * @param updateChangedFieldsOnly flag to signify if only fields whose value
2000     * has changed should be included in the update.
2001     * @throws DataException upon error updating the data source
2002     */

2003    public void updateBatch(List JavaDoc valueObjectList, boolean updateChangedFieldsOnly) throws DataException {
2004        if (valueObjectList == null) {
2005            throw new IllegalArgumentException JavaDoc(myName + "updateBatch(List, boolean): valueObjectArray was null");
2006        }
2007
2008        DBObject checkObject = null;
2009        DBConnectionPool myPool = null;
2010        DBConnection localConnection = null;
2011        DataObjectMetaData metadata = null;
2012        java.sql.PreparedStatement JavaDoc prepStatement = null;
2013        ArrayList JavaDoc fieldData = new ArrayList JavaDoc(6);
2014        ArrayList JavaDoc fieldDataMetaData = new ArrayList JavaDoc(6);
2015        ArrayList JavaDoc keyData = new ArrayList JavaDoc(3);
2016        ArrayList JavaDoc keyDataMetaData = new ArrayList JavaDoc(3);
2017        FastStringBuffer valuesCommand = FastStringBuffer.getInstance();
2018        String JavaDoc theStatementString = "";
2019
2020        try {
2021            for (Iterator JavaDoc i = valueObjectList.iterator(); i.hasNext();) {
2022                DBObject oneObj = (DBObject) i.next();
2023                fieldData.clear();
2024                fieldDataMetaData.clear();
2025                keyData.clear();
2026                keyDataMetaData.clear();
2027
2028                //
2029
//If we're on the first object, then we need to build the prepared statement
2030
//
2031
if (checkObject == null) {
2032                    localConnection = oneObj.getLocalConnection();
2033                    if (localConnection == null) {
2034                        myPool = DBConnectionPool.getInstance(oneObj.getMappedDataContext());
2035                        localConnection = myPool.getConnection("Batch Update");
2036                    }
2037                    localConnection.clear();
2038                    if (localConnection.supportsTransactions()) {
2039                        if (!localConnection.getImmortal()) {
2040                            localConnection.setAutoCommit(false);
2041                        }
2042                    }
2043                    //
2044
//If the database doesn't explicitly support batch updates,
2045
//then we call add multiple times.
2046
//
2047
java.sql.DatabaseMetaData JavaDoc md = localConnection.getConnection().getMetaData();
2048                    if (!md.supportsBatchUpdates()) {
2049                        for (Iterator JavaDoc l = valueObjectList.iterator(); l.hasNext();) {
2050                            DataObject oneDataObject = (DataObject) l.next();
2051                            oneDataObject.update();
2052                        }
2053                        if (localConnection.supportsTransactions()) {
2054                            if (!localConnection.getImmortal()) {
2055                                localConnection.commit();
2056                                localConnection.setAutoCommit(true);
2057                            }
2058                        }
2059                        return;
2060                    }
2061
2062                    theStatementString = buildPreparedUpdateSQL(oneObj, updateChangedFieldsOnly);
2063                    prepStatement = localConnection.createPreparedStatement(theStatementString);
2064                    checkObject = oneObj;
2065                    metadata = checkObject.getMetaData();
2066                }
2067
2068                boolean needCommaValues = false;
2069                valuesCommand.append(" VALUES (");
2070
2071                //
2072
//we have to make sure that the classes are the same time or
2073
//we're in trouble.
2074
//
2075
if (!(checkObject.getClass().getName().equals(oneObj.getClass().getName()))) {
2076                    throw new IllegalArgumentException JavaDoc("JDBC Excecutor.updateBatch(List, boolean)" +
2077                            " all objects in the valueObjectList must be the same type.");
2078                }
2079
2080                //
2081
//Now we iterate through and set all the parameters
2082
//
2083
for (Iterator JavaDoc j = metadata.getFieldListArray().iterator(); j.hasNext();) {
2084                    String JavaDoc oneFieldName = (String JavaDoc) j.next();
2085
2086                    // Only include changed fields in the update if required
2087
if (updateChangedFieldsOnly) {
2088                        if (oneObj.getDataField(oneFieldName).isValueSet() && oneObj.getStatus().equals(
2089                                DataObject.STATUS_NEW)) {
2090                            ;
2091                        } else {
2092                            if (!oneObj.getDataField(oneFieldName).isChanged()) {
2093                                continue;
2094                            }
2095                        }
2096                    }
2097
2098                    DataFieldMetaData oneField = oneObj.getFieldMetaData(oneFieldName);
2099                    oneObj.checkField(oneField.getName(), oneObj.getField(oneField.getName()));
2100
2101                    //Sematics . if oneStringValue == null then
2102
//we skip the field.
2103
//if oneStringValue.equals("null"); then we add a nullable
2104
//section to the PreparedStatement.
2105
String JavaDoc oneStringValue = null;
2106
2107                    oneStringValue = prepareForStorage(oneField, oneObj, false);
2108
2109                    if (oneStringValue == null) {
2110                        oneStringValue = "null";
2111                    }
2112
2113                    if (log.isDebugEnabled()) {
2114                        if (needCommaValues) {
2115                            valuesCommand.append(", ");
2116                        }
2117                        valuesCommand.append(oneStringValue);
2118                        needCommaValues = true;
2119                    }
2120
2121                    if (oneField.isKey()) {
2122                        keyDataMetaData.add(oneField);
2123                        keyData.add(oneStringValue);
2124                    } else {
2125                        //We don't mess with auto-inc fields, virtual fields, or
2126
//binary fields.
2127
if (oneField.isVirtual()
2128                                || oneField.isBinaryObjectType()
2129                                || oneField.isAutoIncremented()
2130                        ) {
2131                            continue;
2132                        }
2133
2134                        fieldDataMetaData.add(oneField);
2135                        fieldData.add(oneStringValue);
2136                    }
2137                }
2138                //
2139
//Ok, order of prepared statement is: data fields first, then
2140
//key fields so we concatenate to make things easier to cope
2141
//with logic-wise
2142
//
2143
fieldData.addAll(keyData);
2144                fieldDataMetaData.addAll(keyDataMetaData);
2145
2146
2147                int size = fieldData.size();
2148// try {
2149
// prepStatement.clearParameters();
2150
// } catch (NullPointerException ex) {
2151
// //
2152
// //Workaround for known Oracle bug. Clear parameters
2153
// //throws NPE's
2154
// //
2155
// if (log.isDebugEnabled()) {
2156
// log.debug("NPE. Oracle Driver?", ex);
2157
// }
2158
// }
2159
TypeMapper typeMapper = TypeMapper.getInstance(localConnection.getDataContext());
2160                for (int j = 0; j < size; j++) {
2161                    String JavaDoc stringValue = (String JavaDoc) fieldData.get(j);
2162
2163                    DBField singleFieldMeta = (DBField) fieldDataMetaData.get(j);
2164
2165                    int typeCode = typeMapper.getJavaSQLType(singleFieldMeta.getTypeString());
2166                    if ("null".equals(stringValue)) {
2167                        prepStatement.setNull(j + 1, typeCode);
2168                    } else if (singleFieldMeta.isNumericType()) {
2169                        if (singleFieldMeta.getTypeString().equalsIgnoreCase("integer") ||
2170                                singleFieldMeta.getTypeString().equalsIgnoreCase("numeric") ||
2171                                singleFieldMeta.getTypeString().equalsIgnoreCase("tinyint") ||
2172                                singleFieldMeta.getTypeString().equalsIgnoreCase("smallint")) {
2173                            prepStatement.setInt(j + 1, Integer.parseInt(stringValue));
2174                        } else if (singleFieldMeta.getTypeString().equalsIgnoreCase("float") ||
2175                                singleFieldMeta.getTypeString().equalsIgnoreCase("real")) {
2176                            prepStatement.setFloat(j + 1, Float.parseFloat(stringValue));
2177                        } else if (singleFieldMeta.getTypeString().equalsIgnoreCase("bigint") ||
2178                                singleFieldMeta.getTypeString().equalsIgnoreCase("decimal")) {
2179                            prepStatement.setLong(j + 1, Long.parseLong(stringValue));
2180                        } else if (singleFieldMeta.getTypeString().equalsIgnoreCase("double")) {
2181                            prepStatement.setDouble(j + 1, Double.parseDouble(stringValue));
2182                        }
2183                    } else if (singleFieldMeta.isDateType()) {
2184                        if (singleFieldMeta.isDateOnlyType()) {
2185                            Date JavaDoc dtOnly = java.sql.Date.valueOf(stringValue);
2186                            prepStatement.setDate(j + 1, dtOnly);
2187                        }
2188                        if (singleFieldMeta.isDateTimeType()) {
2189                            Timestamp JavaDoc dts = Timestamp.valueOf(stringValue);
2190                            prepStatement.setTimestamp(j + 1, dts);
2191                        }
2192                    } else if (singleFieldMeta.isFloatingPointType()) {
2193                        prepStatement.setFloat(j + 1, Float.parseFloat(stringValue));
2194                    } else {
2195                        if (singleFieldMeta.getTypeString().equalsIgnoreCase("text")) {
2196                            if (stringValue.indexOf("\n") > 0) {
2197                                stringValue = StringUtil.replace(stringValue, "\n", "");
2198                            }
2199                            if (stringValue.indexOf("\r") > 0) {
2200                                stringValue = StringUtil.replace(stringValue, "\r", "");
2201                            }
2202                        }
2203                        prepStatement.setString(j + 1, stringValue);
2204
2205                    }
2206                }
2207
2208                //Ok, we're set, now it's time to add the batch
2209
prepStatement.addBatch();
2210                if (oneObj.isCached()) {
2211                    oneObj.removeFromCache(oneObj);
2212                }
2213                if (log.isDebugEnabled()) {
2214                    valuesCommand.append(") ");
2215                    log.debug("Batch Update '" + theStatementString + " " + valuesCommand +
2216                            " request in (" + localConnection.getDescription() +
2217                            ", db/context '" + localConnection.getDataContext() + "')");
2218                    valuesCommand.clear();
2219                }
2220                fieldData.clear();
2221                fieldDataMetaData.clear();
2222                keyData.clear();
2223                keyDataMetaData.clear();
2224            }
2225
2226            prepStatement.executeBatch();
2227            localConnection.clearPreparedStatement();
2228            if (!localConnection.getImmortal()) {
2229                localConnection.commit();
2230            }
2231            valuesCommand.release();
2232        } catch (NullPointerException JavaDoc npe) {
2233            log.error("NPE Error performing batch update", npe);
2234            throw npe;
2235        } catch (NumberFormatException JavaDoc nfe) {
2236            log.error("NumberFormatException Error performing batch update", nfe);
2237            throw nfe;
2238        } catch (java.lang.ArrayIndexOutOfBoundsException JavaDoc ex) {
2239            log.error("ArrayIndexOutOfBoundsException performing batch update", ex);
2240            throw ex;
2241        } catch (ClassCastException JavaDoc cce) {
2242            log.error("Class Cast Exception performing batch update", cce);
2243            throw cce;
2244        } catch (SQLException JavaDoc ex) {
2245            try {
2246                if (!localConnection.getImmortal()) {
2247                    localConnection.rollback();
2248                }
2249            } catch (DBException ex1) {
2250                log.error("Error rolling back update batch transaction", ex1);
2251            }
2252            ex.printStackTrace();
2253            String JavaDoc msg = myName + "updateBatch(DataObject, updateChangedFieldsOnly) SQLException. ";
2254            log.error(msg, ex);
2255            throw new DataException(msg, ex);
2256        } catch (DBException ex) {
2257            try {
2258                if (!localConnection.getImmortal()) {
2259                    localConnection.rollback();
2260                }
2261            } catch (DBException ex1) {
2262                log.error("Error rolling back update batch transaction", ex1);
2263            }
2264            String JavaDoc msg = myName + "updateBatch(DataObject, updateChangedFieldsOnly) error";
2265            log.error(msg, ex);
2266            throw new DataException(msg, ex);
2267        } catch (Throwable JavaDoc t) {
2268            log.error("Caught Throwable performing batch update", t);
2269            throw new DataException(t);
2270        } finally {
2271            if (prepStatement != null) {
2272                try {
2273                    prepStatement.close();
2274                } catch (SQLException JavaDoc ex) {
2275                    log.error("Error closing prepared statement for batch update", ex);
2276                }
2277            }
2278            if (localConnection != null) {
2279                localConnection.clearPreparedStatement();
2280            }
2281
2282            if (myPool != null) {
2283                if (localConnection != null) {
2284                    //Auto-commit is automatically turned back on by
2285
//release
2286
if (!localConnection.getImmortal()) {
2287                        myPool.release(localConnection);
2288                    }
2289                }
2290            }
2291        }
2292    }
2293
2294    /**
2295     * Updates an entire batch of <code>DataObject</code>s
2296     *
2297     * @param valueObjectList A list of <code>DataObject</code>s to update to the underlying
2298     * data source
2299     * @param deleteWithSetFieldsOnly Only include changed fields in the update
2300     * @throws DataException upon error updating the data source
2301     */

2302    public void deleteBatch(List JavaDoc valueObjectList, boolean deleteWithSetFieldsOnly) throws DataException {
2303        if (valueObjectList == null) {
2304            throw new IllegalArgumentException JavaDoc(myName + "updateBatch(List, boolean): valueObjectArray was null");
2305        }
2306
2307        DBObject checkObject = null;
2308        DBConnectionPool myPool = null;
2309        DBConnection localConnection = null;
2310        DataObjectMetaData metadata = null;
2311        java.sql.PreparedStatement JavaDoc prepStatement = null;
2312        ArrayList JavaDoc fieldData = new ArrayList JavaDoc(6);
2313        ArrayList JavaDoc fieldDataMetaData = new ArrayList JavaDoc(6);
2314        ArrayList JavaDoc keyData = new ArrayList JavaDoc(3);
2315        ArrayList JavaDoc keyDataMetaData = new ArrayList JavaDoc(3);
2316        FastStringBuffer valuesCommand = FastStringBuffer.getInstance();
2317        String JavaDoc theStatementString = "";
2318
2319        try {
2320            for (Iterator JavaDoc i = valueObjectList.iterator(); i.hasNext();) {
2321                DBObject oneObj = (DBObject) i.next();
2322                fieldData.clear();
2323                fieldDataMetaData.clear();
2324                keyData.clear();
2325                keyDataMetaData.clear();
2326
2327                //
2328
//If we're on the first object, then we need to build the prepared statement
2329
//
2330
if (checkObject == null) {
2331                    localConnection = oneObj.getLocalConnection();
2332                    if (localConnection == null) {
2333                        myPool = DBConnectionPool.getInstance(oneObj.getMappedDataContext());
2334                        localConnection = myPool.getConnection("Batch Delete");
2335                    }
2336                    localConnection.clear();
2337                    if (localConnection.supportsTransactions()) {
2338                        if (!localConnection.getImmortal()) {
2339                            localConnection.setAutoCommit(false);
2340                        }
2341                    }
2342                    //
2343
//If the database doesn't explicitly support batch updates,
2344
//then we call add multiple times.
2345
//
2346
java.sql.DatabaseMetaData JavaDoc md = localConnection.getConnection().getMetaData();
2347                    if (!md.supportsBatchUpdates()) {
2348                        for (Iterator JavaDoc l = valueObjectList.iterator(); l.hasNext();) {
2349                            DataObject oneDataObject = (DataObject) l.next();
2350                            oneDataObject.update();
2351                        }
2352                        if (localConnection.supportsTransactions()) {
2353                            if (!localConnection.getImmortal()) {
2354                                localConnection.commit();
2355                                localConnection.setAutoCommit(true);
2356                            }
2357                        }
2358                        return;
2359                    }
2360
2361                    theStatementString = buildPreparedDeleteSQL(oneObj, deleteWithSetFieldsOnly);
2362                    prepStatement = localConnection.createPreparedStatement(theStatementString);
2363                    checkObject = oneObj;
2364                    metadata = checkObject.getMetaData();
2365                }
2366
2367                boolean needCommaValues = false;
2368                valuesCommand.append(" VALUES (");
2369
2370                //
2371
//we have to make sure that the classes are the same time or
2372
//we're in trouble.
2373
//
2374
if (!(checkObject.getClass().getName().equals(oneObj.getClass().getName()))) {
2375                    throw new IllegalArgumentException JavaDoc("JDBC Excecutor.deleteBatch(List, boolean)" +
2376                            " all objects in the valueObjectList must be the same type.");
2377                }
2378
2379                //
2380
//Now we iterate through and set all the parameters
2381
//
2382
for (Iterator JavaDoc j = metadata.getFieldListArray().iterator(); j.hasNext();) {
2383                    String JavaDoc oneFieldName = (String JavaDoc) j.next();
2384
2385                    // Only include changed fields in the update if required
2386
if (deleteWithSetFieldsOnly) {
2387                        if (oneObj.getDataField(oneFieldName).isValueSet() && oneObj.getStatus().equals(
2388                                DataObject.STATUS_NEW)) {
2389                            ;
2390                        } else {
2391                            if (!oneObj.getDataField(oneFieldName).isChanged()) {
2392                                continue;
2393                            }
2394                        }
2395                    }
2396
2397                    DataFieldMetaData oneField = oneObj.getFieldMetaData(oneFieldName);
2398                    oneObj.checkField(oneField.getName(), oneObj.getField(oneField.getName()));
2399
2400                    //Sematics . if oneStringValue == null then
2401
//we skip the field.
2402
//if oneStringValue.equals("null"); then we add a nullable
2403
//section to the PreparedStatement.
2404
String JavaDoc oneStringValue = null;
2405
2406                    oneStringValue = prepareForStorage(oneField, oneObj, false);
2407
2408                    if (oneStringValue == null) {
2409                        oneStringValue = "null";
2410                    }
2411
2412                    if (log.isDebugEnabled()) {
2413                        if (needCommaValues) {
2414                            valuesCommand.append(", ");
2415                        }
2416                        valuesCommand.append(oneStringValue);
2417                        needCommaValues = true;
2418                    }
2419
2420                    if (oneField.isKey()) {
2421                        keyDataMetaData.add(oneField);
2422                        keyData.add(oneStringValue);
2423                    } else {
2424                        //We don't mess with auto-inc fields, virtual fields, or
2425
//binary fields.
2426
if (oneField.isVirtual()
2427                                || oneField.isBinaryObjectType()
2428                                || oneField.isAutoIncremented()
2429                        ) {
2430                            continue;
2431                        }
2432
2433// fieldDataMetaData.add(oneField);
2434
// fieldData.add(oneStringValue);
2435
}
2436                }
2437                //
2438
//Ok, order of prepared statement is: data fields first, then
2439
//key fields so we concatenate to make things easier to cope
2440
//with logic-wise
2441
//
2442
fieldData.addAll(keyData);
2443                fieldDataMetaData.addAll(keyDataMetaData);
2444
2445
2446                int size = fieldData.size();
2447// try {
2448
// prepStatement.clearParameters();
2449
// } catch (NullPointerException ex) {
2450
// //
2451
// //Workaround for known Oracle bug. Clear parameters
2452
// //throws NPE's
2453
// //
2454
// if (log.isDebugEnabled()) {
2455
// log.debug("NPE. Oracle Driver?", ex);
2456
// }
2457
// }
2458
TypeMapper typeMapper = TypeMapper.getInstance(localConnection.getDataContext());
2459                for (int j = 0; j < size; j++) {
2460                    String JavaDoc stringValue = (String JavaDoc) fieldData.get(j);
2461
2462                    DBField singleFieldMeta = (DBField) fieldDataMetaData.get(j);
2463
2464                    int typeCode = typeMapper.getJavaSQLType(singleFieldMeta.getTypeString());
2465                    if ("null".equals(stringValue)) {
2466                        prepStatement.setNull(j + 1, typeCode);
2467                    } else if (singleFieldMeta.isNumericType()) {
2468                        if (singleFieldMeta.getTypeString().equalsIgnoreCase("integer") ||
2469                                singleFieldMeta.getTypeString().equalsIgnoreCase("numeric") ||
2470                                singleFieldMeta.getTypeString().equalsIgnoreCase("tinyint") ||
2471                                singleFieldMeta.getTypeString().equalsIgnoreCase("smallint")) {
2472                            prepStatement.setInt(j + 1, Integer.parseInt(stringValue));
2473                        } else if (singleFieldMeta.getTypeString().equalsIgnoreCase("float") ||
2474                                singleFieldMeta.getTypeString().equalsIgnoreCase("real")) {
2475                            prepStatement.setFloat(j + 1, Float.parseFloat(stringValue));
2476                        } else if (singleFieldMeta.getTypeString().equalsIgnoreCase("bigint") ||
2477                                singleFieldMeta.getTypeString().equalsIgnoreCase("decimal")) {
2478                            prepStatement.setLong(j + 1, Long.parseLong(stringValue));
2479                        } else if (singleFieldMeta.getTypeString().equalsIgnoreCase("double")) {
2480                            prepStatement.setDouble(j + 1, Double.parseDouble(stringValue));
2481                        }
2482                    } else if (singleFieldMeta.isDateType()) {
2483                        if (singleFieldMeta.isDateOnlyType()) {
2484                            Date JavaDoc dtOnly = java.sql.Date.valueOf(stringValue);
2485                            prepStatement.setDate(j + 1, dtOnly);
2486                        }
2487                        if (singleFieldMeta.isDateTimeType()) {
2488                            Timestamp JavaDoc dts = Timestamp.valueOf(stringValue);
2489                            prepStatement.setTimestamp(j + 1, dts);
2490                        }
2491                    } else if (singleFieldMeta.isFloatingPointType()) {
2492                        prepStatement.setFloat(j + 1, Float.parseFloat(stringValue));
2493                    } else {
2494                        if (singleFieldMeta.getTypeString().equalsIgnoreCase("text")) {
2495                            if (stringValue.indexOf("\n") > 0) {
2496                                stringValue = StringUtil.replace(stringValue, "\n", "");
2497                            }
2498                            if (stringValue.indexOf("\r") > 0) {
2499                                stringValue = StringUtil.replace(stringValue, "\r", "");
2500                            }
2501                        }
2502                        prepStatement.setString(j + 1, stringValue);
2503
2504                    }
2505                }
2506
2507                //Ok, we're set, now it's time to add the batch
2508
prepStatement.addBatch();
2509                if (oneObj.isCached()) {
2510                    oneObj.removeFromCache(oneObj);
2511                }
2512                if (log.isDebugEnabled()) {
2513                    valuesCommand.append(") ");
2514                    log.debug("Batch Delete '" + theStatementString + " " + valuesCommand +
2515                            " request in (" + localConnection.getDescription() +
2516                            ", db/context '" + localConnection.getDataContext() + "')");
2517                    valuesCommand.clear();
2518                }
2519                fieldData.clear();
2520                fieldDataMetaData.clear();
2521                keyData.clear();
2522                keyDataMetaData.clear();
2523            }
2524
2525            prepStatement.executeBatch();
2526            localConnection.clearPreparedStatement();
2527            if (!localConnection.getImmortal()) {
2528                localConnection.commit();
2529            }
2530            valuesCommand.release();
2531        } catch (NullPointerException JavaDoc npe) {
2532            log.error("NPE Error performing batch delete", npe);
2533            throw npe;
2534        } catch (NumberFormatException JavaDoc nfe) {
2535            log.error("NumberFormatException Error performing batch delete", nfe);
2536            throw nfe;
2537        } catch (java.lang.ArrayIndexOutOfBoundsException JavaDoc ex) {
2538            log.error("ArrayIndexOutOfBoundsException performing batch delete", ex);
2539            throw ex;
2540        } catch (ClassCastException JavaDoc cce) {
2541            log.error("Class Cast Exception performing batch delete", cce);
2542            throw cce;
2543        } catch (SQLException JavaDoc ex) {
2544            try {
2545                if (!localConnection.getImmortal()) {
2546                    localConnection.rollback();
2547                }
2548            } catch (DBException ex1) {
2549                log.error("Error rolling back delete batch transaction", ex1);
2550            }
2551            ex.printStackTrace();
2552            String JavaDoc msg = myName + "deleteBatch(DataObject, deleteWithSetFieldsOnly) SQLException. ";
2553            log.error(msg, ex);
2554            throw new DataException(msg, ex);
2555        } catch (DBException ex) {
2556            try {
2557                if (!localConnection.getImmortal()) {
2558                    localConnection.rollback();
2559                }
2560            } catch (DBException ex1) {
2561                log.error("Error rolling back delete batch transaction", ex1);
2562            }
2563            String JavaDoc msg = myName + "deleteBatch(DataObject, deleteWithSetFieldsOnly) error";
2564            log.error(msg, ex);
2565            throw new DataException(msg, ex);
2566        } catch (Throwable JavaDoc t) {
2567            log.error("Caught Throwable performing batch delete", t);
2568            throw new DataException(t);
2569        } finally {
2570            if (prepStatement != null) {
2571                try {
2572                    prepStatement.close();
2573                } catch (SQLException JavaDoc ex) {
2574                    log.error("Error closing prepared statement for batch delete", ex);
2575                }
2576            }
2577            if (localConnection != null) {
2578                localConnection.clearPreparedStatement();
2579            }
2580
2581            if (myPool != null) {
2582                if (localConnection != null) {
2583                    //Auto-commit is automatically turned back on by
2584
//release
2585
if (!localConnection.getImmortal()) {
2586                        myPool.release(localConnection);
2587                    }
2588                }
2589            }
2590        }
2591
2592    }
2593
2594    /**
2595     * Deletes an entire batch of <code>DataObject</code>s
2596     *
2597     * @param valueObjectList A list of <code>DataObject</code>s to delete to the underlying
2598     * data source
2599     * @throws DataException upon error deleting the data source
2600     */

2601    public void deleteBatch(List JavaDoc valueObjectList) throws DataException {
2602        if (valueObjectList == null) {
2603            throw new IllegalArgumentException JavaDoc(myName + "deleteBatch(List): valueObjectArray was null");
2604        }
2605        deleteBatch(valueObjectList, false);
2606
2607    }
2608
2609}
2610
2611
Popular Tags