KickJava   Java API By Example, From Geeks To Geeks.

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


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

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

30
31
32 package com.sun.jdo.spi.persistence.support.sqlstore.sql;
33
34 import com.sun.jdo.api.persistence.support.JDOFatalInternalException;
35 import com.sun.jdo.spi.persistence.support.sqlstore.*;
36 import com.sun.jdo.spi.persistence.support.sqlstore.model.ClassDesc;
37 import com.sun.jdo.spi.persistence.support.sqlstore.model.FieldDesc;
38 import com.sun.jdo.spi.persistence.support.sqlstore.model.ForeignFieldDesc;
39 import com.sun.jdo.spi.persistence.support.sqlstore.model.LocalFieldDesc;
40 import com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.ColumnRef;
41 import com.sun.jdo.spi.persistence.utility.StringHelper;
42 import com.sun.jdo.spi.persistence.utility.FieldTypeEnumeration;
43 import com.sun.jdo.spi.persistence.utility.I18NHelper;
44 import com.sun.jdo.spi.persistence.utility.logging.Logger;
45
46 import java.io.*;
47 import java.lang.reflect.Field JavaDoc;
48 import java.sql.ResultSet JavaDoc;
49 import java.sql.SQLException JavaDoc;
50 import java.sql.Timestamp JavaDoc;
51 import java.sql.Types JavaDoc;
52 import java.util.*;
53
54
55 /**
56  * This class is used by the store to materialize objects from a
57  * JDBC resultset. Each ResultDesc binds values from the ResultSet
58  * to instances of a persistence capable class.
59  */

60 public class ResultDesc {
61
62     /** List of ResultFieldDesc/ResultDesc. */
63     private List fields;
64
65     /** List of field names corresponding to <code>fields</code>. */
66     private List fieldNames;
67
68     /** Class descriptor. */
69     private ClassDesc config;
70
71     /** Indicates whether this ResultDesc is prefetching relationship fields. */
72     private boolean prefetching;
73
74     /** Array of ForeignFieldDesc. Holds prefetched collection relationship fields. */
75     private ArrayList prefetchedCollectionFields;
76
77     /** The field that is the recipient of the value from this ResultDesc. */
78     private ForeignFieldDesc parentField;
79
80     /** Holds the projected local field. */
81     private ResultFieldDesc fieldProjection;
82
83     /** Result type for aggregate queries. */
84     private int aggregateResultType = FieldTypeEnumeration.NOT_ENUMERATED;
85
86     /** The logger. */
87     private static Logger logger = LogHelperSQLStore.getLogger();
88
89     /** I18N message handler. */
90     private final static ResourceBundle messages = I18NHelper.loadBundle(
91             "com.sun.jdo.spi.persistence.support.sqlstore.Bundle", // NOI18N
92
ResultDesc.class.getClassLoader());
93
94     private boolean debug;
95
96     public ResultDesc(ClassDesc config, int aggregateResultType) {
97         fields = new ArrayList();
98         fieldNames = new ArrayList();
99         this.config = config;
100         this.aggregateResultType = aggregateResultType;
101     }
102
103     /** Create and add a ResultFieldDesc for the given fieldDesc and columnRef.
104      * @param fieldDesc - the field descriptor for the field that is the recipient of
105      * the result value indicated by the columnRef.
106      * @param columnRef - indicates which column in the resultset contains the value.
107      * @param projection - indicates whether the column is a projection
108      */

109     public void addField(LocalFieldDesc fieldDesc, ColumnRef columnRef,
110                          boolean projection) {
111
112             ResultFieldDesc rfd = new ResultFieldDesc(fieldDesc, columnRef);
113             // remember the projection
114
if (projection) {
115                 this.fieldProjection = rfd;
116             }
117             fields.add(rfd);
118             fieldNames.add(fieldDesc.getName());
119     }
120
121     private void addField(ResultDesc rs) {
122         if (rs != null) {
123             fields.add(rs);
124             fieldNames.add(null);
125         }
126     }
127
128     public void setPrefetching() {
129         prefetching = true;
130     }
131
132     /** Set the field that is the recipient of the result of this ResultDesc.
133      * @param parentField - field descriptor for the recipient field of the value
134      * of this ResultDesc.
135      */

136     public void setParentField(ForeignFieldDesc parentField) {
137         this.parentField = parentField;
138     }
139
140     /**
141      * Get the value to be bound to the field described by <code>fieldDesc</code>
142      * from the result set. The conversion to the correct field type might be done
143      * by the driver. If we can't get the correct type from the driver, the
144      * conversion in done in FieldDesc::convertValue.
145      *
146      * @param resultData Result set from the database.
147      * @param columnRef columnRef for the field.
148      * @param fieldDesc Field descriptor of the field to be bound.
149      * @param sm State manager for the persistent object being bound.
150      * @return
151      * Object with the correct type defined in <code>fieldDesc</code>.
152      */

153     private static Object JavaDoc getConvertedObject(ResultSet JavaDoc resultData,
154                                              ColumnRef columnRef,
155                                              FieldDesc fieldDesc,
156                                              StateManager sm) {
157         Object JavaDoc retVal = null;
158         try {
159             retVal = getValueFromResultSet(resultData, columnRef, fieldDesc.getEnumType());
160             // Create an SCO object in case we want to populate a pc.
161
if (retVal != null) {
162                 // Create a SCO instance in case we want to populate a pc.
163
Object JavaDoc scoVal = createSCO(retVal, sm, fieldDesc);
164                 if (scoVal != null) {
165                     retVal = scoVal;
166                 }
167             }
168         } catch (SQLException JavaDoc sqlException) {
169             //The driver is not able to convert for us
170
//We would use resultData.getObject(index) below
171
//and let FieldDesc::convertValue() do the conversion
172
//Nothing to do here
173
try {
174                 // Get the generic object and let FieldDesc::convertValue() deal with it.
175
// This will return an SCO as needed.
176
retVal = fieldDesc.convertValue(resultData.getObject(columnRef.getIndex()), sm);
177             }
178             catch (Exception JavaDoc e) {
179                 //Resolve : The original code was returning null and not throwing any
180
//exception in this case. Should we also do that????
181
logger.log(Logger.WARNING,"sqlstore.exception.log",e);
182             }
183         }
184
185         return retVal;
186     }
187
188     /**
189      * Gets value at index from resultData. resultData is queried for passed resultType.
190      * @param resultData The resultset object.
191      * @param columnRef columnRef for the field.
192      * @param resultType Type of expected result.
193      * @return value from <code>resultData</code> at <code>index</code>.
194      */

195     private static Object JavaDoc getValueFromResultSet(ResultSet JavaDoc resultData,
196                                                 ColumnRef columnRef,
197                                                         int resultType) throws SQLException JavaDoc {
198         int index = columnRef.getIndex();
199         int columnType = columnRef.getColumnType();
200
201         return getValueFromResultSet(resultData, index, resultType, columnType);
202     }
203
204     /**
205      * Gets value at index from <code>resultData</code>.<code>resultData</code>
206      * is queried for passed resultType.
207      *
208      * @param resultData The resultset object.
209      * @param index Index at which result needs to be obtained.
210      * @param resultType Type of expected result.
211      * @return value from <code>resultData</code> at <code>index</code>.
212      */

213     private static Object JavaDoc getValueFromResultSet(ResultSet JavaDoc resultData,
214                                                 int index,
215                                                 int resultType) throws SQLException JavaDoc {
216
217         // Types.OTHER is passed as a placeholder here.
218
// It implies don't care for columnType.
219
return getValueFromResultSet(resultData, index, resultType, Types.OTHER);
220     }
221
222
223     /**
224      * Gets value at index from resultData. resultData is queried for passed resultType.
225      * @param resultData The resultset object.
226      * @param index Index at which result needs to be obtained.
227      * @param resultType Type of expected result.
228      * @param columnType Types of column at index <code>index</code> as represented by
229      * java.sql.Types.
230      * @return value from <code>resultData</code> at <code>index</code>.
231      */

232     private static Object JavaDoc getValueFromResultSet(ResultSet JavaDoc resultData,
233                                                 int index,
234                                                 int resultType,
235                                                 int columnType) throws SQLException JavaDoc {
236
237         Object JavaDoc retVal = null;
238         try {
239             switch(resultType) {
240                 case FieldTypeEnumeration.BOOLEAN_PRIMITIVE :
241                 case FieldTypeEnumeration.BOOLEAN :
242                         boolean booleanValue = resultData.getBoolean(index);
243                         if(!resultData.wasNull() )
244                             retVal = new Boolean JavaDoc(booleanValue);
245                         break;
246                 case FieldTypeEnumeration.CHARACTER_PRIMITIVE :
247                 case FieldTypeEnumeration.CHARACTER :
248                         String JavaDoc strValue = resultData.getString(index);
249                         if(strValue != null)
250                             retVal = FieldDesc.getCharFromString(strValue);
251                         break;
252                 case FieldTypeEnumeration.BYTE_PRIMITIVE :
253                 case FieldTypeEnumeration.BYTE :
254                         byte byteValue = resultData.getByte(index);
255                         if(!resultData.wasNull() )
256                             retVal = new Byte JavaDoc(byteValue);
257                         break;
258                 case FieldTypeEnumeration.SHORT_PRIMITIVE :
259                 case FieldTypeEnumeration.SHORT :
260                         short shortValue = resultData.getShort(index);
261                         if(!resultData.wasNull() )
262                             retVal = new Short JavaDoc(shortValue);
263                         break;
264                 case FieldTypeEnumeration.INTEGER_PRIMITIVE :
265                 case FieldTypeEnumeration.INTEGER :
266                         int intValue = resultData.getInt(index);
267                         if(!resultData.wasNull() )
268                             retVal = new Integer JavaDoc(intValue);
269                         break;
270                 case FieldTypeEnumeration.LONG_PRIMITIVE :
271                 case FieldTypeEnumeration.LONG :
272                         long longValue = resultData.getLong(index);
273                         if(!resultData.wasNull() )
274                             retVal = new Long JavaDoc(longValue);
275                         break;
276                 case FieldTypeEnumeration.FLOAT_PRIMITIVE :
277                 case FieldTypeEnumeration.FLOAT :
278                         float floatValue = resultData.getFloat(index);
279                         if(!resultData.wasNull() )
280                             retVal = new Float JavaDoc(floatValue);
281                         break;
282                 case FieldTypeEnumeration.DOUBLE_PRIMITIVE :
283                 case FieldTypeEnumeration.DOUBLE :
284                         double doubleValue = resultData.getDouble(index);
285                         if(!resultData.wasNull() )
286                             retVal = new Double JavaDoc(doubleValue);
287                         break;
288                 case FieldTypeEnumeration.BIGDECIMAL :
289                 case FieldTypeEnumeration.BIGINTEGER :
290                         retVal = resultData.getBigDecimal(index);
291                         if ((resultType == FieldTypeEnumeration.BIGINTEGER) && (retVal != null)) {
292                             retVal = ( (java.math.BigDecimal JavaDoc) retVal).toBigInteger();
293                         }
294                         break;
295                 case FieldTypeEnumeration.STRING :
296                         if(LocalFieldDesc.isCharLobType(columnType) ) {
297                             Reader reader = resultData.getCharacterStream(index);
298                             retVal = readCharacterStreamToString(reader);
299                         } else {
300                             retVal = resultData.getString(index);
301                         }
302                         break;
303                 case FieldTypeEnumeration.SQL_DATE :
304                         retVal = resultData.getDate(index);
305                         break;
306                 case FieldTypeEnumeration.SQL_TIME :
307                         retVal = resultData.getTime(index);
308                         break;
309                 case FieldTypeEnumeration.UTIL_DATE :
310                 case FieldTypeEnumeration.SQL_TIMESTAMP :
311                         //Variable ts is introduced to avoid cast
312
Timestamp JavaDoc ts;
313                         ts = resultData.getTimestamp(index);
314                         if (resultType == FieldTypeEnumeration.UTIL_DATE && ts != null) {
315                             retVal = new Date(ts.getTime());
316                         } else {
317                             retVal = ts;
318                         }
319                         break;
320                 case FieldTypeEnumeration.ARRAY_BYTE_PRIMITIVE :
321                         InputStream is = resultData.getBinaryStream(index);
322                         retVal = readInputStreamToByteArray(is);
323                         break;
324                case FieldTypeEnumeration.NOT_ENUMERATED :
325                         //RESOLVE:
326
//We should only get here for getting values for hidden fields.
327
//hiddenFields does not have their java type initialized. Its sort of difficult
328
//to initialize java type without major re-org of the code in ClassDesc :(.
329
//But once it is done, we should throw an exception if we reach here.
330
//
331
//For now retrieve value for hidden fields as object as they are any way
332
//stored as Object in SQLStatemanager.
333
retVal = resultData.getObject(index);
334                       break;
335                default :
336                         //If we reach here, a new type has been added to FieldTypeEnumeration.
337
//Please update this method to handle new type.
338
throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
339                             "sqlstore.resultdesc.unknownfieldtype",resultType) );
340             } //switch
341
} catch (SQLException JavaDoc e) {
342             if(logger.isLoggable(Logger.WARNING) ) {
343                 Object JavaDoc items[] =
344                     { new Integer JavaDoc(index), new Integer JavaDoc(resultType), new Integer JavaDoc(columnType), e};
345                 logger.log(Logger.WARNING,"sqlstore.resultdesc.errorgettingvalefromresulset",items);
346             }
347             throw e;
348         }
349
350         // RESOLVE: Following is a workaround till we are able to initialize java type for hidden fields.
351
// When we are able to determine java type of hidden fields, this code should go back
352
// to case FieldTypeEnumeration.String
353
if (LocalFieldDesc.isFixedCharType(columnType)
354             // For Character fields, this method is expected to return
355
// Character. Do not convert them to String.
356
&& resultType != FieldTypeEnumeration.CHARACTER_PRIMITIVE
357             && resultType != FieldTypeEnumeration.CHARACTER
358             && retVal != null) {
359             // To support char columns, we rtrim fields mapped to fixedchar.
360
retVal = StringHelper.rtrim(retVal.toString());
361         }
362
363         return retVal;
364     }
365
366     /**
367      * Creates a SCO corresponding to <code>value</code>.
368      * Currently used for dates. The actual SCO conversion for dates is done in
369      * {@link com.sun.jdo.spi.persistence.support.sqlstore.model.FieldDesc#createSCO(java.lang.Object, com.sun.jdo.spi.persistence.support.sqlstore.StateManager)}.
370      *
371      * @param value Value to be converted.
372      * @param sm StateManager of the persistent object being populated.
373      * @param fieldDesc Field being bound.
374      * @return New SCO instance, null if no SCO was created.
375      */

376     private static Object JavaDoc createSCO(Object JavaDoc value, StateManager sm, FieldDesc fieldDesc) {
377         Object JavaDoc retVal = null;
378
379         if (fieldDesc != null) {
380             int enumType = fieldDesc.getEnumType();
381
382             // Need to convert Date fields into their SCO equivalents
383
switch(enumType) {
384                 case FieldTypeEnumeration.UTIL_DATE:
385                 case FieldTypeEnumeration.SQL_DATE:
386                 case FieldTypeEnumeration.SQL_TIME:
387                 case FieldTypeEnumeration.SQL_TIMESTAMP:
388
389                     retVal = fieldDesc.createSCO(value, sm);
390                     break;
391                 default:
392             }
393         }
394
395         return retVal;
396     }
397
398     /**
399      * Reads from input stream <CODE>is</CODE> into a byte array.
400      *
401      * @param is Input stream obtained from the database.
402      * @return A byte array read from the input stream.
403      * @see java.sql.ResultSet#getBinaryStream(int)
404      */

405     private static byte[] readInputStreamToByteArray(InputStream is) {
406         byte[] byteArray = null;
407         if (is != null) {
408             ByteArrayOutputStream bos = new ByteArrayOutputStream();
409             byte[] chunk = new byte[2000];
410             int read = 0;
411
412             try {
413                 while ((read = is.read(chunk)) != -1) {
414                     bos.write(chunk, 0, read);
415                 }
416                 byteArray = bos.toByteArray();
417             } catch (IOException e) {
418                 // log the exception and don't return any value
419
// Eating the exception here. As the caller also does not
420
// know how to deal with this exception.
421
logger.log(Logger.WARNING,"sqlstore.exception.log",e);
422             }
423         }
424         return byteArray;
425     }
426
427     /**
428      * Reads from the character stream <code>reader</code> into a String.
429      *
430      * @param reader Reader obtained from the database.
431      * @return A String read from the reader.
432      * @see java.sql.ResultSet#getCharacterStream(int)
433      */

434     private static String JavaDoc readCharacterStreamToString(Reader reader) {
435         String JavaDoc retVal = null;
436         if(reader != null) {
437             BufferedReader buffReader = new BufferedReader(reader);
438             StringBuffer JavaDoc buff = new StringBuffer JavaDoc();
439             try {
440                 int charRead;
441                 while( (charRead = buffReader.read() ) != -1) {
442                     buff.append( (char)charRead );
443                 }
444             } catch (IOException e) {
445                     // log the exception and don't return any value
446
// Eating the exception here. As the caller also does not
447
// know how to deal with this exception.
448
logger.log(Logger.WARNING,"sqlstore.exception.log",e);
449             }
450             retVal = buff.toString();
451         }
452         return retVal;
453     }
454
455     /**
456      * Materialize data from the result set into objects.
457      *
458      * @param pm - the PersistenceManager responsible for instantiating objects
459      * @param resultData - JDBC ResultSet containing the data to be materialized
460      * @return
461      * Collection containing the resulting objects. For aggregate queries,
462      * the returned object type is specified by the caller.
463      */

464     public Object JavaDoc getResult(PersistenceManager pm, ResultSet JavaDoc resultData) throws SQLException JavaDoc {
465         Object JavaDoc result = null;
466
467         debug = logger.isLoggable(Logger.FINEST);
468
469         if (!isAggregate()) {
470             Collection resultCollection = new ArrayList();
471
472             // Fill in the data from the current row of resultData.
473
while (resultData.next()) {
474                 Object JavaDoc resultObject = null;
475
476                 if (fieldProjection != null) {
477                     resultObject = getProjectedField(resultData);
478                 } else {
479                     resultObject = setFields(pm, resultData);
480                 }
481                 // resultCollection might contain resultObject if prefetch
482
// is enabled. Do not add duplicates. Duplicates are required
483
// for projection queries
484
if (!prefetching || !resultCollection.contains(resultObject)) {
485                     resultCollection.add(resultObject);
486                 }
487             }
488
489             //Iterate over the results obtained and handle deferred collection updates.
490
applyDeferredUpdatesToPrefetchedCollections(resultCollection);
491             result = resultCollection;
492         } else {
493             // Aggregate functions return an object instead of a collection.
494
result = getAggregateResult(resultData);
495         }
496
497         return result;
498     }
499
500     /**
501      * The prefetched collection fields might have deferred updates for
502      * @param resultCollection
503      */

504     private void applyDeferredUpdatesToPrefetchedCollections(Collection resultCollection) {
505         if (prefetching && prefetchedCollectionFields != null && prefetchedCollectionFields.size() > 0) {
506             for (Iterator resultItr = resultCollection.iterator(); resultItr.hasNext();) {
507                 // resultPC is guranted to be instance of PersistenceCapable
508
PersistenceCapable resultPC = (PersistenceCapable) resultItr.next();
509
510                 // resultPC can be null if this is a projection query
511
if(resultPC != null) {
512                     SQLStateManager sm = (SQLStateManager)resultPC.jdoGetStateManager();
513                     Iterator prefetchedCollectionFieldsIter = prefetchedCollectionFields.iterator();
514                     StateManager resultSM = resultPC.jdoGetStateManager();
515                     while (prefetchedCollectionFieldsIter.hasNext()) {
516                         ForeignFieldDesc prefetchedCollectionField =
517                                 (ForeignFieldDesc) prefetchedCollectionFieldsIter.next();
518                         // process deferred updates for all prefetched collection relationship
519
if(prefetchedCollectionField.cardinalityUPB > 1) {
520                             SCOCollection relationshipValue =
521                                     (SCOCollection) prefetchedCollectionField.getValue(sm);
522                             if(relationshipValue.isDeferred()){
523                                 relationshipValue.applyDeferredUpdates(null);
524                             }
525                             // Presence mask bit for a prefetched collection field is
526
// not set in setFields. Set the bit here.
527
resultSM.setPresenceMaskBit(prefetchedCollectionField.absoluteID);
528                         }
529                     }
530                 }
531             }
532         }
533     }
534
535     /**
536      * Get result for Aggregates. Since resultset containing result for aggregates would not
537      * contain any other columns, it is assumed that the result is available at index == 1.
538      * @param resultData The resultset from which result is to be extracted.
539      */

540     private Object JavaDoc getAggregateResult(ResultSet JavaDoc resultData) throws SQLException JavaDoc {
541         Object JavaDoc result = null;
542
543         if (resultData.next() ) {
544             //Aggregate results are always at index 1;
545
result = getValueFromResultSet(resultData, 1, aggregateResultType);
546         }
547         return result;
548    }
549
550
551     /**
552      * Returns the projected field from the result set. This field is
553      * always a local field. Foreign fields are handled in setFields.
554      *
555      * We return the database value for projections on local fields.
556      * Unless we flush for queries in optimistic transactions the value
557      * from the database might be different from the value in memory.
558      *
559      * @param resultData The SQL result set.
560      * @return
561      * The projected value from the result set. This might be a local field
562      * or the result of an aggregate query.
563      * @see com.sun.jdo.spi.persistence.support.sqlstore.sql.ResultDesc#setFields(PersistenceManager, ResultSet)
564      */

565     private Object JavaDoc getProjectedField(ResultSet JavaDoc resultData) {
566         //Field projection can never be null if this method gets called.
567
FieldDesc f = fieldProjection.getFieldDesc();
568
569         if (debug) {
570             logger.finest("sqlstore.resultdesc.returning_field", f.getName()); // NOI18N
571
}
572         return getConvertedObject(resultData, fieldProjection.getColumnRef(), f, null);
573     }
574
575     /**
576      * Bind the columns from this ResultSet row to the persistent object described
577      * by this ResultDesc. External queries always return only one type of objects
578      * and don't have nested ResultDescs. Internal queries can have nested ResultDescs.
579      * Run through all the fields of the field list and bind the values in
580      * that order. Nested ResultDescs are processed by recursive calls.
581      *
582      * @param pm The PersistenceManager responsible for instantiating objects.
583      * @param resultData JDBC ResultSet containing the data to be materialized.
584      * @return
585      * Persistent object corresponding to values from ResultSet row, can be null.
586      */

587     private Object JavaDoc setFields(PersistenceManager pm, ResultSet JavaDoc resultData) {
588         Object JavaDoc pcObj = null;
589         // Get the Statemanager corresponding to the current row
590
SQLStateManager sm = (SQLStateManager) findOrCreateStateManager(resultData, pm);
591         if (sm != null) {
592             pcObj = sm.getPersistent();
593             sm.getLock();
594             try {
595                 // Fields are read in the order in which they were placed in
596
// the sql select statement. This ordering is important while reading
597
// from streams corresponding to LONG columns on Oracle.
598
for (int i = 0; i < fields.size(); i++) {
599                     Object JavaDoc temp = fields.get(i);
600
601                     if (temp instanceof ResultFieldDesc) {
602                         ResultFieldDesc rfd = (ResultFieldDesc) temp;
603                         LocalFieldDesc f = rfd.getFieldDesc();
604
605                         if (!sm.getPresenceMaskBit(f.absoluteID)) {
606                             Object JavaDoc value = getConvertedObject(resultData, rfd.getColumnRef(), f, sm);
607
608                             if (debug) {
609                                 logger.finest("sqlstore.resultdesc.marking_field", f.getName()); // NOI18N
610
}
611
612                             // Set the field value and presence mask bit.
613
setFieldValue(sm, f, value);
614                         }
615                     } else {
616                         ResultDesc frd = (ResultDesc) temp;
617                         ForeignFieldDesc parentField = frd.parentField;
618
619                         // Only try to fetch the field if it is not already present.
620
// If the field is already present, it should be in
621
// consistent state w.r.t. this transaction. Overwriting
622
// it with the value from database might corrupt consistency of data.
623
if (!sm.getPresenceMaskBit(parentField.absoluteID)) {
624                             Object JavaDoc fobj = frd.setFields(pm, resultData);
625
626                             if(parentField.cardinalityUPB > 1) { // parentField is a collection.
627
SCOCollection collection = (SCOCollection) parentField.getValue(sm);
628                                 if (collection == null) {
629                                     // Getting first member of the collection. Initialize the collection.
630
// Presence mask bit for a collection field can not set here.
631
// This is because the collection is not fully present till all the
632
// elements of the collection are added. If the bit is set here,
633
// next member of this collection from this resultset will not
634
// be processed(added) here.
635
// This bit is set after all the elements of this collection are
636
// processed. That is in applyDeferredUpdatesToPrefetchedCollections()
637
sm.replaceCollection(parentField, null);
638                                     // Get the newly created SCOCollection back.
639
collection = (SCOCollection) parentField.getValue(sm);
640                                 }
641
642                                 if(fobj != null ) {
643                                     collection.addToBaseCollection(fobj);
644                                 }
645                             } else { // parentField is an object.
646
// Set the field value and presence mask bit.
647
setFieldValue(sm, parentField, fobj);
648                             }
649                         }
650                         if (debug) {
651                             logger.finest("sqlstore.resultdesc.marking_foreign_field", // NOI18N
652
parentField.getName());
653                         }
654                     }
655                 }
656
657                 sm.initialize(true);
658             } finally {
659                 // Always release the lock.
660
sm.releaseLock();
661             }
662         } else {
663             // sm can be null if we can not find or create a statemanager from the result data.
664
// This is possible if we are projecting on a foreignfield and there is no
665
// result returned.
666
}
667
668         return pcObj;
669     }
670
671     /**
672      * Set given <code>value</code> for the given field <code>f</code> for
673      * given statemanager <code>sm</code>.
674      * Also set presence mask bit for the field in given <code>sm</code>.
675      * @param sm Given StateManager
676      * @param f Given field
677      * @param value Given value.
678      */

679     private static void setFieldValue(StateManager sm, FieldDesc f, Object JavaDoc value) {
680         f.setValue(sm, value);
681         sm.setPresenceMaskBit(f.absoluteID);
682     }
683
684     /**
685      * Specifies, if this was an aggregate query.
686      */

687     private boolean isAggregate() {
688         return aggregateResultType != FieldTypeEnumeration.NOT_ENUMERATED;
689     }
690
691     /**
692      * Returns a StateManager which PC instance to be populated with the values.
693      * If such instance exists in this PersistenceManager cache,
694      * it is returned, otherwise a new instance is created.
695      */

696     private StateManager findOrCreateStateManager(ResultSet JavaDoc resultData,
697                                                   PersistenceManager pm) {
698         try {
699             Class JavaDoc oidClass = config.getOidClass();
700             Object JavaDoc oid = oidClass.newInstance();
701
702             // Copy key field values
703
Field JavaDoc keyFields[] = config.getKeyFields();
704             String JavaDoc keyNames[] = config.getKeyFieldNames();
705             for (int i = 0; i < keyFields.length; i++) {
706                 Field JavaDoc keyField = keyFields[i];
707                 String JavaDoc keyName = keyNames[i];
708                 FieldDesc fd = config.getField(keyName);
709                 int index = fieldNames.indexOf(keyName);
710
711                 ResultFieldDesc rfd = (ResultFieldDesc)fields.get(index);
712
713                 Object JavaDoc v = getConvertedObject(resultData, rfd.getColumnRef(), fd, null);
714
715                 if (debug) {
716                     logger.finest("sqlstore.resultdesc.marking_key_field",keyName); // NOI18N
717
}
718
719                 if (v == null ) {
720                     return null;
721                 }
722                 keyField.set(oid, v);
723             }
724             return pm.findOrCreateStateManager(oid, config.getPersistenceCapableClass());
725
726         } catch (Exception JavaDoc e) {
727             // RESOLVE...
728
throw new JDOFatalInternalException(e.getMessage());
729         }
730     }
731
732     /**
733      * Joins foreignResult with this resultDesc
734      * @param foreignResult the foreign ResultDesc
735      * @param parentField parentField for the foreind ResultDesc
736      */

737     public void doJoin(ResultDesc foreignResult, ForeignFieldDesc parentField) {
738         addField(foreignResult);
739         foreignResult.parentField = parentField;
740
741         // if foreign result correponds to a collection relationship being
742
// prefetched, remember it.
743
if(parentField.cardinalityUPB > 1) {
744             if(prefetchedCollectionFields == null) {
745                 prefetchedCollectionFields = new ArrayList();
746             }
747             prefetchedCollectionFields.add(parentField);
748         }
749     }
750
751 }
752
Popular Tags