KickJava   Java API By Example, From Geeks To Geeks.

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


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  * RetrieveDescImpl.java
26  *
27  * Created on March 3, 2000
28  *
29  */

30
31 package com.sun.jdo.spi.persistence.support.sqlstore.sql;
32
33 import com.sun.jdo.api.persistence.support.JDOFatalInternalException;
34 import com.sun.jdo.spi.persistence.support.sqlstore.ActionDesc;
35 import com.sun.jdo.spi.persistence.support.sqlstore.RetrieveDesc;
36 import com.sun.jdo.spi.persistence.support.sqlstore.SQLStoreManager;
37 import com.sun.jdo.spi.persistence.support.sqlstore.model.ClassDesc;
38 import com.sun.jdo.spi.persistence.support.sqlstore.model.LocalFieldDesc;
39 import com.sun.jdo.spi.persistence.support.sqlstore.sql.concurrency.Concurrency;
40 import com.sun.jdo.spi.persistence.support.sqlstore.sql.constraint.Constraint;
41 import com.sun.jdo.spi.persistence.support.sqlstore.sql.constraint.ConstraintFieldName;
42 import com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.SelectQueryPlan;
43 import com.sun.jdo.spi.persistence.utility.FieldTypeEnumeration;
44 import com.sun.jdo.spi.persistence.utility.I18NHelper;
45 import com.sun.jdo.spi.persistence.utility.ParameterInfo;
46
47 import java.util.ArrayList JavaDoc;
48 import java.util.Iterator JavaDoc;
49 import java.util.ResourceBundle JavaDoc;
50
51 /**
52  */

53 public class RetrieveDescImpl extends Object JavaDoc implements RetrieveDesc, Cloneable JavaDoc {
54
55     private static final int OPINFO_FIELD_DISALLOWED = 0x01; // 1
56

57     private static final int OPINFO_FIELD_REQUIRED = 0x02; // 2
58

59     private static final int OPINFO_VAL_DISALLOWED = 0x04; // 4
60

61     private static final int OPINFO_VAL_REQUIRED = 0x08; // 8
62

63     private static final int OPINFO_VAL_IS_PCOUNT = 0x10; // 16
64

65     private static final int OPINFO_ILLEGAL = 0x20; // 32
66

67     private static final int OPINFO_NO_OPERATION = 0x40; // 64
68

69     /** Indicates, that the query projects on this RD. */
70     public static final int OPT_PROJECTION = 0x1; // 1
71

72     /** Indicates, that a distinct query should be run. */
73     public static final int OPT_DISTINCT = 0x2; // 2
74

75     /** Indicates, that the selected rows should be locked for update. */
76     public static final int OPT_FOR_UPDATE = 0x4; // 4
77

78     /** Indicates, that an avg aggregate query should be run. */
79     public static final int OPT_AVG = 0x08; // 8
80

81     /** Indicates, that a min aggregate query should be run. */
82     public static final int OPT_MIN = 0x10; // 16
83

84     /** Indicates, that a max aggregate query should be run. */
85     public static final int OPT_MAX = 0x20; // 32
86

87     /** Indicates, that a sum aggregate query should be run. */
88     public static final int OPT_SUM = 0x40; // 64
89

90     /** Indicates, that a count aggregate query should be run. */
91     public static final int OPT_COUNT = 0x80; // 128
92

93     /** Special treatment for count on persistent capable objects. */
94     public static final int OPT_COUNT_PC = 0x100; // 256
95

96     /** Sum of all aggregate options. */
97     public static final int OPT_AGGREGATE = OPT_AVG + OPT_MIN + OPT_MAX +
98             OPT_SUM + OPT_COUNT + OPT_COUNT_PC;
99
100     /** Sum of all aggregate options excluding count on persistent capable objects. */
101     public static final int OPT_AGGREGATE_NON_COUNT_PC = OPT_AGGREGATE - OPT_COUNT_PC;
102
103     /** Indicates, that fetch group fields should be added. */
104     public static final int OPT_ADD_FETCHGROUPS = 0x200; // 512
105

106     /**
107      * Indicates, that only key fields should be added. When this option is set,
108      * it modifies meaning of OPT_ADD_FETCHGROUPS. It is assumed that
109      * only key fieldes from the fetch group will be added.
110      */

111     public static final int OPT_ADD_KEYS_ONLY = 0x400; // 1024
112

113     /**
114      * Indicates, that even if relationship fields are in DFG, they should not
115      * be prefetched. The runtime will attempt to fetch relationhip fields only
116      * when OPT_ADD_FETCH_GROUPS is set.
117      * @see #OPT_ADD_FETCHGROUPS
118      * @see #OPT_ADD_KEYS_ONLY
119      */

120     public static final int OPT_DISABLE_RELATIONSHIP_PREFETCH = 0x800; // 2048
121

122     /** Indicates special treatment for version consistency verifications. */
123     public static final int OPT_VERIFY = 0x1000; // 4024
124

125     /** Array of ConstraintFieldName. */
126     private ArrayList JavaDoc fields;
127
128     /** The constraint stack */
129     private Constraint constraint;
130
131     /** Bitmask of options for this instance as specified by the OPT_* constants */
132     private int options;
133
134     /** Candidate class of this instance */
135     private Class JavaDoc pcClass;
136
137     /** Config for candidate class of this instance */
138     private ClassDesc config;
139
140     /** SelectQueryPlan for this instance */
141     private SelectQueryPlan plan;
142
143     /**
144      * Discriminates different retrieve descriptors which use the same
145      * navigational field.
146      */

147     private Object JavaDoc navigationalId;
148
149     /** Result type for an aggregate query. */
150     private int aggregateResultType = FieldTypeEnumeration.NOT_ENUMERATED;
151
152     /**
153      * I18N message handler
154      */

155     private final static ResourceBundle JavaDoc messages = I18NHelper.loadBundle(
156             "com.sun.jdo.spi.persistence.support.sqlstore.Bundle", // NOI18N
157
RetrieveDescImpl.class.getClassLoader());
158
159     public RetrieveDescImpl(Class JavaDoc pcClass, ClassDesc config) {
160         super();
161
162         this.pcClass = pcClass;
163         this.config = config;
164         fields = new ArrayList JavaDoc();
165         constraint = new Constraint();
166     }
167
168     /**
169      * The addResult method is used to specify which fields should be
170      * returned in a persistent object. If the field requested is a
171      * reference to another persistent object then a RetrieveDesc may be
172      * provided which describes which fields of the referenced object
173      * should be returned and, optionally, constraints on it.
174      * If the parameter <code>projection</code> is true, the field
175      * specified by <code>name</code> should be projected.
176      *
177      * @param name The name of the field to return.
178      * @param foreignConstraint
179      * RetrieveDesc describing fields and constraints for a referenced object.
180      * @param projection Specifies, if this is a projection.
181      */

182     public void addResult(String JavaDoc name,
183                           RetrieveDesc foreignConstraint,
184                           boolean projection) {
185         ConstraintFieldName cfName = new ConstraintFieldName(name, foreignConstraint);
186
187         if (projection) {
188             if ((options & OPT_PROJECTION) > 0) {
189                 throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
190                         "sqlstore.retrievedesc.toomanyprojections")); // NOI18N
191
}
192
193             // For projections on foreign fields, mark the foreign constraint.
194
// For local fields, set the property on the field constraint.
195
if (foreignConstraint != null) {
196                 ((RetrieveDescImpl) foreignConstraint).options |= OPT_PROJECTION;
197             } else {
198                 cfName.setProjection();
199
200                 // Set this property if you want to have DFG fields added for
201
// projections on local fields.
202
// options = options | OPT_PROJECTION;
203
}
204         }
205         fields.add(cfName);
206     }
207
208     /**
209      * The addResult method can be used to specify <it>global</it>
210      * query attributes that don't end up in the where clause.
211      * Aggregate functions and the distinct op code are examples for
212      * those query options. The result type defines the object to be
213      * returned by an aggregate query. In case of distinct the result
214      * type should be FieldTypeEnumeration.NOT_ENUMERATED. The method
215      * might be called twice, in case of a JDOQL query having both an
216      * aggregate and distinct:
217      * query.setResult("avg (distinct salary)");
218      * ->
219      * retrieveDesc.addResult(OP_AVG, FieldTypeEnumeration.DOUBLE);
220      * retrieveDesc.addResult(OP_DISTINCT, FieldTypeEnumeration.NOT_ENUMERATED);
221      * retrieveDesc.addResult("salary", null, true);
222      *
223      * @param opCode The operation code.
224      * @param aggregateResultType The object type returned by aggregate queries.
225      * @see com.sun.jdo.spi.persistence.utility.FieldTypeEnumeration
226      */

227     public void addResult(int opCode, int aggregateResultType) {
228         switch (opCode) {
229             case ActionDesc.OP_DISTINCT:
230                 options = options | OPT_DISTINCT;
231                 break;
232             case ActionDesc.OP_AVG:
233                 options = options | OPT_AVG;
234                 break;
235             case ActionDesc.OP_MIN:
236                 options = options | OPT_MIN;
237                 break;
238             case ActionDesc.OP_MAX:
239                 options = options | OPT_MAX;
240                 break;
241             case ActionDesc.OP_SUM:
242                 options = options | OPT_SUM;
243                 break;
244             case ActionDesc.OP_COUNT:
245                 options = options | OPT_COUNT;
246                 break;
247             case ActionDesc.OP_COUNT_PC:
248                 options = options | OPT_COUNT_PC;
249                 break;
250             default:
251                 throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
252                         "core.constraint.illegalop", "" + opCode)); // NOI18N
253
}
254
255         if (aggregateResultType != FieldTypeEnumeration.NOT_ENUMERATED) {
256             if (this.aggregateResultType == FieldTypeEnumeration.NOT_ENUMERATED) {
257                 this.aggregateResultType = aggregateResultType;
258             } else {
259                 // aggregate result type has already been set
260
throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
261                         "sqlstore.retrievedesc.toomanyresulttypes")); // NOI18N
262
}
263         }
264     }
265
266     /**
267      * Add a field specified by <code>name</code> to the list of fields to be prefetched.
268      * @param name Name of the field to be prefetched.
269      * @param foreignConstraint This parameter is null if the field is a local field.
270      * If the field is a foreign field, this parameter should be not null and must refer
271      * to an instance of RetrieveDesc correpsonding to the config of the foreign field.
272      */

273     public void addPrefetchedField(String JavaDoc name, RetrieveDesc foreignConstraint) {
274         fields.add(new ConstraintFieldName(name, foreignConstraint, true));
275     }
276
277     /**
278      * {@inheritDoc}
279      */

280     public void setPrefetchEnabled(boolean prefetchEnabled) {
281         if (!prefetchEnabled) {
282             options |= OPT_DISABLE_RELATIONSHIP_PREFETCH;
283         } else {
284             // options has the flag OPT_DISABLE_RELATIONSHIP_PREFETCH unset by default
285
}
286     }
287
288     /**
289      * <P>Adds a constraint on the foreign field specified by
290      * <code>name</code>. This method is used to specify a relationship
291      * navigation on field <code>name</code> to the class represented by
292      * the retrieve descriptor <code>foreignConstraint</code>.
293      * If <code>name</code> is null, an unrelated constraint is added.
294      * A constraint is unrelated, if there is neither a foreign field
295      * nor a local field connecting to the retrieve descriptor
296      * <code>foreignConstraint</code>.
297      */

298     public void addConstraint(String JavaDoc name,
299                               RetrieveDesc foreignConstraint) {
300         if (name == null) {
301             constraint.addField(null, foreignConstraint);
302         } else {
303             constraint.addForeignField(name, foreignConstraint);
304         }
305     }
306
307     /**
308      * <P>Adds a constraint on the relationship field specified by
309      * <code>name</code>.
310      * This method is useful e.g. for comparisons of local fields with field of a related object:
311      * emp.addConstraint("lastName", ActionDesc.OP_EQ, mgr, lastName");
312      * compares the employee's lastName field with the lastName field of the related manager.
313      */

314     public void addConstraint(String JavaDoc name, int operation,
315                               RetrieveDesc foreignConstraint, String JavaDoc foreignName) {
316         constraint.addField(foreignName, foreignConstraint);
317         constraint.addField(name, null);
318         constraint.addOperation(operation);
319     }
320
321     /**
322      * The addConstraint method is used to limit the values of fields for
323      * objects being selected.
324      * addConstraint pushes the value, name, and operation onto the
325      * Constraint stack. The constraints are anded together by default.
326      * Arbitrarily complex relationships on the Constraint stack are supported.
327      * The Constraint stack can be manipulated directly if necessary.
328      *
329      * @param name
330      * The name parameter specifies the field whose value
331      * should be limited.
332      * @param operation
333      * The operation parameter specifies the relationship the field
334      * should bear to the value. Values for operation are defined in
335      * the ActionDesc interface.
336      * @param value
337      * The value parameter usually specifies the value to which the
338      * field should be limited, however it is sometimes used to
339      * hold a parameter count as for the OP_IN operation.
340      */

341     public void addConstraint(String JavaDoc name,
342                               int operation,
343                               Object JavaDoc value) {
344         int info = getOperationInfo(operation);
345
346         if ((info & OPINFO_ILLEGAL) > 0) {
347             throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
348                     "core.constraint.illegalop", "" + operation)); // NOI18N
349
} else if ((info & OPINFO_FIELD_REQUIRED) > 0 && name == null) {
350             throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
351                     "core.constraint.fieldrequired", "" + operation)); // NOI18N
352
} else if ((info & OPINFO_FIELD_DISALLOWED) > 0 && name != null) {
353             throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
354                     "core.constraint.fielddisallowed", "" + operation)); // NOI18N
355
} else if ((info & OPINFO_VAL_REQUIRED) > 0 && value == null) {
356             throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
357                     "core.constraint.valrequired", "" + operation)); // NOI18N
358
} else if ((info & OPINFO_VAL_DISALLOWED) > 0 && value != null) {
359             throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
360                     "core.constraint.valdisallowed", "" + operation)); // NOI18N
361
}
362         if ((info & OPINFO_VAL_IS_PCOUNT) > 0) {
363             if (name != null) {
364                 constraint.addField(name, null);
365             }
366             addValueConstraint(name, value);
367         } else {
368             switch (operation) {
369                 case RetrieveDescImpl.OP_PARAMETER:
370                     addParameterConstraint(value);
371                     break;
372                 case ActionDesc.OP_IN:
373                 case ActionDesc.OP_NOTIN:
374                     constraint.addConstraintFieldSubQuery(name,(ActionDesc) value);
375                     break;
376                 default:
377                     if (value != null) {
378                         addValueConstraint(name, value);
379                     }
380                     if (name != null) {
381                         constraint.addField(name, null);
382                     }
383                     break;
384             }
385         }
386         if ((info & OPINFO_NO_OPERATION) == 0) {
387             constraint.addOperation(operation);
388         }
389     }
390
391     /**
392      * Add Constraints corresponding to given <code>fields</code>.
393      * The constraints are added as Parameter Constraints.
394      * index of the parameter starts at given <code>startIndex</code>
395      * @param fields fields for which constraints are to be added.
396      * @param startIndex starting Index for the parameter.
397      */

398     public void addParameterConstraints(LocalFieldDesc[] fields, int startIndex) {
399         for (int i = 0; i < fields.length; i++) {
400             LocalFieldDesc field = fields[i];
401             addParameterConstraint(field, i + startIndex);
402         }
403     }
404
405     /**
406      * Add ParameterConstraint corresponding to given <code>field</code>
407      * at given <code>index</code>.
408      * @param field The field for which constraints are to be added.
409      * @param index Index at which the ParameterConstraint is to be inserted.
410      */

411     public void addParameterConstraint(LocalFieldDesc field, int index) {
412         // Generate parameter info for this parameter.
413
String JavaDoc fieldName = field.getName();
414         int type = field.getEnumType();
415
416         addConstraint(null, ActionDesc.OP_PARAMETER,new ParameterInfo(index, type, fieldName));
417         addConstraint(fieldName, ActionDesc.OP_FIELD, null);
418         addConstraint(null, ActionDesc.OP_EQ, null);
419     }
420
421     /**
422      * Adds information about <code>value</code> on the constraint stack.
423      * @param name Name of the field to which the specified value is bound.
424      * The query compiler can detect the correct value for name only in
425      * case of simple expressions in the filter. A simple expression is
426      * <em>fieldName op value</em>. If the compiler is not able to detect
427      * correct value for name it will pass null.
428      * @param value value to which the field's value is constrained.
429      */

430     private void addValueConstraint(String JavaDoc name, Object JavaDoc value) {
431         constraint.addValue(value, getLocalFieldDesc(name));
432     }
433
434     /**
435      * Adds information about parameter on the constraint stack.
436      * @param value Instance of
437      * <code>com.sun.jdo.spi.persistence.utility.ParameterInfo</code>.
438      * Contains index, type and name of the field to which
439      * this parameter is bound. The field name is used when binding
440      * the parameter to the sql statement.
441      * name can be null for complex expressions in a filter as described in
442      * addValueConstraint.
443      * @see #addValueConstraint
444      */

445     private void addParameterConstraint(Object JavaDoc value) {
446         if (value instanceof ParameterInfo) {
447             ParameterInfo parameterInfo = (ParameterInfo)value;
448             constraint.addParamIndex(parameterInfo.getIndex(), parameterInfo.getType(),
449                     getLocalFieldDesc(parameterInfo.getAssociatedField()));
450         } else {
451             throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
452                     "core.constraint.illegalParameterInfo")); // NOI18N
453
}
454     }
455
456     /**
457      * Returns the local field descriptor for the field <code>name</code>.
458      * Delegates to <code>ClassDesc#getLocalFieldDesc(String)<code>.
459      *
460      * @param name Field name.
461      * @return null if the <code>name</code> is null.
462      * LocalFieldDesc for the field <code>name</code> otherwise.
463      */

464     private LocalFieldDesc getLocalFieldDesc(String JavaDoc name) {
465         return name == null ? null : config.getLocalFieldDesc(name);
466     }
467
468     /**
469      * The getOperationInfo method returns information about the operation
470      * requested. The following constants define different properties of
471      * an operation and can be or'd together:
472      * OPINFO_FIELD_DISALLOWED A field parameter cannot be specified
473      * with this operation
474      * OPINFO_FIELD_REQUIRED A field parameter must be specified
475      * with this operation
476      * OPINFO_VAL_DISALLOWED A value parameter cannot be specified
477      * with this operation
478      * OPINFO_VAL_REQUIRED A value parameter must be specified
479      * with this operation
480      * OPINFO_NULL This operation is a "null" type operation
481      * (i.e. "is null", or "is not null")
482      * OPINFO_ILLEGAL This operation is illegal
483      * OPINFO_NO_OPERATION This isn't an operation at all,
484      * it is some other specifier.
485      * OPINFO_VAL_IS_PCOUNT This operation has a value which is the
486      * parameter count of following parameter
487      * nodes
488      *
489      * @param operation
490      * The operation parameter specifies the operation for which
491      * information is desired.
492     */

493     private static int getOperationInfo(int operation) {
494         int info;
495         switch (operation) {
496             case ActionDesc.OP_ABS:
497                 info = OPINFO_VAL_DISALLOWED;
498                 break;
499             case ActionDesc.OP_ADD:
500                 info = 0;
501                 break;
502             case ActionDesc.OP_AND:
503                 info = 0;
504                 break;
505             case ActionDesc.OP_FIELD:
506                 info = OPINFO_FIELD_REQUIRED | OPINFO_VAL_DISALLOWED | OPINFO_NO_OPERATION;
507                 break;
508             case ActionDesc.OP_BETWEEN:
509                 info = 0;
510                 break;
511             case ActionDesc.OP_DIV:
512                 info = 0;
513                 break;
514             case ActionDesc.OP_EQ:
515                 info = 0;
516                 break;
517             case ActionDesc.OP_NE:
518                 info = 0;
519                 break;
520             case ActionDesc.OP_EQUIJOIN:
521                 info = 0;
522                 break;
523             case ActionDesc.OP_NOT:
524                 info = OPINFO_FIELD_DISALLOWED | OPINFO_VAL_DISALLOWED;
525                 break;
526             case ActionDesc.OP_GE:
527                 info = 0;
528                 break;
529             case ActionDesc.OP_GT:
530                 info = 0;
531                 break;
532             case ActionDesc.OP_IN:
533             case ActionDesc.OP_NOTIN:
534                 info = OPINFO_FIELD_REQUIRED | OPINFO_VAL_REQUIRED;
535                 break;
536             case ActionDesc.OP_LE:
537                 info = 0;
538                 break;
539             case ActionDesc.OP_LEFTJOIN:
540                 info = 0;
541                 break;
542             case ActionDesc.OP_LENGTH:
543                 info = OPINFO_VAL_DISALLOWED;
544                 break;
545             case ActionDesc.OP_LIKE:
546                 info = 0;
547                 break;
548             case ActionDesc.OP_LIKE_ESCAPE:
549                 info = 0;
550                 break;
551             case ActionDesc.OP_LT:
552                 info = 0;
553                 break;
554             case ActionDesc.OP_LTRIM:
555                 info = OPINFO_VAL_DISALLOWED;
556                 break;
557             case ActionDesc.OP_MUL:
558                 info = 0;
559                 break;
560             case ActionDesc.OP_OR:
561                 info = 0;
562                 break;
563             case ActionDesc.OP_ORDERBY:
564                 info = 0;
565                 break;
566             case ActionDesc.OP_ORDERBY_DESC:
567                 info = 0;
568                 break;
569             case ActionDesc.OP_PARAMETER_COUNT:
570                 info = OPINFO_FIELD_DISALLOWED | OPINFO_VAL_REQUIRED | OPINFO_VAL_IS_PCOUNT | OPINFO_NO_OPERATION;
571                 break;
572             case ActionDesc.OP_RIGHTJOIN:
573                 info = 0;
574                 break;
575             case ActionDesc.OP_RTRIM:
576                 info = OPINFO_VAL_DISALLOWED;
577                 break;
578             case ActionDesc.OP_SQRT:
579                 info = OPINFO_VAL_DISALLOWED;
580                 break;
581             case ActionDesc.OP_SUB:
582                 info = 0;
583                 break;
584             case ActionDesc.OP_SUBSTRING:
585                 info = 0;
586                 break;
587             case ActionDesc.OP_POSITION:
588                 info = 0;
589                 break;
590             case ActionDesc.OP_POSITION_START:
591                 info = 0;
592                 break;
593             case ActionDesc.OP_MAYBE_NULL:
594                 info = OPINFO_FIELD_REQUIRED;
595                 break;
596             case ActionDesc.OP_CONCAT:
597                 info = 0;
598                 break;
599             case ActionDesc.OP_VALUE:
600                 info = OPINFO_FIELD_DISALLOWED | OPINFO_VAL_REQUIRED | OPINFO_NO_OPERATION;
601                 break;
602             case ActionDesc.OP_PARAMETER:
603                 info = OPINFO_FIELD_DISALLOWED | OPINFO_VAL_REQUIRED | OPINFO_NO_OPERATION;
604                 break;
605             case OP_NULL:
606             case OP_NOTNULL:
607                 info = 0;
608                 break;
609             case ActionDesc.OP_MOD:
610                 info = 0;
611                 break;
612             default:
613                 info = OPINFO_ILLEGAL;
614                 break;
615         }
616         return info;
617     }
618
619     /**
620      * Builds the internal query plan and initializes the select statements.
621      * Projections on collection fields will not be resolved until the actual
622      * retrieval in {@link SQLStoreManager#retrieve(
623      * com.sun.jdo.spi.persistence.support.sqlstore.PersistenceManager,
624      * RetrieveDesc, com.sun.jdo.spi.persistence.support.sqlstore.ValueFetcher)}.
625      */

626     public synchronized SelectQueryPlan buildQueryPlan(SQLStoreManager store,
627                                                        Concurrency concurrency) {
628
629         if (plan == null) {
630
631             handleProjection();
632
633             plan = SelectQueryPlan.newInstance(this, store, concurrency);
634
635             plan.build();
636
637             // Generate the text for the select statements.
638
ArrayList JavaDoc statements = plan.getStatements();
639
640             // Sanity check.
641
if (statements.size() > 1) {
642                 throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
643                         "sqlstore.retrievedesc.stmntsnotjoined")); // NOI18N
644
}
645         }
646         return plan;
647     }
648
649     /**
650      * Sets the fetch group options for all retrieve descriptors in the
651      * retrieve descriptor hierarchy. This is important for projection and
652      * aggregate queries, as we don't want to select additional fields
653      * from the data store. This is also important for queries where relationship
654      * prefetch is involved, as we want to propagate user's choice to disable
655      * relationship prefetch for a finder to all the retrieve descriptors in
656      * the projection tree.
657      * Also sets the projection on the candidate class in case of queries without
658      * user projection.
659      */

660     private void handleProjection() {
661         // Prepare all the query options that need to be distributed to all the
662
// RetrieveDescs involved in the projection tree.
663
final int queryOptions = options & (OPT_AGGREGATE | OPT_DISABLE_RELATIONSHIP_PREFETCH);
664         RetrieveDescImpl projectedDesc = distributeQueryOptions(
665                 queryOptions, aggregateResultType);
666
667         if (projectedDesc == null) {
668             // Set the default projection on the candidate retrieve descriptor.
669
options |= OPT_PROJECTION;
670             // Prepare fetch group options again after default projection has been set.
671
setFetchGroupOptions(queryOptions);
672         }
673     }
674
675     /**
676      * Marks each descriptor with the options <code>queryOptions</code> and
677      * finds the projection in the retrieve descriptor hierarchy.
678      * The query options have to be known for each descriptor, because we don't want to
679      * generate outer joins for OPT_COUNT_PC and we want to propagate users
680      * choice to disable prefetch for a finder to projected RetrieveDesc.
681      * This method relies on the fact, that each query can have only
682      * <b>one</b> projection.
683      *
684      * @param queryOptions The options that need to be set on all
685      * retrieve descriptors. This helps identify aggregate queries, see
686      * {@link SelectQueryPlan#processJoins()}.
687      * This also helps propagate user's choice to disable prefetch to the
688      * projected RetrieveDesc, see
689      * {@link SelectQueryPlan#addFetchGroup(int, java.util.ArrayList, java.util.ArrayList)}.
690      * @param aggregateResultType The aggregate result type has to
691      * be set on the projected retrieve descriptor.
692      * @return The projected retrieve descriptor, or null there is
693      * no projection.
694      */

695     private RetrieveDescImpl distributeQueryOptions(int queryOptions,
696                                                     int aggregateResultType) {
697         RetrieveDescImpl projectedDesc = null;
698
699         if ((options & OPT_PROJECTION) > 0) {
700             // This is a foreign field projection.
701
// Set the fetch group properties.
702
setFetchGroupOptions(queryOptions);
703             this.aggregateResultType = aggregateResultType;
704             projectedDesc = this;
705         }
706
707         // Distribute the aggregate option to all retrieve descriptors.
708
options |= queryOptions;
709
710         // Loop through all dependent retrieve descriptors in the field list.
711
for (int i = 0; i < fields.size(); i++) {
712             ConstraintFieldName cfn = (ConstraintFieldName) fields.get(i);
713
714             if (cfn.isProjection()) {
715                 // This is a local field projection.
716
// No fetch groups are added.
717
this.aggregateResultType = aggregateResultType;
718                 projectedDesc = this;
719             } else if (cfn.desc != null) {
720                 projectedDesc = ((RetrieveDescImpl) cfn.desc).distributeQueryOptions(
721                         queryOptions, aggregateResultType);
722             }
723         }
724
725         return projectedDesc;
726     }
727
728     /**
729      * Sets the fetch group policy for the projected retrieve descriptor.
730      * The policy is based on the following rules:
731      *
732      * <ul>
733      * <li>Fetchgroups are added for a projection w/o aggregates.</li>
734      * <li>Only keys are added for count(*) queries.</li>
735      * </ul>
736      *
737      * @param queryOptions The quey options that needs to be set for ********
738      * <code>queryOptions</code> Aggregate queries impose
739      * special restrictions on which fields to be selected. All aggregate
740      * queries except count(*) operate on exactly one field. Count(*)
741      * queries operate on persistence capable objects.
742      * @see SelectQueryPlan#processFetchGroups(ArrayList, ArrayList)
743      */

744     private void setFetchGroupOptions(int queryOptions) {
745
746         if ((queryOptions & OPT_AGGREGATE_NON_COUNT_PC) == 0) {
747             // Don't add fetch groups except for projections
748
// w/o aggregates or counts on persistence capable objects.
749
options |= OPT_ADD_FETCHGROUPS;
750
751             if (queryOptions == OPT_COUNT_PC) {
752                 options |= OPT_ADD_KEYS_ONLY;
753             }
754         }
755     }
756
757     /**
758      * Sets a navigational id on the retrieve descriptor. This id
759      * will be used to discriminate different retrieve descriptors which
760      * use the same navigational field. If not set, the field name is used.
761      *
762      * @param navigationalId Tag to discriminate different retrieve
763      * descriptors that use the same navigational field.
764      */

765     public void setNavigationalId(Object JavaDoc navigationalId) {
766         this.navigationalId = navigationalId;
767     }
768
769     /**
770      * Returns the navigational id of this retrieve descriptor. This id
771      * will be used to discriminate different retrieve descriptors which
772      * use the same navigational field. If not set, the field name is used.
773      *
774      * @return Tag to discriminate different retrieve descriptors that
775      * use the same navigational field.
776      */

777     public Object JavaDoc getNavigationalId() {
778         return navigationalId;
779     }
780
781     /**
782      * Sets option <code>option</code>. Only used to mark this
783      * retrieve descriptor as internal. All valid options are defined
784      * in this class.
785      *
786      * @param option Option being set.
787      */

788     public void setOption(int option) {
789         this.options |= option;
790     }
791
792     /**
793      * Returns the result type for aggregate queries.
794      */

795     public int getAggregateResultType() {
796         return aggregateResultType;
797     }
798
799     /**
800      * Returns the options of this retrieve descriptor.
801      *
802      * @return The options of this retrieve descriptor.
803      */

804     public int getOptions() {
805         return options;
806     }
807
808     public SelectQueryPlan getPlan() {
809         return plan;
810     }
811
812     public ClassDesc getConfig() {
813         return config;
814     }
815
816     public void setPlan(SelectQueryPlan plan) {
817         this.plan = plan;
818     }
819
820     public Class JavaDoc getPersistenceCapableClass() {
821         return pcClass;
822     }
823
824     public Constraint getConstraint() {
825         return constraint;
826     }
827
828     public Iterator JavaDoc getFields() {
829         return fields.iterator();
830     }
831
832     public Object JavaDoc clone() {
833         try {
834             RetrieveDescImpl clone = (RetrieveDescImpl) super.clone();
835             clone.fields = new ArrayList JavaDoc();
836             clone.constraint = new Constraint();
837
838             return clone;
839         } catch (CloneNotSupportedException JavaDoc e) {
840             //
841
// shouldn't happen.
842
//
843
return null;
844         }
845     }
846
847 }
848
Popular Tags