KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > internal > expressions > QueryKeyExpression


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

21
22 // Copyright (c) 1998, 2006, Oracle. All rights reserved.
23
package oracle.toplink.essentials.internal.expressions;
24
25 import java.io.*;
26 import java.util.*;
27 import oracle.toplink.essentials.descriptors.FetchGroupManager;
28 import oracle.toplink.essentials.exceptions.*;
29 import oracle.toplink.essentials.expressions.*;
30 import oracle.toplink.essentials.internal.helper.*;
31 import oracle.toplink.essentials.mappings.*;
32 import oracle.toplink.essentials.mappings.foundation.AbstractDirectMapping;
33 import oracle.toplink.essentials.queryframework.*;
34 import oracle.toplink.essentials.querykeys.*;
35 import oracle.toplink.essentials.internal.sessions.AbstractRecord;
36 import oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl;
37 import oracle.toplink.essentials.internal.sessions.AbstractSession;
38 import oracle.toplink.essentials.descriptors.ClassDescriptor;
39
40 /**
41  * Represents expression on query keys or mappings.
42  * This includes direct, relationships query keys and mappings.
43  */

44 public class QueryKeyExpression extends ObjectExpression {
45
46     /** The name of the query key. */
47     protected String JavaDoc name;
48
49     /** Cache the aliased field. Only applies to attributes. */
50     protected DatabaseField aliasedField;
51
52     /** Is this a query across a 1:many or many:many relationship. Does not apply to attributes. */
53     protected boolean shouldQueryToManyRelationship;
54     
55     /** Cache the query key for performance. Store a boolean so we don't repeat the search if there isn't one. */
56     transient protected QueryKey queryKey;
57     protected boolean hasQueryKey;
58
59     /** Same for mappings. */
60     transient protected DatabaseMapping mapping;
61     protected boolean hasMapping;
62
63     public QueryKeyExpression() {
64         this.shouldQueryToManyRelationship = false;
65         this.hasQueryKey = true;
66         this.hasMapping = true;
67     }
68
69     public QueryKeyExpression(String JavaDoc aName, Expression base) {
70         super();
71         name = aName;
72         baseExpression = base;
73         shouldUseOuterJoin = false;
74         shouldQueryToManyRelationship = false;
75         hasQueryKey = true;
76         hasMapping = true;
77     }
78
79     /**
80      * INTERNAL:
81      * Return the expression to join the main table of this node to any auxiliary tables.
82      */

83     public Expression additionalExpressionCriteria() {
84         if (getDescriptor() == null) {
85             return null;
86         }
87
88         Expression criteria = getDescriptor().getQueryManager().getAdditionalJoinExpression();
89         if (criteria != null) {
90             criteria = getBaseExpression().twist(criteria, this);
91             if (shouldUseOuterJoin() && getSession().getPlatform().shouldPrintOuterJoinInWhereClause()) {
92                 criteria.convertToUseOuterJoin();
93             }
94         }
95
96         if(getSession().getPlatform().shouldPrintOuterJoinInWhereClause()) {
97             if(isUsingOuterJoinForMultitableInheritance()) {
98                 Expression childrenCriteria = getDescriptor().getInheritancePolicy().getChildrenJoinExpression();
99                 childrenCriteria = getBaseExpression().twist(childrenCriteria, this);
100                 childrenCriteria.convertToUseOuterJoin();
101                 if(criteria == null) {
102                     criteria = childrenCriteria;
103                 } else {
104                     criteria = criteria.and(childrenCriteria);
105                 }
106             }
107         }
108
109         return criteria;
110     }
111
112     /**
113      * INTERNAL:
114      * Used in case outer joins should be printed in FROM clause.
115      * Each of the additional tables mapped to expressions that joins it.
116      */

117     public Map additionalExpressionCriteriaMap() {
118         if (getDescriptor() == null) {
119             return null;
120         }
121
122         HashMap tablesJoinExpressions = new HashMap();
123         Vector tables = getDescriptor().getTables();
124         // skip the main table - start with i=1
125
int tablesSize = tables.size();
126         if(shouldUseOuterJoin()) {
127             for( int i=1; i < tablesSize; i++) {
128                 DatabaseTable table = (DatabaseTable)tables.elementAt(i);
129                 Expression joinExpression = (Expression)getDescriptor().getQueryManager().getTablesJoinExpressions().get(table);
130                 joinExpression = getBaseExpression().twist(joinExpression, this);
131                 tablesJoinExpressions.put(table, joinExpression);
132             }
133         }
134         if(isUsingOuterJoinForMultitableInheritance()) {
135             List childrenTables = getDescriptor().getInheritancePolicy().getChildrenTables();
136             tablesSize = childrenTables.size();
137             for( int i=0; i < tablesSize; i++) {
138                 DatabaseTable table = (DatabaseTable)childrenTables.get(i);
139                 Expression joinExpression = (Expression)getDescriptor().getInheritancePolicy().getChildrenTablesJoinExpressions().get(table);
140                 joinExpression = getBaseExpression().twist(joinExpression, this);
141                 tablesJoinExpressions.put(table, joinExpression);
142             }
143         }
144         
145         return tablesJoinExpressions;
146     }
147
148     /**
149      * INTERNAL:
150      * Find the alias for a given table
151      */

152     public DatabaseTable aliasForTable(DatabaseTable table) {
153         if (isAttribute() || ((getMapping() != null) && (getMapping().isAggregateObjectMapping() || getMapping().isTransformationMapping()))) {
154             return ((DataExpression)getBaseExpression()).aliasForTable(table);
155         }
156
157         //"ref" and "structure" mappings, no table printed in the FROM clause, need to get the table alias form the parent table
158
if ((getMapping() != null) && (getMapping().isReferenceMapping() || getMapping().isStructureMapping())) {
159             DatabaseTable alias = getBaseExpression().aliasForTable((DatabaseTable)getMapping().getDescriptor().getTables().firstElement());
160             alias.setName(alias.getName() + "." + getMapping().getField().getName());
161             return alias;
162         }
163
164         return super.aliasForTable(table);
165     }
166
167     /**
168      * INTERNAL:
169      * Used for debug printing.
170      */

171     public String JavaDoc descriptionOfNodeType() {
172         return "Query Key";
173     }
174
175     /**
176      * INTERNAL:
177      */

178     public void doQueryToManyRelationship() {
179         shouldQueryToManyRelationship = true;
180     }
181
182     /**
183      * INTERNAL:
184      * Return the field appropriately aliased
185      */

186     public DatabaseField getAliasedField() {
187         if (aliasedField == null) {
188             initializeAliasedField();
189         }
190         return aliasedField;
191
192     }
193
194     /**
195      * Return the alias for our table
196      */

197     protected DatabaseTable getAliasedTable() {
198         DataExpression base = (DataExpression)getBaseExpression();
199
200         DatabaseTable alias = base.aliasForTable(getField().getTable());
201         if (alias == null) {
202             return getField().getTable();
203         } else {
204             return alias;
205         }
206     }
207
208     /**
209      * INTERNAL:
210      * Return the descriptor which contains this query key.
211      */

212     public ClassDescriptor getContainingDescriptor() {
213         return ((DataExpression)getBaseExpression()).getDescriptor();
214     }
215
216     /**
217      * INTERNAL:
218      */

219     public DatabaseField getField() {
220         if (!isAttribute()) {
221             return null;
222         }
223
224         return getContainingDescriptor().getObjectBuilder().getFieldForQueryKeyName(getName());
225     }
226
227     /**
228      * INTERNAL:
229      * Return all the fields
230      */

231     public Vector getFields() {
232         if (isAttribute()) {
233             Vector result = new Vector(1);
234             DatabaseField field = getField();
235             if (field != null) {
236                 result.addElement(field);
237             }
238             return result;
239         } else if ((getMapping() != null) && getMapping().isTransformationMapping()) {
240             return getMapping().getFields();
241         } else {
242             if(isUsingOuterJoinForMultitableInheritance()) {
243                 return getDescriptor().getAllFields();
244             } else {
245                 return super.getFields();
246             }
247         }
248     }
249
250     /**
251      * INTERNAL:
252      * Transform the object-level value into a database-level value
253      */

254     public Object JavaDoc getFieldValue(Object JavaDoc objectValue) {
255         DatabaseMapping mapping = getMapping();
256         Object JavaDoc fieldValue = objectValue;
257         if ((mapping != null) && (mapping.isDirectToFieldMapping())) {
258             // CR#3623207, check for IN Vector here not in mapping.
259
if (objectValue instanceof Vector) {
260                 // This can actually be a vector for IN within expressions... however it would be better for expressions to handle this.
261
Vector values = (Vector)objectValue;
262                 Vector fieldValues = new Vector(values.size());
263                 for (int index = 0; index < values.size(); index++) {
264                     fieldValues.addElement(getFieldValue(values.get(index)));
265                 }
266                 fieldValue = fieldValues;
267             } else {
268                 fieldValue = ((AbstractDirectMapping)mapping).getFieldValue(objectValue, getSession());
269             }
270         }
271
272         return fieldValue;
273     }
274
275     public DatabaseMapping getMapping() {
276         if (!hasMapping) {
277             return null;
278         }
279
280         if (mapping == null) {
281             mapping = super.getMapping();
282             if (mapping == null) {
283                 hasMapping = false;
284             }
285         }
286         return mapping;
287     }
288
289     public DatabaseMapping getMappingFromQueryKey() {
290         QueryKey queryKey = getQueryKeyOrNull();
291         if ((queryKey == null) || (!(queryKey instanceof DirectQueryKey))) {
292             throw QueryException.cannotConformExpression();
293         }
294         mapping = queryKey.getDescriptor().getObjectBuilder().getMappingForField(((DirectQueryKey)queryKey).getField());
295         if (mapping == null) {
296             throw QueryException.cannotConformExpression();
297         }
298         return mapping;
299     }
300
301     public String JavaDoc getName() {
302         return name;
303     }
304
305     /**
306      * INTERNAL:
307      */

308     public Vector getOwnedTables() {
309         if ((getMapping() != null) && (getMapping().isReferenceMapping() || getMapping().isStructureMapping())) {
310             return null;
311         }
312
313         return super.getOwnedTables();
314     }
315
316     public QueryKey getQueryKeyOrNull() {
317         if (!hasQueryKey) {
318             return null;
319         }
320
321         // Oct 19, 2000 JED
322
// Added try/catch. This was throwing a NPE in the following case
323
// expresssionBuilder.get("firstName").get("bob")
324
//moved by Gordon Yorke to cover validate and normalize
325
if (getContainingDescriptor() == null) {
326             throw QueryException.invalidQueryKeyInExpression(getName());
327         }
328         if (queryKey == null) {
329             queryKey = getContainingDescriptor().getQueryKeyNamed(getName());
330             if (queryKey == null) {
331                 hasQueryKey = false;
332             }
333         }
334         return queryKey;
335
336     }
337
338     /**
339      * INTERNAL:
340      * Alias the database field for our current environment
341      */

342     protected void initializeAliasedField() {
343         DatabaseField tempField = (DatabaseField)getField().clone();
344         DatabaseTable aliasedTable = getAliasedTable();
345
346         // Put in a special check here so that if the aliasing does nothing we don't cache the
347
// result because it's invalid. This saves us from caching premature data if e.g. debugging
348
// causes us to print too early"
349
// if (aliasedTable.equals(getField().getTable())) {
350
// return;
351
// } else {
352
aliasedField = tempField;
353         aliasedField.setTable(aliasedTable);
354         // }
355
}
356
357     /**
358      * INTERNAL:
359      */

360     public boolean isAttribute() {
361         if (getSession() == null) {// We can't tell, so say no
362
return false;
363         }
364
365         try {
366             QueryKey queryKey = getQueryKeyOrNull();
367             if (queryKey != null) {
368                 return queryKey.isDirectQueryKey();
369             }
370
371             DatabaseMapping mapping = getMapping();
372             if (mapping != null) {
373                 if (mapping.isVariableOneToOneMapping()) {
374                     throw QueryException.cannotQueryAcrossAVariableOneToOneMapping(mapping, mapping.getDescriptor());
375                 } else {
376                     return mapping.isDirectToFieldMapping();
377                 }
378             }
379         } catch (QueryException e) {
380             throw e;//re-throw the query exception arisen from the query on varibale 1:1 mapping
381
}
382         return false;
383     }
384
385     public boolean isQueryKeyExpression() {
386         return true;
387     }
388
389     /*
390      * INTERNAL:
391      * If this query key respresents a foreign reference answer the
392      * base expression -> foreign reference join criteria.
393      */

394     public Expression mappingCriteria() {
395         Expression selectionCriteria;
396
397         // First look for a query key, then a mapping
398
if (getQueryKeyOrNull() == null) {
399             if ((getMapping() == null) || (!getMapping().isForeignReferenceMapping())) {
400                 return null;
401             } else {
402                 // The join criteria is now twisted by the mappings.
403
selectionCriteria = ((ForeignReferenceMapping)getMapping()).getJoinCriteria(this);
404             }
405         } else {
406             if (!getQueryKeyOrNull().isForeignReferenceQueryKey()) {
407                 return null;
408             } else {
409                 selectionCriteria = ((ForeignReferenceQueryKey)getQueryKeyOrNull()).getJoinCriteria();
410                 selectionCriteria = getBaseExpression().twist(selectionCriteria, this);
411             }
412         }
413
414         if (shouldUseOuterJoin() && getSession().getPlatform().shouldPrintOuterJoinInWhereClause()) {
415             selectionCriteria = selectionCriteria.convertToUseOuterJoin();
416         }
417
418         return selectionCriteria;
419     }
420
421     /**
422      * INTERNAL:
423      * Normalize the expression into a printable structure.
424      * Any joins must be added to form a new root.
425      */

426     public Expression normalize(ExpressionNormalizer normalizer) {
427         return normalize(normalizer, null);
428     }
429
430     /**
431      * INTERNAL:
432      * For CR#2456 if this is part of an objExp.equal(objExp), do not need to add
433      * additional expressions to normalizer both times, and the foreign key join
434      * replaces the equal expression.
435      */

436     public Expression normalize(ExpressionNormalizer normalizer, Vector foreignKeyJoinPointer) {
437         if (hasBeenNormalized()) {
438             return this;
439         }
440         super.normalize(normalizer);
441
442         setHasBeenNormalized(true);
443         if ((getMapping() != null) && getMapping().isDirectToXMLTypeMapping()) {
444             normalizer.getStatement().setRequiresAliases(true);
445         }
446
447         // Check if any joins need to be added.
448
if (isAttribute()) {
449             return this;
450         }
451
452         // If the mapping is 'ref' or 'structure', no join needed.
453
if ((getMapping() != null) && (getMapping().isReferenceMapping() || getMapping().isStructureMapping())) {
454             normalizer.getStatement().setRequiresAliases(true);
455             return this;
456         }
457
458         // Compute if a distinct is required during normalization.
459
if (shouldQueryToManyRelationship() && (!normalizer.getStatement().isDistinctComputed()) && (!normalizer.getStatement().isAggregateSelect())) {
460             normalizer.getStatement().useDistinct();
461         }
462
463         // Turn off DISTINCT if nestedTableMapping is used (not supported by Oracle 8.1.5).
464
if ((getMapping() != null) && getMapping().isNestedTableMapping()) {
465             // There are two types of nested tables, one used by clients, one used by mappings, do nothing in the mapping case.
466
if (!shouldQueryToManyRelationship()) {
467                 return this;
468             }
469             normalizer.getStatement().dontUseDistinct();
470         }
471
472         Expression mappingExpression = mappingCriteria();
473         if (mappingExpression != null) {
474             mappingExpression = mappingExpression.normalize(normalizer);
475         }
476         if (mappingExpression != null) {
477             // If the join was an outer join we must not add the join criteria to the where clause,
478
// if the platform prints the join in the from clause.
479
if (shouldUseOuterJoin() && (getSession().getPlatform().isInformixOuterJoin())) {
480                 normalizer.getStatement().getOuterJoinExpressions().addElement(this);
481                 normalizer.getStatement().getOuterJoinedMappingCriteria().addElement(mappingExpression);
482                 normalizer.addAdditionalExpression(mappingExpression.and(additionalExpressionCriteria()));
483                 return this;
484             } else if ((shouldUseOuterJoin() || isUsingOuterJoinForMultitableInheritance()) && (!getSession().getPlatform().shouldPrintOuterJoinInWhereClause())) {
485                 if(shouldUseOuterJoin()) {
486                     normalizer.getStatement().getOuterJoinExpressions().addElement(this);
487                     normalizer.getStatement().getOuterJoinedMappingCriteria().addElement(mappingExpression);
488                     normalizer.getStatement().getOuterJoinedAdditionalJoinCriteria().addElement(additionalExpressionCriteriaMap());
489                     normalizer.getStatement().getDescriptorsForMultitableInheritanceOnly().add(null);
490                     return this;
491                 } else {
492                     if (isUsingOuterJoinForMultitableInheritance()) {
493                         normalizer.getStatement().getOuterJoinExpressions().addElement(null);
494                         normalizer.getStatement().getOuterJoinedMappingCriteria().addElement(null);
495                         normalizer.getStatement().getOuterJoinedAdditionalJoinCriteria().addElement(additionalExpressionCriteriaMap());
496                         normalizer.getStatement().getDescriptorsForMultitableInheritanceOnly().add(getMapping().getReferenceDescriptor());
497                         // fall through to the main case
498
}
499                 }
500             }
501             
502             // This must be added even if outer. Actually it should be converted to use a right outer join, but that gets complex
503
// so we do not support this current which is a limitation in some cases.
504
if (foreignKeyJoinPointer != null) {
505                 // If this expression is right side of an objExp.equal(objExp), one
506
// need not add additionalExpressionCriteria twice.
507
// Also the join will replace the original objExp.equal(objExp).
508
// For CR#2456.
509
foreignKeyJoinPointer.add(mappingExpression);
510             } else {
511                 normalizer.addAdditionalExpression(mappingExpression.and(additionalExpressionCriteria()));
512             }
513         }
514
515         // For bug 2900974 special code for DirectCollectionMappings moved to printSQL.
516
return this;
517     }
518
519     /**
520      * INTERNAL:
521      * Print SQL onto the stream, using the ExpressionPrinter for context
522      */

523     public void printSQL(ExpressionSQLPrinter printer) {
524         if (isAttribute()) {
525             printer.printField(getAliasedField());
526         }
527
528         // If the mapping is a direct collection then this falls into a gray area.
529
// It must be treated as an attribute at this moment for it has a direct field.
530
// However it is not an attribute in the sense that it also represents a foreign
531
// reference and a mapping criteria has been added.
532
// For bug 2900974 these are now handled as non-attributes during normalize but
533
// as attributes when printing SQL.
534
//
535
if ((getMapping() != null) && getMapping().isDirectCollectionMapping()) {
536             DirectCollectionMapping directCollectionMapping = (DirectCollectionMapping)getMapping();
537
538             // The aliased table comes for free as it was a required part of the join criteria.
539
TableExpression table = (TableExpression)getTable(directCollectionMapping.getReferenceTable());
540             DatabaseTable aliasedTable = table.aliasForTable(table.getTable());
541             DatabaseField aliasedField = (DatabaseField)directCollectionMapping.getDirectField().clone();
542             aliasedField.setTable(aliasedTable);
543             printer.printField(aliasedField);
544         }
545     }
546
547     /**
548      * INTERNAL:
549      * Print java for project class generation
550      */

551     public void printJava(ExpressionJavaPrinter printer) {
552         getBaseExpression().printJava(printer);
553         if (!shouldUseOuterJoin()) {
554             if (!shouldQueryToManyRelationship()) {
555                 printer.printString(".get(");
556             } else {
557                 printer.printString(".anyOf(");
558             }
559         } else {
560             if (!shouldQueryToManyRelationship()) {
561                 printer.printString(".getAllowingNull(");
562             } else {
563                 printer.printString(".anyOfAllowingNone(");
564             }
565         }
566         printer.printString("\"" + getName() + "\")");
567     }
568
569     /**
570      * INTERNAL:
571      * This expression is built on a different base than the one we want. Rebuild it and
572      * return the root of the new tree
573      */

574     public Expression rebuildOn(Expression newBase) {
575         Expression newLocalBase = getBaseExpression().rebuildOn(newBase);
576         QueryKeyExpression result = null;
577
578         // For bug 3096634 rebuild outer joins correctly from the start.
579
if (shouldUseOuterJoin) {
580             result = (QueryKeyExpression)newLocalBase.getAllowingNull(getName());
581         } else {
582             result = (QueryKeyExpression)newLocalBase.get(getName());
583         }
584         if (shouldQueryToManyRelationship) {
585             result.doQueryToManyRelationship();
586         }
587         return result;
588     }
589
590     /**
591      * INTERNAL:
592      * A special version of rebuildOn where the newBase need not be a new
593      * ExpressionBuilder but any expression.
594      * <p>
595      * For nested joined attributes, the joined attribute query must have
596      * its joined attributes rebuilt relative to it.
597      */

598     public Expression rebuildOn(Expression oldBase, Expression newBase) {
599         if (this == oldBase) {
600             return newBase;
601         }
602         Expression newLocalBase = ((QueryKeyExpression)getBaseExpression()).rebuildOn(oldBase, newBase);
603         QueryKeyExpression result = null;
604
605         // For bug 3096634 rebuild outer joins correctly from the start.
606
if (shouldUseOuterJoin) {
607             result = (QueryKeyExpression)newLocalBase.getAllowingNull(getName());
608         } else {
609             result = (QueryKeyExpression)newLocalBase.get(getName());
610         }
611         if (shouldQueryToManyRelationship) {
612             result.doQueryToManyRelationship();
613         }
614         result.setSelectIfOrderedBy(selectIfOrderedBy());
615         return result;
616     }
617
618     /**
619      * Reset cached information here so that we can be sure we're accurate.
620      */

621     protected void resetCache() {
622         hasMapping = true;
623         mapping = null;
624         hasQueryKey = true;
625         queryKey = null;
626     }
627
628     public boolean shouldQueryToManyRelationship() {
629         return shouldQueryToManyRelationship;
630     }
631
632     /**
633      * INTERNAL:
634      * Rebuild myself against the base, with the values of parameters supplied by the context
635      * expression. This is used for transforming a standalone expression (e.g. the join criteria of a mapping)
636      * into part of some larger expression. You normally would not call this directly, instead calling twist
637      * See the comment there for more details"
638      */

639     public Expression twistedForBaseAndContext(Expression newBase, Expression context) {
640         Expression twistedBase = getBaseExpression().twistedForBaseAndContext(newBase, context);
641         QueryKeyExpression result = (QueryKeyExpression)twistedBase.get(getName());
642         if (shouldUseOuterJoin) {
643             result.doUseOuterJoin();
644         }
645         if (shouldQueryToManyRelationship) {
646             result.doQueryToManyRelationship();
647         }
648         return result;
649
650     }
651
652     /**
653      * Do any required validation for this node. Throw an exception if it's incorrect.
654      */

655     public void validateNode() {
656         if ((getQueryKeyOrNull() == null) && (getMapping() == null)) {
657             throw QueryException.invalidQueryKeyInExpression(getName());
658         }
659
660         QueryKey queryKey = getQueryKeyOrNull();
661         DatabaseMapping mapping = getMapping();
662
663         Object JavaDoc theOneThatsNotNull = null;
664         if (queryKey != null) {
665             theOneThatsNotNull = queryKey;
666         }
667         if (mapping != null) {
668             theOneThatsNotNull = mapping;
669         }
670
671         boolean qkIsToMany = false;
672         if (queryKey != null) {
673             qkIsToMany = queryKey.isManyToManyQueryKey() || queryKey.isOneToManyQueryKey();
674         }
675         if (mapping != null) {
676             // Bug 2847621 - Add Aggregate Collection to the list of valid items for outer join.
677
if (shouldUseOuterJoin && (!(mapping.isOneToOneMapping() || mapping.isOneToManyMapping() || mapping.isManyToManyMapping() || mapping.isAggregateCollectionMapping() || mapping.isDirectCollectionMapping()))) {
678                 throw QueryException.outerJoinIsOnlyValidForOneToOneMappings(getMapping());
679             }
680             qkIsToMany = mapping.isCollectionMapping();
681         }
682         if ((!shouldQueryToManyRelationship()) && qkIsToMany && (!mapping.isNestedTableMapping())) {
683             throw QueryException.invalidUseOfToManyQueryKeyInExpression(theOneThatsNotNull);
684         }
685         if (shouldQueryToManyRelationship() && !qkIsToMany) {
686             throw QueryException.invalidUseOfAnyOfInExpression(theOneThatsNotNull);
687         }
688     }
689
690     /**
691      * INTERNAL:
692      * Return the value for in memory comparison.
693      * This is only valid for valueable expressions.
694      */

695     public Object JavaDoc valueFromObject(Object JavaDoc object, AbstractSession session, AbstractRecord translationRow, InMemoryQueryIndirectionPolicy valueHolderPolicy, boolean isObjectUnregistered) {
696         // The expression may be across a relationship, in which case it must be traversed.
697
if ((getBuilder() != getBaseExpression()) && getBaseExpression().isQueryKeyExpression()) {
698             object = getBaseExpression().valueFromObject(object, session, translationRow, valueHolderPolicy, isObjectUnregistered);
699
700             // toDo: Null means the join filters out the row, returning null is not correct if an inner join,
701
// outer/inner joins need to be fixed to filter correctly.
702
if (object == null) {
703                 return null;
704             }
705
706             // If from an anyof the object will be a collection of values,
707
// A new vector must union the object values and the values extracted from it.
708
if (object instanceof Vector) {
709                 Vector comparisonVector = new Vector(((Vector)object).size() + 2);
710                 for (Enumeration valuesToIterate = (Enumeration)((Vector)object).elements();
711                          valuesToIterate.hasMoreElements();) {
712                     Object JavaDoc vectorObject = (Object JavaDoc)valuesToIterate.nextElement();
713                     if (vectorObject == null) {
714                         comparisonVector.addElement(vectorObject);
715                     } else {
716                         Object JavaDoc valueOrValues = valuesFromCollection(vectorObject, session, valueHolderPolicy, isObjectUnregistered);
717
718                         // If a collection of values were extracted union them.
719
if (valueOrValues instanceof Vector) {
720                             for (Enumeration nestedValuesToIterate = (Enumeration)((Vector)valueOrValues).elements();
721                                      nestedValuesToIterate.hasMoreElements();) {
722                                 comparisonVector.addElement(nestedValuesToIterate.nextElement());
723                             }
724                         } else {
725                             comparisonVector.addElement(valueOrValues);
726                         }
727                     }
728                 }
729                 return comparisonVector;
730             }
731         }
732         return valuesFromCollection(object, session, valueHolderPolicy, isObjectUnregistered);
733     }
734
735     /**
736      * INTERNAL
737      * This method iterates through a collection and gets the values from the objects to conform in an in-memory query.
738      * Creation date: (1/19/01 1:18:27 PM)
739      */

740     public Object JavaDoc valuesFromCollection(Object JavaDoc object, AbstractSession session, InMemoryQueryIndirectionPolicy valueHolderPolicy, boolean isObjectUnregistered) {
741         // in case the mapping is null - this can happen if a query key is being used
742
// In this case, check for the query key and find it's mapping.
743
boolean readMappingFromQueryKey = false;
744         if (getMapping() == null) {
745             getMappingFromQueryKey();
746             readMappingFromQueryKey = true;
747         }
748
749         // For bug 2780817 get the mapping directly from the object. In EJB 2.0
750
// inheritance, each child must override mappings defined in an abstract
751
// class with its own.
752
DatabaseMapping mapping = this.mapping;
753         if (mapping.getDescriptor().hasInheritance() && (mapping.getDescriptor().getJavaClass() != object.getClass())) {
754             mapping = session.getDescriptor(object.getClass()).getObjectBuilder().getMappingForAttributeName(getName());
755         }
756
757         //fetch group support
758
if (mapping.getDescriptor().hasFetchGroupManager()) {
759             FetchGroupManager fetchGroupMgr = mapping.getDescriptor().getFetchGroupManager();
760             if (fetchGroupMgr.isPartialObject(object) && (!fetchGroupMgr.isAttributeFetched(object, mapping.getAttributeName()))) {
761                 //the conforming attribute is not fetched, simply throw exception
762
throw QueryException.cannotConformUnfetchedAttribute(mapping.getAttributeName());
763             }
764         }
765
766         if (mapping.isForeignReferenceMapping()) {
767             //CR 3677 integration of a ValueHolderPolicy
768
Object JavaDoc valueFromMapping = mapping.getAttributeValueFromObject(object);
769             if (!((ForeignReferenceMapping)mapping).getIndirectionPolicy().objectIsInstantiated(valueFromMapping)) {
770                 if (!valueHolderPolicy.shouldTriggerIndirection()) {
771                     //If the client wishes us to trigger the indirection then we should do so,
772
//Other wise throw the exception
773
throw QueryException.mustInstantiateValueholders();// you should instantiate the valueholder for this to work
774
}
775
776                 // maybe we should throw this exception from the start, to save time
777
}
778             Object JavaDoc valueToIterate = mapping.getRealAttributeValueFromObject(object, session);
779             UnitOfWorkImpl uow = isObjectUnregistered ? (UnitOfWorkImpl)session : null;
780
781             // First check that object in fact is unregistered.
782
// toDo: ?? Why is this commented out? Why are we supporting the unregistered thing at all?
783
// Does not seem to be any public API for this, nor every used internally?
784
//if (isObjectUnregistered) {
785
// isObjectUnregistered = !uow.getCloneMapping().containsKey(object);
786
//}
787
if (mapping.isCollectionMapping() && (valueToIterate != null)) {
788                 // For bug 2766379 must use the correct version of vectorFor to
789
// unwrap the result same time.
790
valueToIterate = mapping.getContainerPolicy().vectorFor(valueToIterate, session);
791
792                 // toDo: If the value is empty, need to support correct inner/outer join filtering symantics.
793
// For CR 2612601, try to partially replace the result with already
794
// registered objects.
795
if (isObjectUnregistered && (uow.getCloneMapping().get(object) == null)) {
796                     Vector objectValues = (Vector)valueToIterate;
797                     for (int i = 0; i < objectValues.size(); i++) {
798                         Object JavaDoc original = objectValues.elementAt(i);
799                         Object JavaDoc clone = uow.getIdentityMapAccessorInstance().getIdentityMapManager().getFromIdentityMap(original);
800                         if (clone != null) {
801                             objectValues.setElementAt(clone, i);
802                         }
803                     }
804                 }
805
806                 // For CR 2612601, conforming without registering, a query could be
807
// bob.get("address").get("city").equal("Ottawa"); where the address
808
// has been registered and modified in the UOW, but bob has not. Thus
809
// even though bob does not point to the modified address now, it will
810
// as soon as it is registered, so should point to it here.
811
} else if (isObjectUnregistered && (uow.getCloneMapping().get(object) == null)) {
812                 Object JavaDoc clone = uow.getIdentityMapAccessorInstance().getIdentityMapManager().getFromIdentityMap(valueToIterate);
813                 if (clone != null) {
814                     valueToIterate = clone;
815                 }
816             }
817             return valueToIterate;
818         } else if (mapping.isDirectToFieldMapping()) {
819             return ((AbstractDirectMapping)mapping).valueFromObject(object, mapping.getField(), session);
820         } else if (mapping.isAggregateMapping()) {
821             Object JavaDoc aggregateValue = ((AggregateMapping)mapping).getAttributeValueFromObject(object);
822             ;
823             // Bug 3995468 - if this query key is to a mapping in an aggregate object, get the object from actual mapping rather than the aggregate mapping
824
while (readMappingFromQueryKey && mapping.isAggregateObjectMapping() && !((AggregateObjectMapping)mapping).getReferenceClass().equals(queryKey.getDescriptor().getJavaClass())) {
825                 mapping = mapping.getReferenceDescriptor().getObjectBuilder().getMappingForField(((DirectQueryKey)queryKey).getField());
826                 aggregateValue = mapping.getRealAttributeValueFromObject(aggregateValue, session);
827             }
828             return aggregateValue;
829         } else {
830             throw QueryException.cannotConformExpression();
831         }
832     }
833
834     /**
835      * INTERNAL:
836      * Used to print a debug form of the expression tree.
837      */

838     public void writeDescriptionOn(BufferedWriter writer) throws IOException {
839         writer.write(getName());
840         writer.write(tableAliasesDescription());
841     }
842
843     /**
844      * INTERNAL:
845      * Indicates that RelationExpression.normalize method shouldn't attempt
846      * optimize normalization by not normalizing this.
847      */

848     public boolean isNormalizationRequired() {
849         return shouldQueryToManyRelationship() ||
850             
851             // For bug 2718460, some QueryKeyExpressions have a query key but no mapping.
852
// An example is the "back-ref" query key for batch reads. Must not
853
// attempt the optimization for these.
854
getMapping() == null ||
855             
856             // For bug 5234283: WRONG =* SQL FOR LEFT JOIN ON DERBY AND DB2 PLATFORMS
857
// Caused by QueryKeyExpression never been normilized.
858
// The condition should be kept in sync with condtions in normalize method
859
// that trigger adding to normalizer.getStatement().getOuterJoin...
860
((shouldUseOuterJoin() || isUsingOuterJoinForMultitableInheritance()) && !getSession().getPlatform().shouldPrintOuterJoinInWhereClause()) ||
861             (shouldUseOuterJoin() && getSession().getPlatform().isInformixOuterJoin());
862     }
863 }
Popular Tags