0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * // Copyright (c) 1998, 2007, Oracle. All rights reserved.
0005: *
0006: *
0007: * The contents of this file are subject to the terms of either the GNU
0008: * General Public License Version 2 only ("GPL") or the Common Development
0009: * and Distribution License("CDDL") (collectively, the "License"). You
0010: * may not use this file except in compliance with the License. You can obtain
0011: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
0012: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
0013: * language governing permissions and limitations under the License.
0014: *
0015: * When distributing the software, include this License Header Notice in each
0016: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
0017: * Sun designates this particular file as subject to the "Classpath" exception
0018: * as provided by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the License
0020: * Header, with the fields enclosed by brackets [] replaced by your own
0021: * identifying information: "Portions Copyrighted [year]
0022: * [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * If you wish your version of this file to be governed by only the CDDL or
0027: * only the GPL Version 2, indicate your decision by adding "[Contributor]
0028: * elects to include this software in this distribution under the [CDDL or GPL
0029: * Version 2] license." If you don't indicate a single choice of license, a
0030: * recipient has the option to distribute your version of this file under
0031: * either the CDDL, the GPL Version 2 or to extend the choice of license to
0032: * its licensees as provided above. However, if you add GPL Version 2 code
0033: * and therefore, elected the GPL Version 2 license, then the option applies
0034: * only if the new code is made subject to such option by the copyright
0035: * holder.
0036: */
0037: package oracle.toplink.essentials.queryframework;
0038:
0039: import java.util.*;
0040: import oracle.toplink.essentials.expressions.*;
0041: import oracle.toplink.essentials.internal.expressions.*;
0042: import oracle.toplink.essentials.internal.queryframework.*;
0043: import oracle.toplink.essentials.exceptions.*;
0044: import oracle.toplink.essentials.internal.helper.*;
0045: import oracle.toplink.essentials.mappings.*;
0046: import oracle.toplink.essentials.internal.security.PrivilegedAccessHelper;
0047: import oracle.toplink.essentials.internal.sessions.AbstractRecord;
0048: import oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl;
0049: import oracle.toplink.essentials.internal.sessions.AbstractSession;
0050: import oracle.toplink.essentials.descriptors.ClassDescriptor;
0051:
0052: /**
0053: * <b>Purpose</b>: Query for information about a set of objects instead of the objects themselves.
0054: * This supports select single attributes, nested attributes, aggregation functions and group bys.<p>
0055: *
0056: * <b>Attribute Types</b>:<ol>
0057: * <li>addAttribute("directQueryKey") is a short cut method to add an attribute with the same name as its corresponding direct query key.
0058: * <li>addAttribute("attributeName", expBuilder.get("oneToOneMapping").get("directQueryKey")) is the full approach for get values through joined 1:1 relationships.
0059: * <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).
0060: * <li>addAttribute("attributeName", null) Leave a place holder (NULL) value in the result (used for included values from other systems or calculated values).
0061: * </ol>
0062: * <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
0063: * primary key vector can later be used to retrieve the real object.
0064: * @see #retrievePrimaryKeys()
0065: * @see ReportQueryResult#readObject(Class, Session)
0066: * If the values are wanted in the result array then they must be added as attributes. For primary keys which are not mapped directly
0067: * you can add them as DatabaseFields (see above).
0068: *
0069: * @author Doug Clarke
0070: * @since TOPLink/Java 2.0
0071: */
0072: public class ReportQuery extends ReadAllQuery {
0073:
0074: /** Simplifies the result by only returning the first result. */
0075: public static final int ShouldReturnSingleResult = 1;
0076:
0077: /** Simplifies the result by only returning one value. */
0078: public static final int ShouldReturnSingleValue = 2;
0079:
0080: /** Simplifies the result by only returning the single attribute(as opposed to wrapping in a
0081: ReportQueryResult). */
0082: public static final int ShouldReturnSingleAttribute = 3;
0083:
0084: /** For EJB 3 support returns results without using the ReportQueryResult */
0085: public static final int ShouldReturnWithoutReportQueryResult = 4;
0086:
0087: /** Specifies whether to retreive primary keys, first primary key, or no primary key.*/
0088: public static final int FULL_PRIMARY_KEY = 2;
0089: public static final int FIRST_PRIMARY_KEY = 1;
0090: public static final int NO_PRIMARY_KEY = 0;
0091:
0092: //GF_ISSUE_395
0093: protected static final Boolean RESULT_IGNORED = Boolean
0094: .valueOf(true);
0095: //end GF_ISSUE
0096:
0097: /** Flag indicating wether the primary key values should also be retrieved for the reference class. */
0098: protected int shouldRetrievePrimaryKeys;
0099:
0100: /** Collection of names for use by results. */
0101: protected Vector names;
0102:
0103: /** Items to be selected, these could be attributes or aggregate functions. */
0104: protected Vector items;
0105:
0106: /** Expressions representing fields to be used in the GROUP BY clause. */
0107: protected Vector groupByExpressions;
0108:
0109: /** Expression representing the HAVING clause. */
0110: protected Expression havingExpression;
0111:
0112: /** Can be one of (ShouldReturnSingleResult, ShouldReturnSingleValue, ShouldReturnSingleAttribute)
0113: ** Simplifies the result by only returning the first result, first value, or all attribute values
0114: */
0115: protected int returnChoice;
0116:
0117: /** flag to allow items to be added to the last ConstructorReportItem **/
0118: protected boolean addToConstructorItem;
0119: protected Class resultConstructorClass;
0120: protected Class[] constructorArgTypes;
0121: protected List constructorMappings;
0122:
0123: /* GF_ISSUE_395 this attribute stores a set of unique keys that identity results.
0124: * Used when distinct has been set on the query. For use in TCK
0125: */
0126: protected HashSet returnedKeys;
0127:
0128: /**
0129: * INTERNAL:
0130: * The builder should be provided.
0131: */
0132: public ReportQuery() {
0133: this .queryMechanism = new ExpressionQueryMechanism(this );
0134: this .items = new Vector();
0135: this .shouldRetrievePrimaryKeys = NO_PRIMARY_KEY;
0136: this .groupByExpressions = new Vector(3);
0137: this .havingExpression = null;
0138: this .addToConstructorItem = false;
0139:
0140: // overwrite the lock mode to NO_LOCK, this prevents the report query to lock
0141: // when DEFAULT_LOCK_MODE and a pessimistic locking policy are used.
0142: this .setLockMode(ObjectBuildingQuery.NO_LOCK);
0143: }
0144:
0145: public ReportQuery(Class javaClass, Expression expression) {
0146: this ();
0147: this .defaultBuilder = expression.getBuilder();
0148: setReferenceClass(javaClass);
0149: setSelectionCriteria(expression);
0150: }
0151:
0152: /**
0153: * PUBLIC:
0154: * The report query is require to be constructor with an expression builder.
0155: * This build must be used for the selection critiera, any item expressions, group bys and order bys.
0156: */
0157: public ReportQuery(Class javaClass, ExpressionBuilder builder) {
0158: this ();
0159: this .defaultBuilder = builder;
0160: setReferenceClass(javaClass);
0161: }
0162:
0163: /**
0164: * PUBLIC:
0165: * The report query is require to be constructor with an expression builder.
0166: * This build must be used for the selection critiera, any item expressions, group bys and order bys.
0167: */
0168: public ReportQuery(ExpressionBuilder builder) {
0169: this ();
0170: this .defaultBuilder = builder;
0171: }
0172:
0173: /**
0174: * PUBLIC:
0175: * Add the attribute from the reference class to be included in the result.
0176: * EXAMPLE: reportQuery.addAttribute("firstName");
0177: */
0178: public void addAttribute(String itemName) {
0179: addItem(itemName, getExpressionBuilder().get(itemName));
0180: }
0181:
0182: /**
0183: * PUBLIC:
0184: * Add the attribute to be included in the result.
0185: * EXAMPLE: reportQuery.addAttribute("city", expBuilder.get("address").get("city"));
0186: */
0187: public void addAttribute(String itemName,
0188: Expression attributeExpression) {
0189: addItem(itemName, attributeExpression);
0190: }
0191:
0192: /**
0193: * PUBLIC:
0194: * Add the attribute to be included in the result. Return the result as the provided class
0195: * EXAMPLE: reportQuery.addAttribute("city", expBuilder.get("period").get("startTime"), Time.class);
0196: */
0197: public void addAttribute(String itemName,
0198: Expression attributeExpression, Class type) {
0199: addItem(itemName, attributeExpression, type);
0200: }
0201:
0202: /**
0203: * PUBLIC:
0204: * Add the average value of the attribute to be included in the result.
0205: * Aggregation functions can be used with a group by, or on the entire result set.
0206: * EXAMPLE: reportQuery.addAverage("salary");
0207: */
0208: public void addAverage(String itemName) {
0209: addAverage(itemName, getExpressionBuilder().get(itemName));
0210: }
0211:
0212: /**
0213: * PUBLIC:
0214: * Add the average value of the attribute to be included in the result and
0215: * return it as the specified resultType.
0216: * Aggregation functions can be used with a group by, or on the entire result set.
0217: * EXAMPLE: reportQuery.addAverage("salary", Float.class);
0218: */
0219: public void addAverage(String itemName, Class resultType) {
0220: addAverage(itemName, getExpressionBuilder().get(itemName),
0221: resultType);
0222: }
0223:
0224: /**
0225: * PUBLIC:
0226: * Add the average value of the attribute to be included in the result.
0227: * Aggregation functions can be used with a group by, or on the entire result set.
0228: * EXAMPLE: reportQuery.addAverage("managerSalary", expBuilder.get("manager").get("salary"));
0229: */
0230: public void addAverage(String itemName,
0231: Expression attributeExpression) {
0232: addItem(itemName, attributeExpression.average());
0233: }
0234:
0235: /**
0236: * PUBLIC:
0237: * Add the average value of the attribute to be included in the result and
0238: * return it as the specified resultType.
0239: * Aggregation functions can be used with a group by, or on the entire result set.
0240: * EXAMPLE: reportQuery.addAverage("managerSalary", expBuilder.get("manager").get("salary"), Double.class);
0241: */
0242: public void addAverage(String itemName,
0243: Expression attributeExpression, Class resultType) {
0244: addItem(itemName, attributeExpression.average(), resultType);
0245: }
0246:
0247: /**
0248: * PUBLIC:
0249: * Add a ConstructorReportItem to this query's set of return values.
0250: * @param ConstructorReportItem - used to specify a class constructor and values to pass in from this query
0251: * @see ConstructorReportItem
0252: */
0253: public void addConstructorReportItem(ConstructorReportItem item) {
0254: addItem(item);
0255: }
0256:
0257: /**
0258: * PUBLIC:
0259: * Include the number of rows returned by the query in the result.
0260: * Aggregation functions can be used with a group by, or on the entire result set.
0261: * EXAMPLE:
0262: * Java:
0263: * reportQuery.addCount();
0264: * SQL:
0265: * SELECT COUNT (*) FROM ...
0266: * @see #addCount(java.lang.String)
0267: */
0268: public void addCount() {
0269: addCount("COUNT", getExpressionBuilder());
0270: }
0271:
0272: /**
0273: * PUBLIC:
0274: * Include the number of rows returned by the query in the result, where attributeExpression is not null.
0275: * Aggregation functions can be used with a group by, or on the entire result set.
0276: * <p>Example:
0277: * <pre><blockquote>
0278: * TopLink: reportQuery.addCount("id");
0279: * SQL: SELECT COUNT (t0.EMP_ID) FROM EMPLOYEE t0, ...
0280: * </blockquote></pre>
0281: * @param attributeName the number of rows where attributeName is not null will be returned.
0282: * @see #addCount(java.lang.String, oracle.toplink.essentials.expressions.Expression)
0283: */
0284: public void addCount(String attributeName) {
0285: addCount(attributeName, getExpressionBuilder().get(
0286: attributeName));
0287: }
0288:
0289: /**
0290: * PUBLIC:
0291: * Include the number of rows returned by the query in the result, where attributeExpression is not null.
0292: * Aggregation functions can be used with a group by, or on the entire result set.
0293: * Set the count to be returned as the specified resultType.
0294: * <p>Example:
0295: * <pre><blockquote>
0296: * TopLink: reportQuery.addCount("id", Long.class);
0297: * SQL: SELECT COUNT (t0.EMP_ID) FROM EMPLOYEE t0, ...
0298: * </blockquote></pre>
0299: * @param attributeName the number of rows where attributeName is not null will be returned.
0300: * @see #addCount(java.lang.String, oracle.toplink.essentials.expressions.Expression)
0301: */
0302: public void addCount(String attributeName, Class resultType) {
0303: addCount(attributeName, getExpressionBuilder().get(
0304: attributeName), resultType);
0305: }
0306:
0307: /**
0308: * PUBLIC:
0309: * Include the number of rows returned by the query in the result, where attributeExpression
0310: * is not null.
0311: * Aggregation functions can be used with a group by, or on the entire result set.
0312: * <p>Example:
0313: * <pre><blockquote>
0314: * TopLink: reportQuery.addCount("Count", getExpressionBuilder().get("id"));
0315: * SQL: SELECT COUNT (t0.EMP_ID) FROM EMPLOYEE t0, ...
0316: * </blockquote></pre>
0317: * <p>Example: counting only distinct values of an attribute.
0318: * <pre><blockquote>
0319: * TopLink: reportQuery.addCount("Count", getExpressionBuilder().get("address").distinct());
0320: * SQL: SELECT COUNT (DISTINCT t0.ADDR_ID) FROM EMPLOYEE t0, ...
0321: * </blockquote></pre>
0322: * objectAttributes can be specified also, even accross many to many
0323: * mappings.
0324: * @see #addCount()
0325: */
0326: public void addCount(String itemName, Expression attributeExpression) {
0327: addItem(itemName, attributeExpression.count());
0328: }
0329:
0330: /**
0331: * PUBLIC:
0332: * Include the number of rows returned by the query in the result, where attributeExpression
0333: * is not null.
0334: * Aggregation functions can be used with a group by, or on the entire result set.
0335: * Set the count to be returned as the specified resultType.
0336: * <p>Example:
0337: * <pre><blockquote>
0338: * TopLink: reportQuery.addCount("Count", getExpressionBuilder().get("id"), Integer.class);
0339: * SQL: SELECT COUNT (t0.EMP_ID) FROM EMPLOYEE t0, ...
0340: * </blockquote></pre>
0341: * <p>Example: counting only distinct values of an attribute.
0342: * <pre><blockquote>
0343: * TopLink: reportQuery.addCount("Count", getExpressionBuilder().get("address").distinct());
0344: * SQL: SELECT COUNT (DISTINCT t0.ADDR_ID) FROM EMPLOYEE t0, ...
0345: * </blockquote></pre>
0346: * objectAttributes can be specified also, even accross many to many
0347: * mappings.
0348: * @see #addCount()
0349: */
0350: public void addCount(String itemName,
0351: Expression attributeExpression, Class resultType) {
0352: addItem(itemName, attributeExpression.count(), resultType);
0353: }
0354:
0355: /**
0356: * ADVANCED:
0357: * Add the function against the attribute expression to be included in the result.
0358: * Aggregation functions can be used with a group by, or on the entire result set.
0359: * Example: reportQuery.addFunctionItem("average", expBuilder.get("salary"), "average");
0360: */
0361: public void addFunctionItem(String itemName,
0362: Expression attributeExpression, String functionName) {
0363: Expression functionExpression = attributeExpression;
0364: functionExpression = attributeExpression
0365: .getFunction(functionName);
0366:
0367: ReportItem item = new ReportItem(itemName, functionExpression);
0368: addItem(item);
0369:
0370: }
0371:
0372: /**
0373: * PUBLIC:
0374: * Add the attribute to the group by expressions.
0375: * This will group the result set on that attribute and is normally used in conjunction with aggregation functions.
0376: * Example: reportQuery.addGrouping("lastName")
0377: */
0378: public void addGrouping(String attributeName) {
0379: addGrouping(getExpressionBuilder().get(attributeName));
0380: }
0381:
0382: /**
0383: * PUBLIC:
0384: * Add the attribute expression to the group by expressions.
0385: * This will group the result set on that attribute and is normally used in conjunction with aggregation functions.
0386: * Example: reportQuery.addGrouping(expBuilder.get("address").get("country"))
0387: */
0388: public void addGrouping(Expression expression) {
0389: getGroupByExpressions().addElement(expression);
0390: //Bug2804042 Must un-prepare if prepared as the SQL may change.
0391: setIsPrepared(false);
0392: }
0393:
0394: /**
0395: * PUBLIC:
0396: * Add the expression to the query to be used in the HAVING clause.
0397: * 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.
0398: * Example: reportQuery.setHavingExpression(expBuilder.get("address").get("country").equal("Canada"))
0399: */
0400: public void setHavingExpression(Expression expression) {
0401: havingExpression = expression;
0402: setIsPrepared(false);
0403: }
0404:
0405: /**
0406: * INTERNAL:
0407: * Method used to abstract addToConstructorItem behavour from the public addItem methods
0408: */
0409: private void addItem(ReportItem item) {
0410: if (addToConstructorItem
0411: && (getItems().size() > 0)
0412: && (((ReportItem) getItems().lastElement())
0413: .isContructorItem())) {
0414: ((ConstructorReportItem) getItems().lastElement())
0415: .addItem(item);
0416: } else {
0417: getItems().addElement(item);
0418: }
0419: //Bug2804042 Must un-prepare if prepared as the SQL may change.
0420: setIsPrepared(false);
0421: }
0422:
0423: /**
0424: * ADVANCED:
0425: * Add the expression value to be included in the result.
0426: * EXAMPLE: reportQuery.addItem("name", expBuilder.get("firstName").toUpperCase());
0427: */
0428: public void addItem(String itemName, Expression attributeExpression) {
0429: ReportItem item = new ReportItem(itemName, attributeExpression);
0430: addItem(item);
0431: }
0432:
0433: /**
0434: * ADVANCED:
0435: * Add the expression value to be included in the result.
0436: * EXAMPLE: reportQuery.addItem("name", expBuilder.get("firstName").toUpperCase());
0437: */
0438: public void addItem(String itemName,
0439: Expression attributeExpression, List joinedExpressions) {
0440: ReportItem item = new ReportItem(itemName, attributeExpression);
0441: item.getJoinedAttributeManager()
0442: .setJoinedAttributeExpressions_(joinedExpressions);
0443: addItem(item);
0444: }
0445:
0446: /**
0447: * INTERNAL:
0448: * Add the expression value to be included in the result.
0449: * EXAMPLE: reportQuery.addItem("name", expBuilder.get("firstName").toUpperCase());
0450: * The resultType can be specified to support EJBQL that adheres to the
0451: * EJB 3.0 spec.
0452: */
0453: protected void addItem(String itemName,
0454: Expression attributeExpression, Class resultType) {
0455: ReportItem item = new ReportItem(itemName, attributeExpression);
0456: item.setResultType(resultType);
0457: addItem(item);
0458: }
0459:
0460: /**
0461: * PUBLIC:
0462: * Add the maximum value of the attribute to be included in the result.
0463: * Aggregation functions can be used with a group by, or on the entire result set.
0464: * EXAMPLE: reportQuery.addMaximum("salary");
0465: */
0466: public void addMaximum(String itemName) {
0467: addMaximum(itemName, getExpressionBuilder().get(itemName));
0468: }
0469:
0470: /**
0471: * PUBLIC:
0472: * Add the maximum value of the attribute to be included in the result.
0473: * Aggregation functions can be used with a group by, or on the entire result set.
0474: * EXAMPLE: reportQuery.addMaximum("managerSalary", expBuilder.get("manager").get("salary"));
0475: */
0476: public void addMaximum(String itemName,
0477: Expression attributeExpression) {
0478: addItem(itemName, attributeExpression.maximum());
0479: }
0480:
0481: /**
0482: * PUBLIC:
0483: * Add the minimum value of the attribute to be included in the result.
0484: * Aggregation functions can be used with a group by, or on the entire result set.
0485: * EXAMPLE: reportQuery.addMinimum("salary");
0486: */
0487: public void addMinimum(String itemName) {
0488: addMinimum(itemName, getExpressionBuilder().get(itemName));
0489: }
0490:
0491: /**
0492: * PUBLIC:
0493: * Add the minimum value of the attribute to be included in the result.
0494: * Aggregation functions can be used with a group by, or on the entire result set.
0495: * EXAMPLE: reportQuery.addMinimum("managerSalary", expBuilder.get("manager").get("salary"));
0496: */
0497: public void addMinimum(String itemName,
0498: Expression attributeExpression) {
0499: addItem(itemName, attributeExpression.minimum());
0500: }
0501:
0502: /**
0503: * PUBLIC:
0504: * Add the standard deviation value of the attribute to be included in the result.
0505: * Aggregation functions can be used with a group by, or on the entire result set.
0506: * EXAMPLE: reportQuery.addStandardDeviation("salary");
0507: */
0508: public void addStandardDeviation(String itemName) {
0509: addStandardDeviation(itemName, getExpressionBuilder().get(
0510: itemName));
0511: }
0512:
0513: /**
0514: * PUBLIC:
0515: * Add the standard deviation value of the attribute to be included in the result.
0516: * Aggregation functions can be used with a group by, or on the entire result set.
0517: * EXAMPLE: reportQuery.addStandardDeviation("managerSalary", expBuilder.get("manager").get("salary"));
0518: */
0519: public void addStandardDeviation(String itemName,
0520: Expression attributeExpression) {
0521: addItem(itemName, attributeExpression.standardDeviation());
0522: }
0523:
0524: /**
0525: * PUBLIC:
0526: * Add the sum value of the attribute to be included in the result.
0527: * Aggregation functions can be used with a group by, or on the entire result set.
0528: * EXAMPLE: reportQuery.addSum("salary");
0529: */
0530: public void addSum(String itemName) {
0531: addSum(itemName, getExpressionBuilder().get(itemName));
0532: }
0533:
0534: /**
0535: * PUBLIC:
0536: * Add the sum value of the attribute to be included in the result and
0537: * return it as the specified resultType.
0538: * Aggregation functions can be used with a group by, or on the entire result set.
0539: * EXAMPLE: reportQuery.addSum("salary", Float.class);
0540: */
0541: public void addSum(String itemName, Class resultType) {
0542: addSum(itemName, getExpressionBuilder().get(itemName),
0543: resultType);
0544: }
0545:
0546: /**
0547: * PUBLIC:
0548: * Add the sum value of the attribute to be included in the result.
0549: * Aggregation functions can be used with a group by, or on the entire result set.
0550: * EXAMPLE: reportQuery.addSum("managerSalary", expBuilder.get("manager").get("salary"));
0551: */
0552: public void addSum(String itemName, Expression attributeExpression) {
0553: addItem(itemName, attributeExpression.sum());
0554: }
0555:
0556: /**
0557: * PUBLIC:
0558: * Add the sum value of the attribute to be included in the result and
0559: * return it as the specified resultType.
0560: * Aggregation functions can be used with a group by, or on the entire result set.
0561: * EXAMPLE: reportQuery.addSum("managerSalary", expBuilder.get("manager").get("salary"), Float.class);
0562: */
0563: public void addSum(String itemName, Expression attributeExpression,
0564: Class resultType) {
0565: addItem(itemName, attributeExpression.sum(), resultType);
0566: }
0567:
0568: /**
0569: * PUBLIC:
0570: * Add the variance value of the attribute to be included in the result.
0571: * Aggregation functions can be used with a group by, or on the entire result set.
0572: * EXAMPLE: reportQuery.addVariance("salary");
0573: */
0574: public void addVariance(String itemName) {
0575: addVariance(itemName, getExpressionBuilder().get(itemName));
0576: }
0577:
0578: /**
0579: * PUBLIC:
0580: * Add the variance value of the attribute to be included in the result.
0581: * Aggregation functions can be used with a group by, or on the entire result set.
0582: * EXAMPLE: reportQuery.addVariance("managerSalary", expBuilder.get("manager").get("salary"));
0583: */
0584: public void addVariance(String itemName,
0585: Expression attributeExpression) {
0586: addItem(itemName, attributeExpression.variance());
0587: }
0588:
0589: /**
0590: * PUBLIC: Call a constructor for the given class with the results of this query.
0591: * @param constructorClass
0592: */
0593: public ConstructorReportItem beginAddingConstructorArguments(
0594: Class constructorClass) {
0595: ConstructorReportItem citem = new ConstructorReportItem(
0596: constructorClass.getName());
0597: citem.setResultType(constructorClass);
0598: //add directly to avoid addToConstructorItem behaviour
0599: getItems().add(citem);
0600: //Bug2804042 Must un-prepare if prepared as the SQL may change.
0601: setIsPrepared(false);
0602: this .addToConstructorItem = true;
0603: return citem;
0604: }
0605:
0606: /**
0607: * PUBLIC: Call a constructor for the given class with the results of this query.
0608: * @param constructorClass
0609: * @param constructorArgTypes - sets the argument types to be passed to the constructor.
0610: */
0611: public ConstructorReportItem beginAddingConstructorArguments(
0612: Class constructorClass, Class[] constructorArgTypes) {
0613: ConstructorReportItem citem = beginAddingConstructorArguments(constructorClass);
0614: citem.setConstructorArgTypes(constructorArgTypes);
0615: return citem;
0616: }
0617:
0618: /**
0619: * INTERNAL:
0620: * Construct a result from a row. Either return a ReportQueryResult or just the attribute.
0621: */
0622: public Object buildObject(AbstractRecord row, Vector toManyJoinData) {
0623: ReportQueryResult reportQueryResult = new ReportQueryResult(
0624: this , row, toManyJoinData);
0625: //GF_ISSUE_395
0626: if (this .returnedKeys != null) {
0627: if (this .returnedKeys.contains(reportQueryResult
0628: .getResultKey())) {
0629: return RESULT_IGNORED; //distinguish between null values and thrown away duplicates
0630: } else {
0631: this .returnedKeys.add(reportQueryResult.getResultKey());
0632: }
0633: }
0634: //end GF_ISSUE_395
0635: if (this .shouldReturnSingleAttribute()) {
0636: return reportQueryResult.getResults().firstElement();
0637: }
0638: if (this .shouldReturnWithoutReportQueryResult()) {
0639: if (reportQueryResult.getResults().size() == 1) {
0640: return reportQueryResult.getResults().firstElement();
0641: }
0642: return reportQueryResult.toArray();
0643: }
0644: return reportQueryResult;
0645: }
0646:
0647: /**
0648: * INTERNAL:
0649: * Construct a container of ReportQueryResult from the rows.
0650: * If only one result or value was asked for only return that.
0651: */
0652: public Object buildObjects(Vector rows) {
0653: if (shouldReturnSingleResult() || shouldReturnSingleValue()) {
0654: if (rows.isEmpty()) {
0655: return null;
0656: }
0657: ReportQueryResult result = (ReportQueryResult) buildObject(
0658: (AbstractRecord) rows.firstElement(), rows);
0659: if (shouldReturnSingleValue()) {
0660: return result.elements().nextElement();
0661: }
0662: return result;
0663: }
0664:
0665: ContainerPolicy containerPolicy = getContainerPolicy();
0666: Object reportResults = containerPolicy.containerInstance(rows
0667: .size());
0668: // GF_ISSUE_395
0669: if (shouldDistinctBeUsed()) {
0670: this .returnedKeys = new HashSet();
0671: }
0672: //end GF_ISSUE
0673: //If only the attribute is desired, then buildObject will only get the first attribute each time
0674: for (Enumeration rowsEnum = rows.elements(); rowsEnum
0675: .hasMoreElements();) {
0676: // GF_ISSUE_395
0677: Object result = buildObject((AbstractRecord) rowsEnum
0678: .nextElement(), rows);
0679: if (result != RESULT_IGNORED) {
0680: containerPolicy.addInto(result, reportResults,
0681: getSession());
0682: }
0683: //end GF_ISSUE
0684: }
0685: return reportResults;
0686: }
0687:
0688: /**
0689: * INTERNAL:
0690: * The cache check is done before the prepare as a hit will not require the work to be done.
0691: */
0692: protected Object checkEarlyReturnImpl(AbstractSession session,
0693: AbstractRecord translationRow) {
0694: // Check for in-memory only query.
0695: if (shouldCheckCacheOnly()) {
0696: throw QueryException
0697: .cannotSetShouldCheckCacheOnlyOnReportQuery();
0698: } else {
0699: return null;
0700: }
0701: }
0702:
0703: /**
0704: * INTERNAL: Required for a very special case of bug 2612185:
0705: * ReportItems from parallelExpressions, on a ReportQuery which is a subQuery,
0706: * which is being batch read.
0707: * In a batch query the selection criteria is effectively cloned twice, meaning
0708: * the ReportItems need to be cloned an extra time also to stay in sync.
0709: * Each call to copiedVersionFrom() will take O(1) time as the expression was
0710: * already cloned.
0711: */
0712: public void copyReportItems(Dictionary alreadyDone) {
0713: items = (Vector) items.clone();
0714: for (int i = items.size() - 1; i >= 0; i--) {
0715: ReportItem item = (ReportItem) items.elementAt(i);
0716: Expression expression = item.getAttributeExpression();
0717: if ((expression != null)
0718: && (alreadyDone.get(expression.getBuilder()) != null)) {
0719: expression = expression.copiedVersionFrom(alreadyDone);
0720: }
0721: items.set(i, new ReportItem(item.getName(), expression));
0722: }
0723: if (groupByExpressions != null) {
0724: groupByExpressions = (Vector) groupByExpressions.clone();
0725: for (int i = groupByExpressions.size() - 1; i >= 0; i--) {
0726: Expression item = (Expression) groupByExpressions
0727: .elementAt(i);
0728: if (alreadyDone.get(item.getBuilder()) != null) {
0729: groupByExpressions.set(i, item
0730: .copiedVersionFrom(alreadyDone));
0731: }
0732: }
0733: }
0734: if (orderByExpressions != null) {
0735: for (int i = orderByExpressions.size() - 1; i >= 0; i--) {
0736: Expression item = (Expression) orderByExpressions
0737: .elementAt(i);
0738: if (alreadyDone.get(item.getBuilder()) != null) {
0739: orderByExpressions.set(i, item
0740: .copiedVersionFrom(alreadyDone));
0741: }
0742: }
0743: }
0744: }
0745:
0746: /**
0747: * PUBLIC:
0748: * Set if the query results should contain the primary keys or each associated object.
0749: * This make retrieving the real object easier.
0750: * By default they are not retrieved.
0751: */
0752: public void dontRetrievePrimaryKeys() {
0753: setShouldRetrievePrimaryKeys(false);
0754: //Bug2804042 Must un-prepare if prepared as the SQL may change.
0755: setIsPrepared(false);
0756: }
0757:
0758: /**
0759: * PUBLIC:
0760: * Don't simplify the result by returning the single attribute. Wrap in a ReportQueryResult.
0761: */
0762: public void dontReturnSingleAttribute() {
0763: if (shouldReturnSingleAttribute()) {
0764: returnChoice = 0;
0765: }
0766: }
0767:
0768: /**
0769: * PUBLIC:
0770: * Simplifies the result by only returning the first result.
0771: * This can be used if it known that only one row is returned by the report query.
0772: */
0773: public void dontReturnSingleResult() {
0774: if (shouldReturnSingleResult()) {
0775: returnChoice = 0;
0776: }
0777: }
0778:
0779: /**
0780: * PUBLIC:
0781: * Simplifies the result by only returning a single value.
0782: * This can be used if it known that only one row is returned by the report query and only a single item is added
0783: * to the report.
0784: */
0785: public void dontReturnSingleValue() {
0786: if (shouldReturnSingleValue()) {
0787: returnChoice = 0;
0788: }
0789: }
0790:
0791: /**
0792: * PUBLIC:
0793: * Simplifies the result by only returning a single value.
0794: * This can be used if it known that only one row is returned by the report query and only a single item is added
0795: * to the report.
0796: */
0797: public void dontReturnWithoutReportQueryResult() {
0798: if (shouldReturnWithoutReportQueryResult()) {
0799: returnChoice = 0;
0800: }
0801: }
0802:
0803: /**
0804: * PUBLIC:
0805: * Used in conjunction with beginAddingConstructorArguments to signal that expressions should no longer be
0806: * be added to the collection used in the constructor
0807: *
0808: * Get the rows and build the object from the rows.
0809: * @exception DatabaseException - an error has occurred on the database
0810: * @return Vector - collection of objects resulting from execution of query.
0811: */
0812: public void endAddingToConstructorItem() {
0813: this .addToConstructorItem = false;
0814: }
0815:
0816: /**
0817: * INTERNAL:
0818: * Execute the query.
0819: * Get the rows and build the object from the rows.
0820: * @exception DatabaseException - an error has occurred on the database
0821: * @return Vector - collection of objects resulting from execution of query.
0822: */
0823: public Object executeDatabaseQuery() throws DatabaseException {
0824: // ensure a pessimistic locking query will go down the write connection
0825: if (isLockQuery() && getSession().isUnitOfWork()) {
0826: UnitOfWorkImpl unitOfWork = (UnitOfWorkImpl) getSession();
0827: // Note if a nested unit of work this will recursively start a
0828: // transaction early on the parent also.
0829: if (isLockQuery()) {
0830: if ((!unitOfWork.getCommitManager().isActive())
0831: && (!unitOfWork
0832: .wasTransactionBegunPrematurely())) {
0833: unitOfWork.beginTransaction();
0834: unitOfWork.setWasTransactionBegunPrematurely(true);
0835: }
0836: }
0837: }
0838:
0839: if (getContainerPolicy().overridesRead()) {
0840: return getContainerPolicy().execute();
0841: }
0842:
0843: if (getQueryId() == 0) {
0844: setQueryId(getSession().getNextQueryId());
0845: }
0846:
0847: Vector rows = getQueryMechanism().selectAllReportQueryRows();
0848: // If using -m joins, must set all rows.
0849: return buildObjects(rows);
0850: }
0851:
0852: /**
0853: * INTERNAL:
0854: * Return the group bys.
0855: */
0856: public Vector getGroupByExpressions() {
0857: return groupByExpressions;
0858: }
0859:
0860: /**
0861: * INTERNAL:
0862: * Return the Having expression.
0863: */
0864: public Expression getHavingExpression() {
0865: return havingExpression;
0866: }
0867:
0868: /**
0869: * INTERNAL:
0870: * return a collection of expressions if PK's are used.
0871: */
0872: public Vector getQueryExpressions() {
0873: Vector fieldExpressions = new Vector(getItems().size());
0874:
0875: // For bug 3115576 and an EXISTS subquery only need to return a single field.
0876: if (shouldRetrieveFirstPrimaryKey()) {
0877: if (!getDescriptor().getPrimaryKeyFields().isEmpty()) {
0878: fieldExpressions.addElement(getDescriptor()
0879: .getPrimaryKeyFields().get(0));
0880: }
0881: }
0882: if (shouldRetrievePrimaryKeys()) {
0883: fieldExpressions.addAll(getDescriptor()
0884: .getPrimaryKeyFields());
0885: }
0886:
0887: return fieldExpressions;
0888: }
0889:
0890: /**
0891: * INTERNAL:
0892: * return a collection of expressions from the items. Ignore the null (place holders).
0893: */
0894: public Vector getItemExpressions() {
0895: Vector fieldExpressions = new Vector(getItems().size());
0896:
0897: // For bug 3115576 and an EXISTS subquery only need to return a single field.
0898: if (shouldRetrieveFirstPrimaryKey()) {
0899: if (!getDescriptor().getPrimaryKeyFields().isEmpty()) {
0900: fieldExpressions.addElement(getDescriptor()
0901: .getPrimaryKeyFields().get(0));
0902: }
0903: }
0904: if (shouldRetrievePrimaryKeys()) {
0905: fieldExpressions.addAll(getDescriptor()
0906: .getPrimaryKeyFields());
0907: }
0908:
0909: for (Enumeration itemsEnum = getItems().elements(); itemsEnum
0910: .hasMoreElements();) {
0911: ReportItem item = (ReportItem) itemsEnum.nextElement();
0912: Expression fieldExpression = item.getAttributeExpression();
0913: if (fieldExpression != null) {
0914: fieldExpressions.addElement(fieldExpression);
0915: }
0916: }
0917: return fieldExpressions;
0918: }
0919:
0920: /**
0921: * INTERNAL:
0922: * @return ReportQueryItems defining the attributes to be read
0923: */
0924: public Vector getItems() {
0925: return items;
0926: }
0927:
0928: /**
0929: * INTERNAL:
0930: * Clear the ReportQueryItems
0931: */
0932: public void clearItems() {
0933: items = new Vector();
0934: setIsPrepared(false);
0935: }
0936:
0937: /**
0938: * INTERNAL:
0939: * Lazily initialize and return the names of the items requested for use in each result object
0940: */
0941: public Vector getNames() {
0942: if (names == null) {
0943: names = new Vector();
0944: for (Enumeration e = getItems().elements(); e
0945: .hasMoreElements();) {
0946: names.addElement(((ReportItem) e.nextElement())
0947: .getName());
0948: }
0949: }
0950: return names;
0951: }
0952:
0953: /**
0954: * PUBLIC:
0955: * Return if this is a report query.
0956: */
0957: public boolean isReportQuery() {
0958: return true;
0959: }
0960:
0961: /**
0962: * INTERNAL:
0963: * Prepare the receiver for execution in a session.
0964: * Initialize each item with its DTF mapping
0965: */
0966: protected void prepare() throws QueryException {
0967: // Oct 19, 2000 JED
0968: // Added exception to be thrown if no attributes have been added to the query
0969: if (getItems().size() > 0) {
0970: try {
0971: for (Enumeration itemsEnum = getItems().elements(); itemsEnum
0972: .hasMoreElements();) {
0973: ((ReportItem) itemsEnum.nextElement())
0974: .initialize(this );
0975: }
0976: } catch (QueryException exception) {
0977: exception.setQuery(this );
0978: throw exception;
0979: }
0980: } else {
0981: if ((!shouldRetrievePrimaryKeys())
0982: && (!shouldRetrieveFirstPrimaryKey())) {
0983: throw QueryException.noAttributesForReportQuery(this );
0984: }
0985: }
0986:
0987: super .prepare();
0988:
0989: }
0990:
0991: /**
0992: * INTERNAL:
0993: * Prepare a report query with a count defined on an object attribute.
0994: * Added to fix bug 3268040, addCount(objectAttribute) not supported.
0995: */
0996: protected void prepareObjectAttributeCount(
0997: Dictionary clonedExpressions) {
0998: prepareObjectAttributeCount(getItems(), clonedExpressions);
0999: }
1000:
1001: private void prepareObjectAttributeCount(List items,
1002: Dictionary clonedExpressions) {
1003: int numOfReportItems = items.size();
1004: //gf675: need to loop through all items to fix all count(..) instances
1005: for (int i = 0; i < numOfReportItems; i++) {
1006: ReportItem item = (ReportItem) items.get(i);
1007: if (item == null) {
1008: continue;
1009: } else if (item instanceof ConstructorReportItem) {
1010: // recursive call to process child ReportItems
1011: prepareObjectAttributeCount(
1012: ((ConstructorReportItem) item).getReportItems(),
1013: clonedExpressions);
1014: } else if (item.getAttributeExpression() instanceof FunctionExpression) {
1015: FunctionExpression count = (FunctionExpression) item
1016: .getAttributeExpression();
1017: if (count.getOperator().getSelector() == ExpressionOperator.Count) {
1018: Expression baseExp = count.getBaseExpression();
1019: boolean distinctUsed = false;
1020: if (baseExp.isFunctionExpression()
1021: && (((FunctionExpression) baseExp)
1022: .getOperator().getSelector() == ExpressionOperator.Distinct)) {
1023: distinctUsed = true;
1024: baseExp = ((FunctionExpression) baseExp)
1025: .getBaseExpression();
1026: }
1027: boolean outerJoin = false;
1028: ClassDescriptor newDescriptor = null;
1029: if (baseExp.isQueryKeyExpression()) {
1030: // now need to find out if it is a direct to field or something else.
1031: DatabaseMapping mapping = getLeafMappingFor(
1032: baseExp, getDescriptor());
1033: if ((mapping != null)
1034: && !mapping.isDirectToFieldMapping()) {
1035: newDescriptor = mapping
1036: .getReferenceDescriptor();
1037: outerJoin = ((QueryKeyExpression) baseExp)
1038: .shouldUseOuterJoin();
1039: }
1040: } else if (baseExp.isExpressionBuilder()) {
1041: newDescriptor = getSession().getDescriptor(
1042: ((ExpressionBuilder) baseExp)
1043: .getQueryClass());
1044: }
1045:
1046: if (newDescriptor != null) {
1047: // At this point we are committed to rewriting the query.
1048: if (newDescriptor.hasSimplePrimaryKey()) {
1049: // case 1: simple PK =>
1050: // treat COUNT(entity) as COUNT(entity.pk)
1051: DatabaseMapping pk = getMappingOfFirstPrimaryKey(newDescriptor);
1052: Expression countArg = baseExp.get(pk
1053: .getAttributeName());
1054: if (distinctUsed) {
1055: countArg = countArg.distinct();
1056: }
1057: count.setBaseExpression(countArg);
1058: count.getChildren().setElementAt(countArg,
1059: 0);
1060: } else if (!distinctUsed) {
1061: // case 2: composite PK, but no DISTINCT =>
1062: // pick a PK column for the COUNT aggregate
1063: DatabaseMapping pk = getMappingOfFirstPrimaryKey(newDescriptor);
1064: Expression countArg = baseExp.get(pk
1065: .getAttributeName());
1066: while (pk.isAggregateObjectMapping()) {
1067: newDescriptor = ((AggregateObjectMapping) pk)
1068: .getReferenceDescriptor();
1069: pk = getMappingOfFirstPrimaryKey(newDescriptor);
1070: countArg = countArg.get(pk
1071: .getAttributeName());
1072: }
1073: count.setBaseExpression(countArg);
1074: count.getChildren().setElementAt(countArg,
1075: 0);
1076: } else if (!outerJoin) {
1077: // case 3: composite PK and DISTINCT, but no
1078: // outer join => previous solution using
1079: // COUNT(*) and EXISTS subquery
1080:
1081: // If this is a subselect baseExp is yet uncloned,
1082: // and will miss out if moved now from items into a selection criteria.
1083: if (clonedExpressions != null) {
1084: if (clonedExpressions.get(baseExp
1085: .getBuilder()) != null) {
1086: baseExp = (QueryKeyExpression) baseExp
1087: .copiedVersionFrom(clonedExpressions);
1088: } else {
1089: baseExp = (QueryKeyExpression) baseExp
1090: .rebuildOn(getExpressionBuilder());
1091: }
1092: }
1093:
1094: // Now the reference class of the query needs to be reversed.
1095: // See the bug description for an explanation.
1096: ExpressionBuilder countBuilder = baseExp
1097: .getBuilder();
1098: ExpressionBuilder outerBuilder = new ExpressionBuilder();
1099:
1100: ReportQuery subSelect = new ReportQuery(
1101: getReferenceClass(), countBuilder);
1102: subSelect
1103: .setShouldRetrieveFirstPrimaryKey(true);
1104:
1105: // Make sure the outerBuilder does not appear on the left of the subselect.
1106: // Putting a builder on the left is desirable to trigger an optimization.
1107: if (getSelectionCriteria() != null) {
1108: outerBuilder
1109: .setQueryClass(newDescriptor
1110: .getJavaClass());
1111: subSelect
1112: .setSelectionCriteria(baseExp
1113: .equal(outerBuilder)
1114: .and(
1115: getSelectionCriteria()));
1116: } else {
1117: subSelect.setSelectionCriteria(baseExp
1118: .equal(outerBuilder));
1119: }
1120: setSelectionCriteria(outerBuilder
1121: .exists(subSelect));
1122: count.setBaseExpression(outerBuilder);
1123: count.getChildren().setElementAt(
1124: outerBuilder, 0);
1125: setReferenceClass(newDescriptor
1126: .getJavaClass());
1127: changeDescriptor(getSession());
1128: } else {
1129: // case 4: composite PK, DISTINCT, outer join =>
1130: // not supported, throw exception
1131: throw QueryException
1132: .distinctCountOnOuterJoinedCompositePK(
1133: newDescriptor, this );
1134: }
1135: }
1136: }
1137: }
1138: }
1139: }
1140:
1141: /** */
1142: private DatabaseMapping getMappingOfFirstPrimaryKey(
1143: ClassDescriptor descriptor) {
1144: if (descriptor != null) {
1145: for (Iterator i = descriptor.getMappings().iterator(); i
1146: .hasNext();) {
1147: DatabaseMapping m = (DatabaseMapping) i.next();
1148: if (m.isPrimaryKeyMapping()) {
1149: return m;
1150: }
1151: }
1152: }
1153: return null;
1154: }
1155:
1156: /**
1157: * INTERNAL:
1158: * Prepare the mechanism.
1159: */
1160: protected void prepareSelectAllRows() {
1161: prepareObjectAttributeCount(null);
1162:
1163: getQueryMechanism().prepareReportQuerySelectAllRows();
1164: }
1165:
1166: /**
1167: * INTERNAL:
1168: * Prepare the receiver for being printed inside a subselect.
1169: * This prepares the statement but not the call.
1170: */
1171: public synchronized void prepareSubSelect(AbstractSession session,
1172: AbstractRecord translationRow, Dictionary clonedExpressions)
1173: throws QueryException {
1174: if (isPrepared()) {
1175: return;
1176: }
1177:
1178: setIsPrepared(true);
1179: setSession(session);
1180: setTranslationRow(translationRow);
1181:
1182: checkDescriptor(getSession());
1183:
1184: if (descriptor.isAggregateDescriptor()) {
1185: // Not allowed
1186: throw QueryException
1187: .aggregateObjectCannotBeDeletedOrWritten(
1188: descriptor, this );
1189: }
1190:
1191: try {
1192: for (Enumeration itemsEnum = getItems().elements(); itemsEnum
1193: .hasMoreElements();) {
1194: ((ReportItem) itemsEnum.nextElement()).initialize(this );
1195: }
1196: } catch (QueryException exception) {
1197: exception.setQuery(this );
1198: throw exception;
1199: }
1200:
1201: prepareObjectAttributeCount(clonedExpressions);
1202:
1203: getQueryMechanism().prepareReportQuerySubSelect();
1204:
1205: setSession(null);
1206: setTranslationRow(null);
1207: }
1208:
1209: /**
1210: * PUBLIC:
1211: * Set if the query results should contain the primary keys or each associated object.
1212: * This make retrieving the real object easier.
1213: * By default they are not retrieved.
1214: */
1215: public void retrievePrimaryKeys() {
1216: setShouldRetrievePrimaryKeys(true);
1217: //Bug2804042 Must un-prepare if prepared as the SQL may change.
1218: setIsPrepared(false);
1219: }
1220:
1221: /**
1222: * PUBLIC:
1223: * Simplify the result by returning a single attribute. Don't wrap in a ReportQueryResult.
1224: */
1225: public void returnSingleAttribute() {
1226: returnChoice = ShouldReturnSingleAttribute;
1227: }
1228:
1229: /**
1230: * PUBLIC:
1231: * Simplifies the result by only returning the first result.
1232: * This can be used if it known that only one row is returned by the report query.
1233: */
1234: public void returnSingleResult() {
1235: returnChoice = ShouldReturnSingleResult;
1236: }
1237:
1238: /**
1239: * PUBLIC:
1240: * Simplifies the result by only returning a single value.
1241: * This can be used if it known that only one row is returned by the report query and only a single item is added
1242: * to the report.
1243: */
1244: public void returnSingleValue() {
1245: returnChoice = ShouldReturnSingleValue;
1246: }
1247:
1248: /**
1249: * PUBLIC:
1250: * Simplifies the result by only returning a single value.
1251: * This can be used if it known that only one row is returned by the report query and only a single item is added
1252: * to the report.
1253: */
1254: public void returnWithoutReportQueryResult() {
1255: this .returnChoice = ShouldReturnWithoutReportQueryResult;
1256: }
1257:
1258: /**
1259: * PUBLIC:
1260: * Set if the query results should contain the primary keys or each associated object.
1261: * This make retrieving the real object easier.
1262: * By default they are not retrieved.
1263: */
1264: public void setShouldRetrievePrimaryKeys(
1265: boolean shouldRetrievePrimaryKeys) {
1266: this .shouldRetrievePrimaryKeys = (shouldRetrievePrimaryKeys ? FULL_PRIMARY_KEY
1267: : NO_PRIMARY_KEY);
1268: }
1269:
1270: /**
1271: * ADVANCED:
1272: * Sets if the query results should contain the first primary key of each associated object.
1273: * Usefull if this is an EXISTS subquery and you don't care what fields are returned
1274: * so long as it is a single field.
1275: * The default value is false.
1276: * This should only be used with a subquery.
1277: */
1278: public void setShouldRetrieveFirstPrimaryKey(
1279: boolean shouldRetrieveFirstPrimaryKey) {
1280: this .shouldRetrievePrimaryKeys = (shouldRetrieveFirstPrimaryKey ? FIRST_PRIMARY_KEY
1281: : NO_PRIMARY_KEY);
1282: }
1283:
1284: /**
1285: * PUBLIC:
1286: * Simplifies the result by only returning the attribute (as opposed to wrapping in a ReportQueryResult).
1287: * This can be used if it is known that only one attribute is returned by the report query.
1288: */
1289: public void setShouldReturnSingleAttribute(boolean newChoice) {
1290: if (newChoice) {
1291: returnSingleAttribute();
1292: } else {
1293: dontReturnSingleAttribute();
1294: }
1295: }
1296:
1297: /**
1298: * PUBLIC:
1299: * Simplifies the result by only returning the first result.
1300: * This can be used if it known that only one row is returned by the report query.
1301: */
1302: public void setShouldReturnSingleResult(boolean newChoice) {
1303: if (newChoice) {
1304: returnSingleResult();
1305: } else {
1306: dontReturnSingleResult();
1307: }
1308: }
1309:
1310: /**
1311: * PUBLIC:
1312: * Simplifies the result by only returning a single value.
1313: * This can be used if it known that only one row is returned by the report query and only a single item is added
1314: * to the report.
1315: */
1316: public void setShouldReturnSingleValue(boolean newChoice) {
1317: if (newChoice) {
1318: returnSingleValue();
1319: } else {
1320: dontReturnSingleValue();
1321: }
1322: }
1323:
1324: /**
1325: * PUBLIC:
1326: * Simplifies the result by returning a nested list instead of the ReportQueryResult.
1327: * This is used by EJB 3.
1328: */
1329: public void setShouldReturnWithoutReportQueryResult(
1330: boolean newChoice) {
1331: if (newChoice) {
1332: returnWithoutReportQueryResult();
1333: } else {
1334: dontReturnWithoutReportQueryResult();
1335: }
1336: }
1337:
1338: /**
1339: * PUBLIC:
1340: * Return if the query results should contain the primary keys or each associated object.
1341: * This make retrieving the real object easier.
1342: */
1343: public boolean shouldRetrievePrimaryKeys() {
1344: return (shouldRetrievePrimaryKeys == FULL_PRIMARY_KEY);
1345: }
1346:
1347: /**
1348: * PUBLIC:
1349: * Return if the query results should contain the first primary key of each associated object.
1350: * Usefull if this is an EXISTS subquery and you don't care what fields are returned
1351: * so long as it is a single field.
1352: */
1353: public boolean shouldRetrieveFirstPrimaryKey() {
1354: return (shouldRetrievePrimaryKeys == FIRST_PRIMARY_KEY);
1355: }
1356:
1357: /**
1358: * PUBLIC:
1359: * Answer if we are only returning the attribute (as opposed to wrapping in a ReportQueryResult).
1360: * This can be used if it is known that only one attribute is returned by the report query.
1361: */
1362: public boolean shouldReturnSingleAttribute() {
1363: return returnChoice == ShouldReturnSingleAttribute;
1364: }
1365:
1366: /**
1367: * PUBLIC:
1368: * Simplifies the result by only returning the first result.
1369: * This can be used if it known that only one row is returned by the report query.
1370: */
1371: public boolean shouldReturnSingleResult() {
1372: return returnChoice == ShouldReturnSingleResult;
1373: }
1374:
1375: /**
1376: * PUBLIC:
1377: * Simplifies the result by only returning a single value.
1378: * This can be used if it known that only one row is returned by the report query and only a single item is added
1379: * to the report.
1380: */
1381: public boolean shouldReturnSingleValue() {
1382: return returnChoice == ShouldReturnSingleValue;
1383: }
1384:
1385: /**
1386: * PUBLIC:
1387: * Simplifies the result by returning a nested list instead of the ReportQueryResult.
1388: * This is used by EJB 3.
1389: */
1390: public boolean shouldReturnWithoutReportQueryResult() {
1391: return returnChoice == ShouldReturnWithoutReportQueryResult;
1392: }
1393:
1394: }
|