KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > queryframework > ReportQuery


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

21 // Copyright (c) 1998, 2006, Oracle. All rights reserved.
22
package oracle.toplink.essentials.queryframework;
23
24 import java.util.*;
25 import oracle.toplink.essentials.expressions.*;
26 import oracle.toplink.essentials.internal.expressions.*;
27 import oracle.toplink.essentials.internal.queryframework.*;
28 import oracle.toplink.essentials.exceptions.*;
29 import oracle.toplink.essentials.internal.helper.*;
30 import oracle.toplink.essentials.mappings.*;
31 import oracle.toplink.essentials.internal.security.PrivilegedAccessHelper;
32 import oracle.toplink.essentials.internal.sessions.AbstractRecord;
33 import oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl;
34 import oracle.toplink.essentials.internal.sessions.AbstractSession;
35 import oracle.toplink.essentials.descriptors.ClassDescriptor;
36
37 /**
38  * <b>Purpose</b>: Query for information about a set of objects instead of the objects themselves.
39  * This supports select single attributes, nested attributes, aggregation functions and group bys.<p>
40  *
41  * <b>Attribute Types</b>:<ol>
42  * <li>addAttribute("directQueryKey") is a short cut method to add an attribute with the same name as its corresponding direct query key.
43  * <li>addAttribute("attributeName", expBuilder.get("oneToOneMapping").get("directQueryKey")) is the full approach for get values through joined 1:1 relationships.
44  * <li>addAttribute("attributeName", expBuilder.getField("TABLE.FIELD")) allows the addition of raw values or values which were not mapped in the object model directly (i.e. FK attributes).
45  * <li>addAttribute("attributeName", null) Leave a place holder (NULL) value in the result (used for included values from other systems or calculated values).
46  * </ol>
47  * <b>Retrieving Primary Keys</b>: It is possble to retrieve the primary key raw values within each result, but stored in a separate (internal) vector. This
48  * primary key vector can later be used to retrieve the real object.
49  * @see #retrievePrimaryKeys()
50  * @see ReportQueryResult#readObject(Class, Session)
51  * If the values are wanted in the result array then they must be added as attributes. For primary keys which are not mapped directly
52  * you can add them as DatabaseFields (see above).
53  *
54  * @author Doug Clarke
55  * @since TOPLink/Java 2.0
56  */

57 public class ReportQuery extends ReadAllQuery {
58
59     /** Simplifies the result by only returning the first result. */
60     public static final int ShouldReturnSingleResult = 1;
61
62     /** Simplifies the result by only returning one value. */
63     public static final int ShouldReturnSingleValue = 2;
64
65     /** Simplifies the result by only returning the single attribute(as opposed to wrapping in a
66     ReportQueryResult). */

67     public static final int ShouldReturnSingleAttribute = 3;
68     
69     /** For EJB 3 support returns results without using the ReportQueryResult */
70     public static final int ShouldReturnWithoutReportQueryResult = 4;
71
72     /** Specifies whether to retreive primary keys, first primary key, or no primary key.*/
73     public static final int FULL_PRIMARY_KEY = 2;
74     public static final int FIRST_PRIMARY_KEY = 1;
75     public static final int NO_PRIMARY_KEY = 0;
76     
77     //GF_ISSUE_395
78
protected static final Boolean JavaDoc RESULT_IGNORED = Boolean.valueOf(true);
79     //end GF_ISSUE
80

81     /** Flag indicating wether the primary key values should also be retrieved for the reference class. */
82     protected int shouldRetrievePrimaryKeys;
83
84     /** Collection of names for use by results. */
85     protected Vector names;
86
87     /** Items to be selected, these could be attributes or aggregate functions. */
88     protected Vector items;
89
90     /** Expressions representing fields to be used in the GROUP BY clause. */
91     protected Vector groupByExpressions;
92     
93     /** Expression representing the HAVING clause. */
94     protected Expression havingExpression;
95
96     /** Can be one of (ShouldReturnSingleResult, ShouldReturnSingleValue, ShouldReturnSingleAttribute)
97      ** Simplifies the result by only returning the first result, first value, or all attribute values
98      */

99     protected int returnChoice;
100     
101     /** flag to allow items to be added to the last ConstructorReportItem **/
102     protected boolean addToConstructorItem;
103     protected Class JavaDoc resultConstructorClass;
104     protected Class JavaDoc[] constructorArgTypes;
105     protected List constructorMappings;
106     
107     /* GF_ISSUE_395 this attribute stores a set of unique keys that identity results.
108      * Used when distinct has been set on the query. For use in TCK
109      */

110     protected HashSet returnedKeys;
111
112     /**
113      * INTERNAL:
114      * The builder should be provided.
115      */

116     public ReportQuery() {
117         this.queryMechanism = new ExpressionQueryMechanism(this);
118         this.items = new Vector();
119         this.shouldRetrievePrimaryKeys = NO_PRIMARY_KEY;
120         this.groupByExpressions = new Vector(3);
121         this.havingExpression=null;
122         this.addToConstructorItem = false;
123
124         // overwrite the lock mode to NO_LOCK, this prevents the report query to lock
125
// when DEFAULT_LOCK_MODE and a pessimistic locking policy are used.
126
this.setLockMode(ObjectBuildingQuery.NO_LOCK);
127     }
128
129     public ReportQuery(Class JavaDoc javaClass, Expression expression) {
130         this();
131         this.defaultBuilder = expression.getBuilder();
132         setReferenceClass(javaClass);
133         setSelectionCriteria(expression);
134     }
135
136     /**
137      * PUBLIC:
138      * The report query is require to be constructor with an expression builder.
139      * This build must be used for the selection critiera, any item expressions, group bys and order bys.
140      */

141     public ReportQuery(Class JavaDoc javaClass, ExpressionBuilder builder) {
142         this();
143         this.defaultBuilder = builder;
144         setReferenceClass(javaClass);
145     }
146
147     /**
148      * PUBLIC:
149      * The report query is require to be constructor with an expression builder.
150      * This build must be used for the selection critiera, any item expressions, group bys and order bys.
151      */

152     public ReportQuery(ExpressionBuilder builder) {
153         this();
154         this.defaultBuilder = builder;
155     }
156
157     /**
158      * PUBLIC:
159      * Add the attribute from the reference class to be included in the result.
160      * EXAMPLE: reportQuery.addAttribute("firstName");
161      */

162     public void addAttribute(String JavaDoc itemName) {
163         addItem(itemName, getExpressionBuilder().get(itemName));
164     }
165
166     /**
167      * PUBLIC:
168      * Add the attribute to be included in the result.
169      * EXAMPLE: reportQuery.addAttribute("city", expBuilder.get("address").get("city"));
170      */

171     public void addAttribute(String JavaDoc itemName, Expression attributeExpression) {
172         addItem(itemName, attributeExpression);
173     }
174
175     /**
176      * PUBLIC:
177      * Add the attribute to be included in the result. Return the result as the provided class
178      * EXAMPLE: reportQuery.addAttribute("city", expBuilder.get("period").get("startTime"), Time.class);
179      */

180     public void addAttribute(String JavaDoc itemName, Expression attributeExpression, Class JavaDoc type) {
181         addItem(itemName, attributeExpression, type);
182     }
183
184     /**
185      * PUBLIC:
186      * Add the average value of the attribute to be included in the result.
187      * Aggregation functions can be used with a group by, or on the entire result set.
188      * EXAMPLE: reportQuery.addAverage("salary");
189      */

190     public void addAverage(String JavaDoc itemName) {
191         addAverage(itemName, getExpressionBuilder().get(itemName));
192     }
193     
194     /**
195      * PUBLIC:
196      * Add the average value of the attribute to be included in the result and
197      * return it as the specified resultType.
198      * Aggregation functions can be used with a group by, or on the entire result set.
199      * EXAMPLE: reportQuery.addAverage("salary", Float.class);
200      */

201     public void addAverage(String JavaDoc itemName, Class JavaDoc resultType) {
202         addAverage(itemName, getExpressionBuilder().get(itemName), resultType);
203     }
204
205     /**
206      * PUBLIC:
207      * Add the average value of the attribute to be included in the result.
208      * Aggregation functions can be used with a group by, or on the entire result set.
209      * EXAMPLE: reportQuery.addAverage("managerSalary", expBuilder.get("manager").get("salary"));
210      */

211     public void addAverage(String JavaDoc itemName, Expression attributeExpression) {
212         addItem(itemName, attributeExpression.average());
213     }
214     
215     /**
216      * PUBLIC:
217      * Add the average value of the attribute to be included in the result and
218      * return it as the specified resultType.
219      * Aggregation functions can be used with a group by, or on the entire result set.
220      * EXAMPLE: reportQuery.addAverage("managerSalary", expBuilder.get("manager").get("salary"), Double.class);
221      */

222     public void addAverage(String JavaDoc itemName, Expression attributeExpression, Class JavaDoc resultType) {
223         addItem(itemName, attributeExpression.average(), resultType);
224     }
225     
226     /**
227      * PUBLIC:
228      * Add a ConstructorReportItem to this query's set of return values.
229      * @param ConstructorReportItem - used to specify a class constructor and values to pass in from this query
230      * @see ConstructorReportItem
231      */

232     public void addConstructorReportItem(ConstructorReportItem item){
233         addItem(item);
234     }
235
236     /**
237      * PUBLIC:
238      * Include the number of rows returned by the query in the result.
239      * Aggregation functions can be used with a group by, or on the entire result set.
240      * EXAMPLE:
241      * Java:
242      * reportQuery.addCount();
243      * SQL:
244      * SELECT COUNT (*) FROM ...
245      * @see #addCount(java.lang.String)
246      */

247     public void addCount() {
248         addCount("COUNT", getExpressionBuilder());
249     }
250
251     /**
252      * PUBLIC:
253      * Include the number of rows returned by the query in the result, where attributeExpression is not null.
254      * Aggregation functions can be used with a group by, or on the entire result set.
255      * <p>Example:
256      * <pre><blockquote>
257      * TopLink: reportQuery.addCount("id");
258      * SQL: SELECT COUNT (t0.EMP_ID) FROM EMPLOYEE t0, ...
259      * </blockquote></pre>
260      * @param attributeName the number of rows where attributeName is not null will be returned.
261      * @see #addCount(java.lang.String, oracle.toplink.essentials.expressions.Expression)
262      */

263     public void addCount(String JavaDoc attributeName) {
264         addCount(attributeName, getExpressionBuilder().get(attributeName));
265     }
266     
267     /**
268      * PUBLIC:
269      * Include the number of rows returned by the query in the result, where attributeExpression is not null.
270      * Aggregation functions can be used with a group by, or on the entire result set.
271      * Set the count to be returned as the specified resultType.
272      * <p>Example:
273      * <pre><blockquote>
274      * TopLink: reportQuery.addCount("id", Long.class);
275      * SQL: SELECT COUNT (t0.EMP_ID) FROM EMPLOYEE t0, ...
276      * </blockquote></pre>
277      * @param attributeName the number of rows where attributeName is not null will be returned.
278      * @see #addCount(java.lang.String, oracle.toplink.essentials.expressions.Expression)
279      */

280     public void addCount(String JavaDoc attributeName, Class JavaDoc resultType) {
281         addCount(attributeName, getExpressionBuilder().get(attributeName), resultType);
282     }
283
284     /**
285      * PUBLIC:
286      * Include the number of rows returned by the query in the result, where attributeExpression
287      * is not null.
288      * Aggregation functions can be used with a group by, or on the entire result set.
289      * <p>Example:
290      * <pre><blockquote>
291      * TopLink: reportQuery.addCount("Count", getExpressionBuilder().get("id"));
292      * SQL: SELECT COUNT (t0.EMP_ID) FROM EMPLOYEE t0, ...
293      * </blockquote></pre>
294      * <p>Example: counting only distinct values of an attribute.
295      * <pre><blockquote>
296      * TopLink: reportQuery.addCount("Count", getExpressionBuilder().get("address").distinct());
297      * SQL: SELECT COUNT (DISTINCT t0.ADDR_ID) FROM EMPLOYEE t0, ...
298      * </blockquote></pre>
299      * objectAttributes can be specified also, even accross many to many
300      * mappings.
301      * @see #addCount()
302      */

303     public void addCount(String JavaDoc itemName, Expression attributeExpression) {
304         addItem(itemName, attributeExpression.count());
305     }
306     
307     /**
308      * PUBLIC:
309      * Include the number of rows returned by the query in the result, where attributeExpression
310      * is not null.
311      * Aggregation functions can be used with a group by, or on the entire result set.
312      * Set the count to be returned as the specified resultType.
313      * <p>Example:
314      * <pre><blockquote>
315      * TopLink: reportQuery.addCount("Count", getExpressionBuilder().get("id"), Integer.class);
316      * SQL: SELECT COUNT (t0.EMP_ID) FROM EMPLOYEE t0, ...
317      * </blockquote></pre>
318      * <p>Example: counting only distinct values of an attribute.
319      * <pre><blockquote>
320      * TopLink: reportQuery.addCount("Count", getExpressionBuilder().get("address").distinct());
321      * SQL: SELECT COUNT (DISTINCT t0.ADDR_ID) FROM EMPLOYEE t0, ...
322      * </blockquote></pre>
323      * objectAttributes can be specified also, even accross many to many
324      * mappings.
325      * @see #addCount()
326      */

327     public void addCount(String JavaDoc itemName, Expression attributeExpression, Class JavaDoc resultType) {
328         addItem(itemName, attributeExpression.count(), resultType);
329     }
330
331     /**
332      * ADVANCED:
333      * Add the function against the attribute expression to be included in the result.
334      * Aggregation functions can be used with a group by, or on the entire result set.
335      * Example: reportQuery.addFunctionItem("average", expBuilder.get("salary"), "average");
336      */

337     public void addFunctionItem(String JavaDoc itemName, Expression attributeExpression, String JavaDoc functionName) {
338         Expression functionExpression = attributeExpression;
339         functionExpression = attributeExpression.getFunction(functionName);
340
341         ReportItem item = new ReportItem(itemName, functionExpression);
342         addItem(item);
343
344     }
345
346     /**
347      * PUBLIC:
348      * Add the attribute to the group by expressions.
349      * This will group the result set on that attribute and is normally used in conjunction with aggregation functions.
350      * Example: reportQuery.addGrouping("lastName")
351      */

352     public void addGrouping(String JavaDoc attributeName) {
353         addGrouping(getExpressionBuilder().get(attributeName));
354     }
355
356     /**
357      * PUBLIC:
358      * Add the attribute expression to the group by expressions.
359      * This will group the result set on that attribute and is normally used in conjunction with aggregation functions.
360      * Example: reportQuery.addGrouping(expBuilder.get("address").get("country"))
361      */

362     public void addGrouping(Expression expression) {
363         getGroupByExpressions().addElement(expression);
364         //Bug2804042 Must un-prepare if prepared as the SQL may change.
365
setIsPrepared(false);
366     }
367     
368     /**
369      * PUBLIC:
370      * Add the expression to the query to be used in the HAVING clause.
371      * This epression will be used to filter the result sets after they are grouped. It must be used in conjunction with the GROUP BY clause.
372      * Example: reportQuery.setHavingExpression(expBuilder.get("address").get("country").equal("Canada"))
373      */

374     public void setHavingExpression(Expression expression) {
375         havingExpression = expression;
376         setIsPrepared(false);
377     }
378     
379     /**
380      * INTERNAL:
381      * Method used to abstract addToConstructorItem behavour from the public addItem methods
382      */

383     private void addItem(ReportItem item){
384         if (addToConstructorItem && (getItems().size()>0) &&(((ReportItem)getItems().lastElement()).isContructorItem() )){
385             ((ConstructorReportItem)getItems().lastElement()).addItem(item);
386         }else{
387             getItems().addElement(item);
388         }
389         //Bug2804042 Must un-prepare if prepared as the SQL may change.
390
setIsPrepared(false);
391     }
392
393     /**
394      * ADVANCED:
395      * Add the expression value to be included in the result.
396      * EXAMPLE: reportQuery.addItem("name", expBuilder.get("firstName").toUpperCase());
397      */

398     public void addItem(String JavaDoc itemName, Expression attributeExpression) {
399         ReportItem item = new ReportItem(itemName, attributeExpression);
400         addItem(item);
401     }
402     
403     /**
404      * ADVANCED:
405      * Add the expression value to be included in the result.
406      * EXAMPLE: reportQuery.addItem("name", expBuilder.get("firstName").toUpperCase());
407      */

408     public void addItem(String JavaDoc itemName, Expression attributeExpression, List joinedExpressions) {
409         ReportItem item = new ReportItem(itemName, attributeExpression);
410         item.getJoinedAttributeManager().setJoinedAttributeExpressions_(joinedExpressions);
411         addItem(item);
412     }
413     
414     /**
415      * INTERNAL:
416      * Add the expression value to be included in the result.
417      * EXAMPLE: reportQuery.addItem("name", expBuilder.get("firstName").toUpperCase());
418      * The resultType can be specified to support EJBQL that adheres to the
419      * EJB 3.0 spec.
420      */

421     protected void addItem(String JavaDoc itemName, Expression attributeExpression, Class JavaDoc resultType) {
422         ReportItem item = new ReportItem(itemName, attributeExpression);
423         item.setResultType(resultType);
424         addItem(item);
425     }
426
427     /**
428      * PUBLIC:
429      * Add the maximum value of the attribute to be included in the result.
430      * Aggregation functions can be used with a group by, or on the entire result set.
431      * EXAMPLE: reportQuery.addMaximum("salary");
432      */

433     public void addMaximum(String JavaDoc itemName) {
434         addMaximum(itemName, getExpressionBuilder().get(itemName));
435     }
436
437     /**
438      * PUBLIC:
439      * Add the maximum value of the attribute to be included in the result.
440      * Aggregation functions can be used with a group by, or on the entire result set.
441      * EXAMPLE: reportQuery.addMaximum("managerSalary", expBuilder.get("manager").get("salary"));
442      */

443     public void addMaximum(String JavaDoc itemName, Expression attributeExpression) {
444         addItem(itemName, attributeExpression.maximum());
445     }
446
447     /**
448      * PUBLIC:
449      * Add the minimum value of the attribute to be included in the result.
450      * Aggregation functions can be used with a group by, or on the entire result set.
451      * EXAMPLE: reportQuery.addMinimum("salary");
452      */

453     public void addMinimum(String JavaDoc itemName) {
454         addMinimum(itemName, getExpressionBuilder().get(itemName));
455     }
456
457     /**
458      * PUBLIC:
459      * Add the minimum value of the attribute to be included in the result.
460      * Aggregation functions can be used with a group by, or on the entire result set.
461      * EXAMPLE: reportQuery.addMinimum("managerSalary", expBuilder.get("manager").get("salary"));
462      */

463     public void addMinimum(String JavaDoc itemName, Expression attributeExpression) {
464         addItem(itemName, attributeExpression.minimum());
465     }
466
467     /**
468      * PUBLIC:
469      * Add the standard deviation value of the attribute to be included in the result.
470      * Aggregation functions can be used with a group by, or on the entire result set.
471      * EXAMPLE: reportQuery.addStandardDeviation("salary");
472      */

473     public void addStandardDeviation(String JavaDoc itemName) {
474         addStandardDeviation(itemName, getExpressionBuilder().get(itemName));
475     }
476
477     /**
478      * PUBLIC:
479      * Add the standard deviation value of the attribute to be included in the result.
480      * Aggregation functions can be used with a group by, or on the entire result set.
481      * EXAMPLE: reportQuery.addStandardDeviation("managerSalary", expBuilder.get("manager").get("salary"));
482      */

483     public void addStandardDeviation(String JavaDoc itemName, Expression attributeExpression) {
484         addItem(itemName, attributeExpression.standardDeviation());
485     }
486
487     /**
488      * PUBLIC:
489      * Add the sum value of the attribute to be included in the result.
490      * Aggregation functions can be used with a group by, or on the entire result set.
491      * EXAMPLE: reportQuery.addSum("salary");
492      */

493     public void addSum(String JavaDoc itemName) {
494         addSum(itemName, getExpressionBuilder().get(itemName));
495     }
496
497     /**
498      * PUBLIC:
499      * Add the sum value of the attribute to be included in the result and
500      * return it as the specified resultType.
501      * Aggregation functions can be used with a group by, or on the entire result set.
502      * EXAMPLE: reportQuery.addSum("salary", Float.class);
503      */

504     public void addSum(String JavaDoc itemName, Class JavaDoc resultType) {
505         addSum(itemName, getExpressionBuilder().get(itemName), resultType);
506     }
507
508     /**
509      * PUBLIC:
510      * Add the sum value of the attribute to be included in the result.
511      * Aggregation functions can be used with a group by, or on the entire result set.
512      * EXAMPLE: reportQuery.addSum("managerSalary", expBuilder.get("manager").get("salary"));
513      */

514     public void addSum(String JavaDoc itemName, Expression attributeExpression) {
515         addItem(itemName, attributeExpression.sum());
516     }
517
518     /**
519      * PUBLIC:
520      * Add the sum value of the attribute to be included in the result and
521      * return it as the specified resultType.
522      * Aggregation functions can be used with a group by, or on the entire result set.
523      * EXAMPLE: reportQuery.addSum("managerSalary", expBuilder.get("manager").get("salary"), Float.class);
524      */

525     public void addSum(String JavaDoc itemName, Expression attributeExpression, Class JavaDoc resultType) {
526         addItem(itemName, attributeExpression.sum(), resultType);
527     }
528
529     /**
530      * PUBLIC:
531      * Add the variance value of the attribute to be included in the result.
532      * Aggregation functions can be used with a group by, or on the entire result set.
533      * EXAMPLE: reportQuery.addVariance("salary");
534      */

535     public void addVariance(String JavaDoc itemName) {
536         addVariance(itemName, getExpressionBuilder().get(itemName));
537     }
538
539     /**
540      * PUBLIC:
541      * Add the variance value of the attribute to be included in the result.
542      * Aggregation functions can be used with a group by, or on the entire result set.
543      * EXAMPLE: reportQuery.addVariance("managerSalary", expBuilder.get("manager").get("salary"));
544      */

545     public void addVariance(String JavaDoc itemName, Expression attributeExpression) {
546         addItem(itemName, attributeExpression.variance());
547     }
548     
549     /**
550      * PUBLIC: Call a constructor for the given class with the results of this query.
551      * @param constructorClass
552      */

553     public ConstructorReportItem beginAddingConstructorArguments(Class JavaDoc constructorClass){
554         ConstructorReportItem citem = new ConstructorReportItem(constructorClass.getName());
555         citem.setResultType(constructorClass);
556         //add directly to avoid addToConstructorItem behaviour
557
getItems().add(citem);
558         //Bug2804042 Must un-prepare if prepared as the SQL may change.
559
setIsPrepared(false);
560         this.addToConstructorItem=true;
561         return citem;
562     }
563     /**
564      * PUBLIC: Call a constructor for the given class with the results of this query.
565      * @param constructorClass
566      * @param constructorArgTypes - sets the argument types to be passed to the constructor.
567      */

568     public ConstructorReportItem beginAddingConstructorArguments(Class JavaDoc constructorClass, Class JavaDoc[] constructorArgTypes){
569         ConstructorReportItem citem =beginAddingConstructorArguments(constructorClass);
570         citem.setConstructorArgTypes(constructorArgTypes);
571         return citem;
572     }
573
574     /**
575      * INTERNAL:
576      * Construct a result from a row. Either return a ReportQueryResult or just the attribute.
577      */

578     public Object JavaDoc buildObject(AbstractRecord row, Vector toManyJoinData) {
579         ReportQueryResult reportQueryResult = new ReportQueryResult(this, row, toManyJoinData);
580         //GF_ISSUE_395
581
if (this.returnedKeys != null){
582             if (this.returnedKeys.contains(reportQueryResult.getResultKey())){
583                 return RESULT_IGNORED; //distinguish between null values and thrown away duplicates
584
} else {
585                 this.returnedKeys.add(reportQueryResult.getResultKey());
586             }
587         }
588         //end GF_ISSUE_395
589
if (this.shouldReturnSingleAttribute()) {
590             return reportQueryResult.getResults().firstElement();
591         }
592         if (this.shouldReturnWithoutReportQueryResult()){
593             if (reportQueryResult.getResults().size() == 1){
594                 return reportQueryResult.getResults().firstElement();
595             }
596             return reportQueryResult.toArray();
597         }
598         return reportQueryResult;
599     }
600
601     /**
602      * INTERNAL:
603      * Construct a container of ReportQueryResult from the rows.
604      * If only one result or value was asked for only return that.
605      */

606     public Object JavaDoc buildObjects(Vector rows) {
607         if (shouldReturnSingleResult() || shouldReturnSingleValue()) {
608             if (rows.isEmpty()) {
609                 return null;
610             }
611             ReportQueryResult result = (ReportQueryResult)buildObject((AbstractRecord)rows.firstElement(), rows);
612             if (shouldReturnSingleValue()) {
613                 return result.elements().nextElement();
614             }
615             return result;
616         }
617
618         ContainerPolicy containerPolicy = getContainerPolicy();
619         Object JavaDoc reportResults = containerPolicy.containerInstance(rows.size());
620         // GF_ISSUE_395
621
if (shouldDistinctBeUsed()){
622             this.returnedKeys = new HashSet();
623         }
624         //end GF_ISSUE
625
//If only the attribute is desired, then buildObject will only get the first attribute each time
626
for (Enumeration rowsEnum = rows.elements(); rowsEnum.hasMoreElements();) {
627             // GF_ISSUE_395
628
Object JavaDoc result = buildObject((AbstractRecord)rowsEnum.nextElement(), rows);
629             if (result != RESULT_IGNORED){
630                 containerPolicy.addInto(result, reportResults, getSession());
631             }
632             //end GF_ISSUE
633
}
634         return reportResults;
635     }
636
637     /**
638      * INTERNAL:
639      * The cache check is done before the prepare as a hit will not require the work to be done.
640      */

641     protected Object JavaDoc checkEarlyReturnImpl(AbstractSession session, AbstractRecord translationRow) {
642         // Check for in-memory only query.
643
if (shouldCheckCacheOnly()) {
644             throw QueryException.cannotSetShouldCheckCacheOnlyOnReportQuery();
645         } else {
646             return null;
647         }
648     }
649     
650     /**
651      * INTERNAL: Required for a very special case of bug 2612185:
652      * ReportItems from parallelExpressions, on a ReportQuery which is a subQuery,
653      * which is being batch read.
654      * In a batch query the selection criteria is effectively cloned twice, meaning
655      * the ReportItems need to be cloned an extra time also to stay in sync.
656      * Each call to copiedVersionFrom() will take O(1) time as the expression was
657      * already cloned.
658      */

659     public void copyReportItems(Dictionary alreadyDone) {
660         items = (Vector)items.clone();
661         for (int i = items.size() - 1; i >= 0; i--) {
662             ReportItem item = (ReportItem)items.elementAt(i);
663             Expression expression = item.getAttributeExpression();
664             if ((expression != null) && (alreadyDone.get(expression.getBuilder()) != null)) {
665                 expression = expression.copiedVersionFrom(alreadyDone);
666             }
667             items.set(i, new ReportItem(item.getName(), expression));
668         }
669         if (groupByExpressions != null) {
670             groupByExpressions = (Vector)groupByExpressions.clone();
671             for (int i = groupByExpressions.size() - 1; i >= 0; i--) {
672                 Expression item = (Expression)groupByExpressions.elementAt(i);
673                 if (alreadyDone.get(item.getBuilder()) != null) {
674                     groupByExpressions.set(i, item.copiedVersionFrom(alreadyDone));
675                 }
676             }
677         }
678         if (orderByExpressions != null) {
679             for (int i = orderByExpressions.size() - 1; i >= 0; i--) {
680                 Expression item = (Expression)orderByExpressions.elementAt(i);
681                 if (alreadyDone.get(item.getBuilder()) != null) {
682                     orderByExpressions.set(i, item.copiedVersionFrom(alreadyDone));
683                 }
684             }
685         }
686     }
687
688     /**
689      * PUBLIC:
690      * Set if the query results should contain the primary keys or each associated object.
691      * This make retrieving the real object easier.
692      * By default they are not retrieved.
693      */

694     public void dontRetrievePrimaryKeys() {
695         setShouldRetrievePrimaryKeys(false);
696         //Bug2804042 Must un-prepare if prepared as the SQL may change.
697
setIsPrepared(false);
698     }
699
700     /**
701      * PUBLIC:
702      * Don't simplify the result by returning the single attribute. Wrap in a ReportQueryResult.
703      */

704     public void dontReturnSingleAttribute() {
705         if (shouldReturnSingleAttribute()) {
706             returnChoice = 0;
707         }
708     }
709
710     /**
711      * PUBLIC:
712      * Simplifies the result by only returning the first result.
713      * This can be used if it known that only one row is returned by the report query.
714      */

715     public void dontReturnSingleResult() {
716         if (shouldReturnSingleResult()) {
717             returnChoice = 0;
718         }
719     }
720
721     /**
722      * PUBLIC:
723      * Simplifies the result by only returning a single value.
724      * This can be used if it known that only one row is returned by the report query and only a single item is added
725      * to the report.
726      */

727     public void dontReturnSingleValue() {
728         if (shouldReturnSingleValue()) {
729             returnChoice = 0;
730         }
731     }
732
733     /**
734      * PUBLIC:
735      * Simplifies the result by only returning a single value.
736      * This can be used if it known that only one row is returned by the report query and only a single item is added
737      * to the report.
738      */

739     public void dontReturnWithoutReportQueryResult() {
740         if (shouldReturnWithoutReportQueryResult()) {
741             returnChoice = 0;
742         }
743     }
744     
745     /**
746      * PUBLIC:
747      * Used in conjunction with beginAddingConstructorArguments to signal that expressions should no longer be
748      * be added to the collection used in the constructor
749      *
750      * Get the rows and build the object from the rows.
751      * @exception DatabaseException - an error has occurred on the database
752      * @return Vector - collection of objects resulting from execution of query.
753      */

754     public void endAddingToConstructorItem(){
755         this.addToConstructorItem=false;
756     }
757
758     /**
759      * INTERNAL:
760      * Execute the query.
761      * Get the rows and build the object from the rows.
762      * @exception DatabaseException - an error has occurred on the database
763      * @return Vector - collection of objects resulting from execution of query.
764      */

765     public Object JavaDoc executeDatabaseQuery() throws DatabaseException {
766         if (getContainerPolicy().overridesRead()) {
767             return getContainerPolicy().execute();
768         }
769
770         if (getQueryId() == 0) {
771             setQueryId(getSession().getNextQueryId());
772         }
773
774         Vector rows = getQueryMechanism().selectAllReportQueryRows();
775         // If using -m joins, must set all rows.
776
return buildObjects(rows);
777     }
778
779     /**
780      * INTERNAL:
781      * Return the group bys.
782      */

783     public Vector getGroupByExpressions() {
784         return groupByExpressions;
785     }
786     
787     /**
788      * INTERNAL:
789      * Return the Having expression.
790      */

791     public Expression getHavingExpression() {
792         return havingExpression;
793     }
794
795     /**
796      * INTERNAL:
797      * return a collection of expressions if PK's are used.
798      */

799     public Vector getQueryExpressions() {
800         Vector fieldExpressions = new Vector(getItems().size());
801
802         // For bug 3115576 and an EXISTS subquery only need to return a single field.
803
if (shouldRetrieveFirstPrimaryKey()) {
804             if (!getDescriptor().getPrimaryKeyFields().isEmpty()) {
805                 fieldExpressions.addElement(getDescriptor().getPrimaryKeyFields().get(0));
806             }
807         }
808         if (shouldRetrievePrimaryKeys()) {
809             fieldExpressions.addAll(getDescriptor().getPrimaryKeyFields());
810         }
811
812         return fieldExpressions;
813     }
814
815     /**
816      * INTERNAL:
817      * return a collection of expressions from the items. Ignore the null (place holders).
818      */

819     public Vector getItemExpressions() {
820         Vector fieldExpressions = new Vector(getItems().size());
821
822         // For bug 3115576 and an EXISTS subquery only need to return a single field.
823
if (shouldRetrieveFirstPrimaryKey()) {
824             if (!getDescriptor().getPrimaryKeyFields().isEmpty()) {
825                 fieldExpressions.addElement(getDescriptor().getPrimaryKeyFields().get(0));
826             }
827         }
828         if (shouldRetrievePrimaryKeys()) {
829             fieldExpressions.addAll(getDescriptor().getPrimaryKeyFields());
830         }
831
832         for (Enumeration itemsEnum = getItems().elements(); itemsEnum.hasMoreElements();) {
833             ReportItem item = (ReportItem)itemsEnum.nextElement();
834             Expression fieldExpression = item.getAttributeExpression();
835             if (fieldExpression != null) {
836                 fieldExpressions.addElement(fieldExpression);
837             }
838         }
839         return fieldExpressions;
840     }
841
842     /**
843      * INTERNAL:
844      * @return ReportQueryItems defining the attributes to be read
845      */

846     public Vector getItems() {
847         return items;
848     }
849
850     /**
851      * INTERNAL:
852      * Clear the ReportQueryItems
853      */

854     public void clearItems() {
855         items = new Vector();
856         setIsPrepared(false);
857     }
858
859     /**
860      * INTERNAL:
861      * Lazily initialize and return the names of the items requested for use in each result object
862      */

863     public Vector getNames() {
864         if (names == null) {
865             names = new Vector();
866             for (Enumeration e = getItems().elements(); e.hasMoreElements();) {
867                 names.addElement(((ReportItem)e.nextElement()).getName());
868             }
869         }
870         return names;
871     }
872
873     /**
874      * PUBLIC:
875      * Return if this is a report query.
876      */

877     public boolean isReportQuery() {
878         return true;
879     }
880
881     /**
882      * INTERNAL:
883      * Prepare the receiver for execution in a session.
884      * Initialize each item with its DTF mapping
885      */

886     protected void prepare() throws QueryException {
887         // Oct 19, 2000 JED
888
// Added exception to be thrown if no attributes have been added to the query
889
if (getItems().size() > 0) {
890             try {
891                 for (Enumeration itemsEnum = getItems().elements(); itemsEnum.hasMoreElements();) {
892                     ((ReportItem)itemsEnum.nextElement()).initialize(this);
893                 }
894             } catch (QueryException exception) {
895                 exception.setQuery(this);
896                 throw exception;
897             }
898         } else {
899             if ((!shouldRetrievePrimaryKeys()) && (!shouldRetrieveFirstPrimaryKey())) {
900                 throw QueryException.noAttributesForReportQuery(this);
901             }
902         }
903
904         super.prepare();
905
906     }
907
908     /**
909      * INTERNAL:
910      * Prepare a report query with a count defined on an object attribute.
911      * Added to fix bug 3268040, addCount(objectAttribute) not supported.
912      */

913     protected void prepareObjectAttributeCount(Dictionary clonedExpressions) {
914         int numOfReportItems = getItems().size();
915         //gf675: need to loop through all items to fix all count(..) instances
916
for (int i =0;i<numOfReportItems; i++){
917             ReportItem countItem = (ReportItem)getItems().elementAt(i);
918             if ((countItem != null) && (countItem.getAttributeExpression() instanceof FunctionExpression)) {
919                 FunctionExpression count = (FunctionExpression)countItem.getAttributeExpression();
920                 if (count.getOperator().getSelector() == ExpressionOperator.Count) {
921                     Expression baseExp = count.getBaseExpression();
922                     boolean distinctUsed = false;
923                     if (baseExp.isFunctionExpression() && (((FunctionExpression)baseExp).getOperator().getSelector() == ExpressionOperator.Distinct)) {
924                         distinctUsed = true;
925                         baseExp = ((FunctionExpression)baseExp).getBaseExpression();
926                     }
927                     if (baseExp.isQueryKeyExpression()) {
928                         QueryKeyExpression countExp = (QueryKeyExpression)baseExp;
929     
930                         // now need to find out if it is a direct to field or something else.
931
DatabaseMapping mapping = getLeafMappingFor(countExp, getDescriptor());
932                         if ((mapping != null) && !mapping.isDirectToFieldMapping() && (mapping.getReferenceDescriptor() != null)) {
933                             // At this point we are committed to rewriting the query.
934
ClassDescriptor newDescriptor = mapping.getReferenceDescriptor();
935                             if (distinctUsed) {
936                                 // If this is a subselect countExp is yet uncloned,
937
// and will miss out if moved now from items into a selection criteria.
938
if (clonedExpressions != null) {
939                                     if (clonedExpressions.get(countExp.getBuilder()) != null) {
940                                         countExp = (QueryKeyExpression)countExp.copiedVersionFrom(clonedExpressions);
941                                     } else {
942                                         countExp = (QueryKeyExpression)countExp.rebuildOn(getExpressionBuilder());
943                                     }
944                                 }
945     
946                                 // Now the reference class of the query needs to be reversed.
947
// See the bug description for an explanation.
948
ExpressionBuilder countBuilder = countExp.getBuilder();
949                                 ExpressionBuilder outerBuilder = new ExpressionBuilder();
950     
951                                 ReportQuery subSelect = new ReportQuery(getReferenceClass(), countBuilder);
952                                 subSelect.setShouldRetrieveFirstPrimaryKey(true);
953     
954                                 // Make sure the outerBuilder does not appear on the left of the subselect.
955
// Putting a builder on the left is desirable to trigger an optimization.
956
if (getSelectionCriteria() != null) {
957                                     outerBuilder.setQueryClass(newDescriptor.getJavaClass());
958                                     subSelect.setSelectionCriteria(getSelectionCriteria().and(outerBuilder.equal(countExp)));
959                                 } else {
960                                     subSelect.setSelectionCriteria(countExp.equal(outerBuilder));
961                                 }
962                                 setSelectionCriteria(outerBuilder.exists(subSelect));
963                                 count.setBaseExpression(outerBuilder);
964                                 count.getChildren().setElementAt( outerBuilder, 0);
965                                 setReferenceClass(newDescriptor.getJavaClass());
966                                 changeDescriptor(getSession());
967                             } else {
968                                 // Here everything worked fine, save an empty COUNT() was being generated.
969
Expression newCountEx = countExp.prefixSQL("*");
970                                 // modify the original count expression incase it is used elsewhere - such as in a having clause
971
count.setBaseExpression(newCountEx);
972                                 count.getChildren().setElementAt( newCountEx, 0);
973                             }
974                         }
975                     }
976                 }
977             }
978         }
979     }
980
981     /**
982      * INTERNAL:
983      * Prepare the mechanism.
984      */

985     protected void prepareSelectAllRows() {
986         prepareObjectAttributeCount(null);
987
988         getQueryMechanism().prepareReportQuerySelectAllRows();
989     }
990
991     /**
992      * INTERNAL:
993      * Prepare the receiver for being printed inside a subselect.
994      * This prepares the statement but not the call.
995      */

996     public synchronized void prepareSubSelect(AbstractSession session, AbstractRecord translationRow, Dictionary clonedExpressions) throws QueryException {
997         if (isPrepared()) {
998             return;
999         }
1000
1001        setIsPrepared(true);
1002        setSession(session);
1003        setTranslationRow(translationRow);
1004
1005        checkDescriptor(getSession());
1006
1007        if (descriptor.isAggregateDescriptor()) {
1008            // Not allowed
1009
throw QueryException.aggregateObjectCannotBeDeletedOrWritten(descriptor, this);
1010        }
1011
1012        try {
1013            for (Enumeration itemsEnum = getItems().elements(); itemsEnum.hasMoreElements();) {
1014                ((ReportItem)itemsEnum.nextElement()).initialize(this);
1015            }
1016        } catch (QueryException exception) {
1017            exception.setQuery(this);
1018            throw exception;
1019        }
1020
1021        prepareObjectAttributeCount(clonedExpressions);
1022
1023        getQueryMechanism().prepareReportQuerySubSelect();
1024
1025        setSession(null);
1026        setTranslationRow(null);
1027    }
1028
1029    /**
1030     * PUBLIC:
1031     * Set if the query results should contain the primary keys or each associated object.
1032     * This make retrieving the real object easier.
1033     * By default they are not retrieved.
1034     */

1035    public void retrievePrimaryKeys() {
1036        setShouldRetrievePrimaryKeys(true);
1037        //Bug2804042 Must un-prepare if prepared as the SQL may change.
1038
setIsPrepared(false);
1039    }
1040
1041    /**
1042     * PUBLIC:
1043     * Simplify the result by returning a single attribute. Don't wrap in a ReportQueryResult.
1044     */

1045    public void returnSingleAttribute() {
1046        returnChoice = ShouldReturnSingleAttribute;
1047    }
1048
1049    /**
1050     * PUBLIC:
1051     * Simplifies the result by only returning the first result.
1052     * This can be used if it known that only one row is returned by the report query.
1053     */

1054    public void returnSingleResult() {
1055        returnChoice = ShouldReturnSingleResult;
1056    }
1057
1058    /**
1059     * PUBLIC:
1060     * Simplifies the result by only returning a single value.
1061     * This can be used if it known that only one row is returned by the report query and only a single item is added
1062     * to the report.
1063     */

1064    public void returnSingleValue() {
1065        returnChoice = ShouldReturnSingleValue;
1066    }
1067
1068    /**
1069     * PUBLIC:
1070     * Simplifies the result by only returning a single value.
1071     * This can be used if it known that only one row is returned by the report query and only a single item is added
1072     * to the report.
1073     */

1074    public void returnWithoutReportQueryResult() {
1075        this.returnChoice = ShouldReturnWithoutReportQueryResult;
1076    }
1077
1078    /**
1079     * PUBLIC:
1080     * Set if the query results should contain the primary keys or each associated object.
1081     * This make retrieving the real object easier.
1082     * By default they are not retrieved.
1083     */

1084    public void setShouldRetrievePrimaryKeys(boolean shouldRetrievePrimaryKeys) {
1085        this.shouldRetrievePrimaryKeys = (shouldRetrievePrimaryKeys ? FULL_PRIMARY_KEY : NO_PRIMARY_KEY);
1086    }
1087
1088    /**
1089     * ADVANCED:
1090     * Sets if the query results should contain the first primary key of each associated object.
1091     * Usefull if this is an EXISTS subquery and you don't care what fields are returned
1092     * so long as it is a single field.
1093     * The default value is false.
1094     * This should only be used with a subquery.
1095     */

1096    public void setShouldRetrieveFirstPrimaryKey(boolean shouldRetrieveFirstPrimaryKey) {
1097        this.shouldRetrievePrimaryKeys = (shouldRetrieveFirstPrimaryKey ? FIRST_PRIMARY_KEY : NO_PRIMARY_KEY);
1098    }
1099
1100    /**
1101     * PUBLIC:
1102     * Simplifies the result by only returning the attribute (as opposed to wrapping in a ReportQueryResult).
1103     * This can be used if it is known that only one attribute is returned by the report query.
1104     */

1105    public void setShouldReturnSingleAttribute(boolean newChoice) {
1106        if (newChoice) {
1107            returnSingleAttribute();
1108        } else {
1109            dontReturnSingleAttribute();
1110        }
1111    }
1112
1113    /**
1114     * PUBLIC:
1115     * Simplifies the result by only returning the first result.
1116     * This can be used if it known that only one row is returned by the report query.
1117     */

1118    public void setShouldReturnSingleResult(boolean newChoice) {
1119        if (newChoice) {
1120            returnSingleResult();
1121        } else {
1122            dontReturnSingleResult();
1123        }
1124    }
1125
1126    /**
1127     * PUBLIC:
1128     * Simplifies the result by only returning a single value.
1129     * This can be used if it known that only one row is returned by the report query and only a single item is added
1130     * to the report.
1131     */

1132    public void setShouldReturnSingleValue(boolean newChoice) {
1133        if (newChoice) {
1134            returnSingleValue();
1135        } else {
1136            dontReturnSingleValue();
1137        }
1138    }
1139
1140    /**
1141     * PUBLIC:
1142     * Simplifies the result by returning a nested list instead of the ReportQueryResult.
1143     * This is used by EJB 3.
1144     */

1145    public void setShouldReturnWithoutReportQueryResult(boolean newChoice) {
1146        if (newChoice) {
1147            returnWithoutReportQueryResult();
1148        } else {
1149            dontReturnWithoutReportQueryResult();
1150        }
1151    }
1152
1153    /**
1154     * PUBLIC:
1155     * Return if the query results should contain the primary keys or each associated object.
1156     * This make retrieving the real object easier.
1157     */

1158    public boolean shouldRetrievePrimaryKeys() {
1159        return (shouldRetrievePrimaryKeys == FULL_PRIMARY_KEY);
1160    }
1161
1162    /**
1163     * PUBLIC:
1164     * Return if the query results should contain the first primary key of each associated object.
1165     * Usefull if this is an EXISTS subquery and you don't care what fields are returned
1166     * so long as it is a single field.
1167     */

1168    public boolean shouldRetrieveFirstPrimaryKey() {
1169        return (shouldRetrievePrimaryKeys == FIRST_PRIMARY_KEY);
1170    }
1171
1172    /**
1173     * PUBLIC:
1174     * Answer if we are only returning the attribute (as opposed to wrapping in a ReportQueryResult).
1175     * This can be used if it is known that only one attribute is returned by the report query.
1176     */

1177    public boolean shouldReturnSingleAttribute() {
1178        return returnChoice == ShouldReturnSingleAttribute;
1179    }
1180
1181    /**
1182     * PUBLIC:
1183     * Simplifies the result by only returning the first result.
1184     * This can be used if it known that only one row is returned by the report query.
1185     */

1186    public boolean shouldReturnSingleResult() {
1187        return returnChoice == ShouldReturnSingleResult;
1188    }
1189
1190    /**
1191     * PUBLIC:
1192     * Simplifies the result by only returning a single value.
1193     * This can be used if it known that only one row is returned by the report query and only a single item is added
1194     * to the report.
1195     */

1196    public boolean shouldReturnSingleValue() {
1197        return returnChoice == ShouldReturnSingleValue;
1198    }
1199
1200    /**
1201     * PUBLIC:
1202     * Simplifies the result by returning a nested list instead of the ReportQueryResult.
1203     * This is used by EJB 3.
1204     */

1205    public boolean shouldReturnWithoutReportQueryResult() {
1206        return returnChoice == ShouldReturnWithoutReportQueryResult;
1207    }
1208
1209
1210}
1211
Popular Tags