| /* |
| * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // Oracle - initial API and implementation from Oracle TopLink |
| package org.eclipse.persistence.queries; |
| |
| import java.util.*; |
| |
| import org.eclipse.persistence.descriptors.VersionLockingPolicy; |
| import org.eclipse.persistence.expressions.*; |
| import org.eclipse.persistence.internal.descriptors.OptimisticLockingPolicy; |
| import org.eclipse.persistence.internal.expressions.*; |
| import org.eclipse.persistence.internal.queries.*; |
| import org.eclipse.persistence.exceptions.*; |
| import org.eclipse.persistence.internal.helper.*; |
| import org.eclipse.persistence.internal.sessions.remote.*; |
| import org.eclipse.persistence.internal.sessions.AbstractRecord; |
| import org.eclipse.persistence.internal.sessions.AbstractSession; |
| import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl; |
| |
| /** |
| * <b>Purpose</b>: Query for information about a set of objects instead of the objects themselves. |
| * This supports select single attributes, nested attributes, aggregation functions and group bys.<p> |
| * |
| * <b>Attribute Types</b>:<ol> |
| * <li>addAttribute("directQueryKey") is a short cut method to add an attribute with the same name as its corresponding direct query key. |
| * <li>addAttribute("attributeName", expBuilder.get("oneToOneMapping").get("directQueryKey")) is the full approach for get values through joined 1:1 relationships. |
| * <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). |
| * <li>addAttribute("attributeName", null) Leave a place holder (NULL) value in the result (used for included values from other systems or calculated values). |
| * </ol> |
| * <b>Retrieving Primary Keys</b>: It is possible to retrieve the primary key raw values within each result, but stored in a separate (internal) vector. This |
| * primary key vector can later be used to retrieve the real object. |
| * @see #retrievePrimaryKeys() |
| * If the values are wanted in the result array then they must be added as attributes. For primary keys which are not mapped directly |
| * you can add them as DatabaseFields (see above). |
| * |
| * @author Doug Clarke |
| * @since TOPLink/Java 2.0 |
| */ |
| public class ReportQuery extends ReadAllQuery { |
| |
| /** Default, returns ReportQueryResult objects. */ |
| public static final int ShouldReturnReportResult = 0; |
| |
| /** Simplifies the result by only returning the first result. */ |
| public static final int ShouldReturnSingleResult = 1; |
| |
| /** Simplifies the result by only returning one value. */ |
| public static final int ShouldReturnSingleValue = 2; |
| |
| /** Simplifies the result by only returning the single attribute(as opposed to wrapping in a |
| ReportQueryResult). */ |
| public static final int ShouldReturnSingleAttribute = 3; |
| |
| /** For EJB 3 support returns results without using the ReportQueryResult */ |
| public static final int ShouldReturnWithoutReportQueryResult = 4; |
| |
| /** For EJB 3 support returns results as an Object array. */ |
| public static final int ShouldReturnArray = 5; |
| |
| /** For example, ... EXISTS( SELECT 1 FROM ... */ |
| public static final int ShouldSelectValue1 = 6; |
| |
| /** Specifies whether to retrieve primary keys, first primary key, or no primary key.*/ |
| public static final int FULL_PRIMARY_KEY = 2; |
| public static final int FIRST_PRIMARY_KEY = 1; |
| public static final int NO_PRIMARY_KEY = 0; |
| |
| //GF_ISSUE_395 |
| private enum ResultStatus { IGNORED }; |
| //end GF_ISSUE |
| |
| /** Flag indicating whether the primary key values should also be retrieved for the reference class. */ |
| protected int shouldRetrievePrimaryKeys; |
| |
| /** Collection of names for use by results. */ |
| protected List<String> names; |
| |
| /** Items to be selected, these could be attributes or aggregate functions. */ |
| protected List<ReportItem> items; |
| |
| /** Expressions representing fields to be used in the GROUP BY clause. */ |
| protected List<Expression> groupByExpressions; |
| |
| /** Expression representing the HAVING clause. */ |
| protected Expression havingExpression; |
| |
| /** Can be one of (ShouldReturnSingleResult, ShouldReturnSingleValue, ShouldReturnSingleAttribute) |
| ** Simplifies the result by only returning the first result, first value, or all attribute values |
| */ |
| protected int returnChoice; |
| |
| /** flag to allow items to be added to the last ConstructorReportItem **/ |
| protected boolean addToConstructorItem; |
| |
| /* GF_ISSUE_395 this attribute stores a set of unique keys that identity results. |
| * Used when distinct has been set on the query. For use in TCK |
| */ |
| protected Set<Object> returnedKeys; |
| |
| /** |
| * INTERNAL: |
| * The builder should be provided. |
| */ |
| public ReportQuery() { |
| this.queryMechanism = new ExpressionQueryMechanism(this); |
| this.items = new ArrayList<>(); |
| this.shouldRetrievePrimaryKeys = NO_PRIMARY_KEY; |
| this.addToConstructorItem = false; |
| |
| // overwrite the lock mode to NO_LOCK, this prevents the report query to lock |
| // when DEFAULT_LOCK_MODE and a pessimistic locking policy are used. |
| setLockMode(ObjectBuildingQuery.NO_LOCK); |
| this.shouldUseSerializedObjectPolicy = false; |
| } |
| |
| public ReportQuery(Class javaClass, Expression expression) { |
| this(); |
| this.defaultBuilder = expression.getBuilder(); |
| setReferenceClass(javaClass); |
| setSelectionCriteria(expression); |
| } |
| |
| /** |
| * PUBLIC: |
| * The report query is require to be constructor with an expression builder. |
| * This build must be used for the selection critiera, any item expressions, group bys and order bys. |
| */ |
| public ReportQuery(Class javaClass, ExpressionBuilder builder) { |
| this(); |
| this.defaultBuilder = builder; |
| setReferenceClass(javaClass); |
| } |
| |
| /** |
| * PUBLIC: |
| * The report query is require to be constructor with an expression builder. |
| * This build must be used for the selection critiera, any item expressions, group bys and order bys. |
| */ |
| public ReportQuery(ExpressionBuilder builder) { |
| this(); |
| this.defaultBuilder = builder; |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the attribute from the reference class to be included in the result. |
| * EXAMPLE: reportQuery.addAttribute("firstName"); |
| */ |
| public void addAttribute(String itemName) { |
| addItem(itemName, getExpressionBuilder().get(itemName)); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the attribute to be included in the result. |
| * EXAMPLE: reportQuery.addAttribute("city", expBuilder.get("address").get("city")); |
| */ |
| public void addAttribute(String itemName, Expression attributeExpression) { |
| addItem(itemName, attributeExpression); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the attribute to be included in the result. Return the result as the provided class |
| * EXAMPLE: reportQuery.addAttribute("city", expBuilder.get("period").get("startTime"), Time.class); |
| */ |
| public void addAttribute(String itemName, Expression attributeExpression, Class type) { |
| addItem(itemName, attributeExpression, type); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the average value of the attribute to be included in the result. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * EXAMPLE: reportQuery.addAverage("salary"); |
| */ |
| public void addAverage(String itemName) { |
| addAverage(itemName, getExpressionBuilder().get(itemName)); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the average value of the attribute to be included in the result and |
| * return it as the specified resultType. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * EXAMPLE: reportQuery.addAverage("salary", Float.class); |
| */ |
| public void addAverage(String itemName, Class resultType) { |
| addAverage(itemName, getExpressionBuilder().get(itemName), resultType); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the average value of the attribute to be included in the result. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * EXAMPLE: reportQuery.addAverage("managerSalary", expBuilder.get("manager").get("salary")); |
| */ |
| public void addAverage(String itemName, Expression attributeExpression) { |
| addItem(itemName, attributeExpression.average()); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the average value of the attribute to be included in the result and |
| * return it as the specified resultType. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * EXAMPLE: reportQuery.addAverage("managerSalary", expBuilder.get("manager").get("salary"), Double.class); |
| */ |
| public void addAverage(String itemName, Expression attributeExpression, Class resultType) { |
| addItem(itemName, attributeExpression.average(), resultType); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add a ConstructorReportItem to this query's set of return values. |
| * @param item used to specify a class constructor and values to pass in from this query |
| * @see ConstructorReportItem |
| */ |
| public void addConstructorReportItem(ConstructorReportItem item){ |
| addItem(item); |
| } |
| |
| /** |
| * PUBLIC: |
| * Include the number of rows returned by the query in the result. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * EXAMPLE: |
| * Java: |
| * reportQuery.addCount(); |
| * SQL: |
| * SELECT COUNT (*) FROM ... |
| * @see #addCount(java.lang.String) |
| */ |
| public void addCount() { |
| addCount("COUNT", getExpressionBuilder()); |
| } |
| |
| /** |
| * PUBLIC: |
| * Include the number of rows returned by the query in the result, where attributeExpression is not null. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * <p>Example: |
| * <blockquote><pre> |
| * TopLink: reportQuery.addCount("id"); |
| * SQL: SELECT COUNT (t0.EMP_ID) FROM EMPLOYEE t0, ... |
| * </pre></blockquote> |
| * @param attributeName the number of rows where attributeName is not null will be returned. |
| * @see #addCount(java.lang.String, org.eclipse.persistence.expressions.Expression) |
| */ |
| public void addCount(String attributeName) { |
| addCount(attributeName, getExpressionBuilder().get(attributeName)); |
| } |
| |
| /** |
| * PUBLIC: |
| * Include the number of rows returned by the query in the result, where attributeExpression is not null. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * Set the count to be returned as the specified resultType. |
| * <p>Example: |
| * <blockquote><pre> |
| * TopLink: reportQuery.addCount("id", Long.class); |
| * SQL: SELECT COUNT (t0.EMP_ID) FROM EMPLOYEE t0, ... |
| * </pre></blockquote> |
| * @param attributeName the number of rows where attributeName is not null will be returned. |
| * @see #addCount(java.lang.String, org.eclipse.persistence.expressions.Expression) |
| */ |
| public void addCount(String attributeName, Class resultType) { |
| addCount(attributeName, getExpressionBuilder().get(attributeName), resultType); |
| } |
| |
| /** |
| * PUBLIC: |
| * Include the number of rows returned by the query in the result, where attributeExpression |
| * is not null. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * <p>Example: |
| * <blockquote><pre> |
| * TopLink: reportQuery.addCount("Count", getExpressionBuilder().get("id")); |
| * SQL: SELECT COUNT (t0.EMP_ID) FROM EMPLOYEE t0, ... |
| * </pre></blockquote> |
| * <p>Example: counting only distinct values of an attribute. |
| * <blockquote><pre> |
| * TopLink: reportQuery.addCount("Count", getExpressionBuilder().get("address").distinct()); |
| * SQL: SELECT COUNT (DISTINCT t0.ADDR_ID) FROM EMPLOYEE t0, ... |
| * </pre></blockquote> |
| * objectAttributes can be specified also, even accross many to many |
| * mappings. |
| * @see #addCount() |
| */ |
| public void addCount(String itemName, Expression attributeExpression) { |
| addItem(itemName, attributeExpression.count()); |
| } |
| |
| /** |
| * PUBLIC: |
| * Include the number of rows returned by the query in the result, where attributeExpression |
| * is not null. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * Set the count to be returned as the specified resultType. |
| * <p>Example: |
| * <blockquote><pre> |
| * TopLink: reportQuery.addCount("Count", getExpressionBuilder().get("id"), Integer.class); |
| * SQL: SELECT COUNT (t0.EMP_ID) FROM EMPLOYEE t0, ... |
| * </pre></blockquote> |
| * <p>Example: counting only distinct values of an attribute. |
| * <blockquote><pre> |
| * TopLink: reportQuery.addCount("Count", getExpressionBuilder().get("address").distinct()); |
| * SQL: SELECT COUNT (DISTINCT t0.ADDR_ID) FROM EMPLOYEE t0, ... |
| * </pre></blockquote> |
| * objectAttributes can be specified also, even accross many to many |
| * mappings. |
| * @see #addCount() |
| */ |
| public void addCount(String itemName, Expression attributeExpression, Class resultType) { |
| addItem(itemName, attributeExpression.count(), resultType); |
| } |
| |
| /** |
| * ADVANCED: |
| * Add the function against the attribute expression to be included in the result. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * Example: reportQuery.addFunctionItem("average", expBuilder.get("salary"), "average"); |
| */ |
| public void addFunctionItem(String itemName, Expression attributeExpression, String functionName) { |
| Expression functionExpression = attributeExpression; |
| functionExpression = attributeExpression.getFunction(functionName); |
| |
| ReportItem item = new ReportItem(itemName, functionExpression); |
| addItem(item); |
| |
| //Bug2804042 Must un-prepare if prepared as the SQL may change. |
| setIsPrepared(false); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the attribute to the group by expressions. |
| * This will group the result set on that attribute and is normally used in conjunction with aggregation functions. |
| * Example: reportQuery.addGrouping("lastName") |
| */ |
| public void addGrouping(String attributeName) { |
| addGrouping(getExpressionBuilder().get(attributeName)); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the attribute expression to the group by expressions. |
| * This will group the result set on that attribute and is normally used in conjunction with aggregation functions. |
| * Example: reportQuery.addGrouping(expBuilder.get("address").get("country")) |
| */ |
| public void addGrouping(Expression expression) { |
| getGroupByExpressions().add(expression); |
| //Bug2804042 Must un-prepare if prepared as the SQL may change. |
| setIsPrepared(false); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the expression to the query to be used in the HAVING clause. |
| * 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. |
| * <p>Example: |
| * <p>reportQuery.setHavingExpression(expBuilder.get("address").get("country").equal("Canada")) |
| */ |
| public void setHavingExpression(Expression expression) { |
| havingExpression = expression; |
| setIsPrepared(false); |
| } |
| |
| /** |
| * INTERNAL: |
| * Method used to abstract addToConstructorItem behavour from the public addItem methods |
| */ |
| private void addItem(ReportItem item){ |
| if (this.addToConstructorItem && (getItems().size() > 0) && (getItems().get(getItems().size() - 1).isConstructorItem())) { |
| ((ConstructorReportItem)getItems().get(getItems().size() - 1)).addItem(item); |
| } else { |
| getItems().add(item); |
| } |
| //Bug2804042 Must un-prepare if prepared as the SQL may change. |
| setIsPrepared(false); |
| } |
| |
| /** |
| * ADVANCED: |
| * Add the expression value to be included in the result. |
| * EXAMPLE: reportQuery.addItem("name", expBuilder.get("firstName").toUpperCase()); |
| */ |
| public void addItem(String itemName, Expression attributeExpression) { |
| ReportItem item = new ReportItem(itemName, attributeExpression); |
| addItem(item); |
| |
| //Bug2804042 Must un-prepare if prepared as the SQL may change. |
| setIsPrepared(false); |
| } |
| |
| /** |
| * ADVANCED: |
| * Add the expression value to be included in the result. |
| * EXAMPLE: reportQuery.addItem("name", expBuilder.get("firstName").toUpperCase()); |
| */ |
| public void addItem(String itemName, Expression attributeExpression, List joinedExpressions) { |
| ReportItem item = new ReportItem(itemName, attributeExpression); |
| if (joinedExpressions != null && ! joinedExpressions.isEmpty()){ |
| item.getJoinedAttributeManager().setJoinedAttributeExpressions_(joinedExpressions); |
| } |
| addItem(item); |
| } |
| |
| /** |
| * INTERNAL: |
| * Add the expression value to be included in the result. |
| * EXAMPLE: reportQuery.addItem("name", expBuilder.get("firstName").toUpperCase()); |
| * The resultType can be specified to support EJBQL that adheres to the |
| * EJB 3.0 spec. |
| */ |
| protected void addItem(String itemName, Expression attributeExpression, Class resultType) { |
| ReportItem item = new ReportItem(itemName, attributeExpression); |
| item.setResultType(resultType); |
| addItem(item); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the maximum value of the attribute to be included in the result. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * EXAMPLE: reportQuery.addMaximum("salary"); |
| */ |
| public void addMaximum(String itemName) { |
| addMaximum(itemName, getExpressionBuilder().get(itemName)); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the maximum value of the attribute to be included in the result. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * EXAMPLE: reportQuery.addMaximum("salary", Integer.class); |
| */ |
| public void addMaximum(String itemName, Class resultType) { |
| addMaximum(itemName, getExpressionBuilder().get(itemName), resultType); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the maximum value of the attribute to be included in the result. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * EXAMPLE: reportQuery.addMaximum("managerSalary", expBuilder.get("manager").get("salary")); |
| */ |
| public void addMaximum(String itemName, Expression attributeExpression) { |
| addItem(itemName, attributeExpression.maximum()); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the maximum value of the attribute to be included in the result. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * EXAMPLE: reportQuery.addMaximum("managerSalary", expBuilder.get("manager").get("salary"), Integer.class); |
| */ |
| public void addMaximum(String itemName, Expression attributeExpression, Class resultType) { |
| addItem(itemName, attributeExpression.maximum(), resultType); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the minimum value of the attribute to be included in the result. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * EXAMPLE: reportQuery.addMinimum("salary"); |
| */ |
| public void addMinimum(String itemName) { |
| addMinimum(itemName, getExpressionBuilder().get(itemName)); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the minimum value of the attribute to be included in the result. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * EXAMPLE: reportQuery.addMinimum("salary", Integer.class); |
| */ |
| public void addMinimum(String itemName, Class resultType) { |
| addMinimum(itemName, getExpressionBuilder().get(itemName), resultType); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the minimum value of the attribute to be included in the result. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * EXAMPLE: reportQuery.addMinimum("managerSalary", expBuilder.get("manager").get("salary")); |
| */ |
| public void addMinimum(String itemName, Expression attributeExpression) { |
| addItem(itemName, attributeExpression.minimum()); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the minimum value of the attribute to be included in the result. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * EXAMPLE: reportQuery.addMinimum("managerSalary", expBuilder.get("manager").get("salary"), Integer.class); |
| */ |
| public void addMinimum(String itemName, Expression attributeExpression, Class resultType) { |
| addItem(itemName, attributeExpression.minimum(), resultType); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the standard deviation value of the attribute to be included in the result. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * EXAMPLE: reportQuery.addStandardDeviation("salary"); |
| */ |
| public void addStandardDeviation(String itemName) { |
| addStandardDeviation(itemName, getExpressionBuilder().get(itemName)); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the standard deviation value of the attribute to be included in the result. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * EXAMPLE: reportQuery.addStandardDeviation("managerSalary", expBuilder.get("manager").get("salary")); |
| */ |
| public void addStandardDeviation(String itemName, Expression attributeExpression) { |
| addItem(itemName, attributeExpression.standardDeviation()); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the sum value of the attribute to be included in the result. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * EXAMPLE: reportQuery.addSum("salary"); |
| */ |
| public void addSum(String itemName) { |
| addSum(itemName, getExpressionBuilder().get(itemName)); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the sum value of the attribute to be included in the result and |
| * return it as the specified resultType. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * EXAMPLE: reportQuery.addSum("salary", Float.class); |
| */ |
| public void addSum(String itemName, Class resultType) { |
| addSum(itemName, getExpressionBuilder().get(itemName), resultType); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the sum value of the attribute to be included in the result. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * EXAMPLE: reportQuery.addSum("managerSalary", expBuilder.get("manager").get("salary")); |
| */ |
| public void addSum(String itemName, Expression attributeExpression) { |
| addItem(itemName, attributeExpression.sum()); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the sum value of the attribute to be included in the result and |
| * return it as the specified resultType. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * EXAMPLE: reportQuery.addSum("managerSalary", expBuilder.get("manager").get("salary"), Float.class); |
| */ |
| public void addSum(String itemName, Expression attributeExpression, Class resultType) { |
| addItem(itemName, attributeExpression.sum(), resultType); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the variance value of the attribute to be included in the result. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * EXAMPLE: reportQuery.addVariance("salary"); |
| */ |
| public void addVariance(String itemName) { |
| addVariance(itemName, getExpressionBuilder().get(itemName)); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the variance value of the attribute to be included in the result. |
| * Aggregation functions can be used with a group by, or on the entire result set. |
| * EXAMPLE: reportQuery.addVariance("managerSalary", expBuilder.get("manager").get("salary")); |
| */ |
| public void addVariance(String itemName, Expression attributeExpression) { |
| addItem(itemName, attributeExpression.variance()); |
| } |
| |
| /** |
| * PUBLIC: Call a constructor for the given class with the results of this query. |
| */ |
| public ConstructorReportItem beginAddingConstructorArguments(Class constructorClass){ |
| ConstructorReportItem citem = new ConstructorReportItem(constructorClass.getName()); |
| citem.setResultType(constructorClass); |
| //add directly to avoid addToConstructorItem behavior |
| getItems().add(citem); |
| //Bug2804042 Must un-prepare if prepared as the SQL may change. |
| setIsPrepared(false); |
| this.addToConstructorItem=true; |
| return citem; |
| } |
| /** |
| * PUBLIC: Call a constructor for the given class with the results of this query. |
| * @param constructorArgTypes - sets the argument types to be passed to the constructor. |
| */ |
| public ConstructorReportItem beginAddingConstructorArguments(Class constructorClass, Class[] constructorArgTypes){ |
| ConstructorReportItem citem =beginAddingConstructorArguments(constructorClass); |
| citem.setConstructorArgTypes(constructorArgTypes); |
| return citem; |
| } |
| |
| /** |
| * INTERNAL: |
| * By default return the row. |
| * Used by cursored stream. |
| */ |
| @Override |
| public Object buildObject(AbstractRecord row) { |
| //Bug 445132 : Avoid NPE. |
| Vector v = new Vector(); |
| v.add(row); |
| return buildObject(row, v); |
| } |
| |
| /** |
| * INTERNAL: |
| * Construct a result from a row. Either return a ReportQueryResult or just the attribute. |
| * @param toManyJoinData All rows fetched by query. It is required to be not null. |
| */ |
| public Object buildObject(AbstractRecord row, Vector toManyJoinData) { |
| ReportQueryResult reportQueryResult = new ReportQueryResult(this, row, toManyJoinData); |
| //GF_ISSUE_395 |
| if (this.returnedKeys != null){ |
| if (this.returnedKeys.contains(reportQueryResult.getResultKey())){ |
| return ResultStatus.IGNORED; //distinguish between null values and thrown away duplicates |
| } else { |
| this.returnedKeys.add(reportQueryResult.getResultKey()); |
| } |
| } |
| //end GF_ISSUE_395 |
| if (shouldReturnSingleAttribute()) { |
| return reportQueryResult.getResults().get(0); |
| } else if (shouldReturnArray()) { |
| return reportQueryResult.toArray(); |
| } else if (shouldReturnWithoutReportQueryResult()) { |
| if (reportQueryResult.size() == 1) { |
| return reportQueryResult.getResults().get(0); |
| } else { |
| return reportQueryResult.toArray(); |
| } |
| } else if (shouldReturnSingleValue()) { |
| return reportQueryResult.getResults().get(0); |
| } else { |
| return reportQueryResult; |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Construct a container of ReportQueryResult from the rows. |
| * If only one result or value was asked for only return that. |
| */ |
| public Object buildObjects(Vector rows) { |
| if (shouldReturnSingleResult() || shouldReturnSingleValue()) { |
| if (rows.isEmpty()) { |
| return null; |
| } |
| return buildObject((AbstractRecord)rows.get(0), rows); |
| } |
| |
| ContainerPolicy containerPolicy = getContainerPolicy(); |
| int size = rows.size(); |
| Object reportResults = containerPolicy.containerInstance(size); |
| // GF_ISSUE_395 |
| if (shouldDistinctBeUsed()){ |
| this.returnedKeys = new HashSet(size); |
| } |
| //end GF_ISSUE |
| //If only the attribute is desired, then buildObject will only get the first attribute each time |
| for (int index = 0; index < size; index++) { |
| // GF_ISSUE_395 |
| Object result = buildObject((AbstractRecord)rows.get(index), rows); |
| if (result != ResultStatus.IGNORED) { |
| containerPolicy.addInto(result, reportResults, this.session); |
| } |
| //end GF_ISSUE |
| } |
| if (shouldCacheQueryResults()) { |
| setTemporaryCachedQueryResults(reportResults); |
| } |
| return reportResults; |
| } |
| |
| /** |
| * INTERNAL: |
| * The cache check is done before the prepare as a hit will not require the work to be done. |
| */ |
| @Override |
| protected Object checkEarlyReturnLocal(AbstractSession session, AbstractRecord translationRow) { |
| // Check for in-memory only query. |
| if (shouldCheckCacheOnly()) { |
| throw QueryException.cannotSetShouldCheckCacheOnlyOnReportQuery(); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Check to see if a custom query should be used for this query. |
| * This is done before the query is copied and prepared/executed. |
| * null means there is none. |
| */ |
| @Override |
| protected DatabaseQuery checkForCustomQuery(AbstractSession session, AbstractRecord translationRow) { |
| return null; |
| } |
| |
| /** |
| * INTERNAL: |
| * Clone the query. |
| */ |
| @Override |
| public Object clone() { |
| ReportQuery cloneQuery = (ReportQuery)super.clone(); |
| cloneQuery.items = new ArrayList<>(this.items.size()); |
| |
| for (ReportItem item : this.items) { |
| ReportItem newItem = (ReportItem)item.clone(); |
| if (item.getJoinedAttributeManagerInternal() != null){ |
| JoinedAttributeManager manager = item.getJoinedAttributeManager().clone(); |
| manager.setBaseQuery(cloneQuery); |
| newItem.setJoinedAttributeManager(manager); |
| } |
| cloneQuery.addItem(newItem); |
| } |
| |
| if (this.groupByExpressions != null) { |
| cloneQuery.groupByExpressions = new ArrayList<>(this.groupByExpressions); |
| } |
| |
| return cloneQuery; |
| } |
| |
| /** |
| * INTERNAL: Required for a very special case of bug 2612185: |
| * ReportItems from parallelExpressions, on a ReportQuery which is a subQuery, |
| * which is being batch read. |
| * In a batch query the selection criteria is effectively cloned twice, meaning |
| * the ReportItems need to be cloned an extra time also to stay in sync. |
| * Each call to copiedVersionFrom() will take O(1) time as the expression was |
| * already cloned. |
| */ |
| public void copyReportItems(Map alreadyDone) { |
| this.items = new ArrayList<>(this.items); |
| for (int i = this.items.size() - 1; i >= 0; i--) { |
| ReportItem item = this.items.get(i); |
| Expression expression = item.getAttributeExpression(); |
| if ((expression != null) && (alreadyDone.get(expression.getBuilder()) != null)) { |
| expression = expression.copiedVersionFrom(alreadyDone); |
| } |
| this.items.set(i, new ReportItem(item.getName(), expression)); |
| } |
| if (this.groupByExpressions != null) { |
| this.groupByExpressions = new ArrayList<>(this.groupByExpressions); |
| for (int i = this.groupByExpressions.size() - 1; i >= 0; i--) { |
| Expression item = this.groupByExpressions.get(i); |
| if (alreadyDone.get(item.getBuilder()) != null) { |
| this.groupByExpressions.set(i, item.copiedVersionFrom(alreadyDone)); |
| } |
| } |
| } |
| if (this.havingExpression != null) { |
| this.havingExpression = this.havingExpression.copiedVersionFrom(alreadyDone); |
| } |
| if (this.orderByExpressions != null) { |
| for (int i = this.orderByExpressions.size() - 1; i >= 0; i--) { |
| Expression item = this.orderByExpressions.get(i); |
| if (alreadyDone.get(item.getBuilder()) != null) { |
| this.orderByExpressions.set(i, item.copiedVersionFrom(alreadyDone)); |
| } |
| } |
| } |
| } |
| |
| /** |
| * PUBLIC: |
| * Set if the query results should contain the primary keys or each associated object. |
| * This make retrieving the real object easier. |
| * By default they are not retrieved. |
| */ |
| public void dontRetrievePrimaryKeys() { |
| setShouldRetrievePrimaryKeys(false); |
| //Bug2804042 Must un-prepare if prepared as the SQL may change. |
| setIsPrepared(false); |
| } |
| |
| /** |
| * PUBLIC: |
| * Don't simplify the result by returning the single attribute. Wrap in a ReportQueryResult. |
| */ |
| public void dontReturnSingleAttribute() { |
| if (shouldReturnSingleAttribute()) { |
| this.returnChoice = 0; |
| } |
| } |
| |
| /** |
| * PUBLIC: |
| * Simplifies the result by only returning the first result. |
| * This can be used if it known that only one row is returned by the report query. |
| */ |
| public void dontReturnSingleResult() { |
| if (shouldReturnSingleResult()) { |
| this.returnChoice = 0; |
| } |
| } |
| |
| /** |
| * PUBLIC: |
| * Simplifies the result by only returning a single value. |
| * This can be used if it known that only one row is returned by the report query and only a single item is added |
| * to the report. |
| */ |
| public void dontReturnSingleValue() { |
| if (shouldReturnSingleValue()) { |
| this.returnChoice = 0; |
| } |
| } |
| |
| /** |
| * PUBLIC: |
| * Simplifies the result by only returning a single value. |
| * This can be used if it known that only one row is returned by the report query and only a single item is added |
| * to the report. |
| */ |
| public void dontReturnWithoutReportQueryResult() { |
| if (shouldReturnWithoutReportQueryResult()) { |
| this.returnChoice = 0; |
| } |
| } |
| |
| /** |
| * PUBLIC: |
| * Used in conjunction with beginAddingConstructorArguments to signal that expressions should no longer be |
| * be added to the collection used in the constructor. |
| */ |
| public void endAddingToConstructorItem(){ |
| this.addToConstructorItem = false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Execute the query. |
| * Get the rows and build the objects or report data from the rows. |
| * @exception DatabaseException - an error has occurred on the database |
| * @return either collection of objects, or report data resulting from execution of query. |
| */ |
| @Override |
| public Object executeDatabaseQuery() throws DatabaseException { |
| // ensure a pessimistic locking query will go down the write connection |
| if (isLockQuery() && getSession().isUnitOfWork()) { |
| UnitOfWorkImpl unitOfWork = (UnitOfWorkImpl)getSession(); |
| // Note if a nested unit of work this will recursively start a |
| // transaction early on the parent also. |
| if (isLockQuery()) { |
| if ((!unitOfWork.getCommitManager().isActive()) && (!unitOfWork.wasTransactionBegunPrematurely())) { |
| unitOfWork.beginTransaction(); |
| unitOfWork.setWasTransactionBegunPrematurely(true); |
| } |
| } |
| } |
| if (getContainerPolicy().overridesRead()) { |
| return getContainerPolicy().execute(); |
| } |
| |
| if (getQueryId() == 0) { |
| setQueryId(getSession().getNextQueryId()); |
| } |
| setExecutionTime(System.currentTimeMillis()); |
| if (getDescriptor().isDescriptorForInterface()) { |
| return getDescriptor().getInterfacePolicy().selectAllObjectsUsingMultipleTableSubclassRead(this); |
| } |
| |
| return buildObjects(getQueryMechanism().selectAllReportQueryRows()); |
| } |
| |
| /** |
| * INTERNAL: |
| * Extract the correct query result from the transporter. |
| */ |
| @Override |
| public Object extractRemoteResult(Transporter transporter) { |
| return transporter.getObject(); |
| } |
| |
| /** |
| * INTERNAL: |
| * Return the group bys. |
| */ |
| public List<Expression> getGroupByExpressions() { |
| if (this.groupByExpressions == null) { |
| this.groupByExpressions = new ArrayList<>(); |
| } |
| return this.groupByExpressions; |
| } |
| |
| /** |
| * INTERNAL: |
| * Return if any group bys exist, allow lazy initialization. |
| * This should be called before calling getGroupByExpressions(). |
| */ |
| public boolean hasGroupByExpressions() { |
| return (this.groupByExpressions != null) && (!this.groupByExpressions.isEmpty()); |
| } |
| |
| /** |
| * INTERNAL: |
| * Set the group bys. |
| */ |
| public void setGroupByExpressions(List<Expression> groupByExpressions) { |
| this.groupByExpressions = groupByExpressions; |
| } |
| |
| /** |
| * INTERNAL: |
| * Return the Having expression. |
| */ |
| public Expression getHavingExpression() { |
| return havingExpression; |
| } |
| |
| /** |
| * INTERNAL: |
| * return a collection of expressions if PK's are used. |
| */ |
| public Vector getQueryExpressions() { |
| Vector fieldExpressions = NonSynchronizedVector.newInstance(getItems().size()); |
| |
| if (shouldSelectValue1()) { |
| Expression one = new ConstantExpression(1, new ExpressionBuilder()); |
| this.addItem("one", one); |
| this.dontUseDistinct(); |
| fieldExpressions.addElement(one); |
| } else |
| // For bug 3115576 and an EXISTS subquery only need to return a single field. |
| if (shouldRetrieveFirstPrimaryKey()) { |
| if (!getDescriptor().getPrimaryKeyFields().isEmpty()) { |
| fieldExpressions.addElement(getDescriptor().getPrimaryKeyFields().get(0)); |
| } |
| } |
| if (shouldRetrievePrimaryKeys()) { |
| fieldExpressions.addAll(getDescriptor().getPrimaryKeyFields()); |
| } |
| |
| return fieldExpressions; |
| } |
| |
| /** |
| * INTERNAL: |
| * Returns the specific default redirector for this query type. There are numerous default query redirectors. |
| * See ClassDescriptor for their types. |
| */ |
| @Override |
| protected QueryRedirector getDefaultRedirector(){ |
| return descriptor.getDefaultReportQueryRedirector(); |
| } |
| |
| /** |
| * INTERNAL: |
| * @return ReportItems defining the attributes to be read. |
| */ |
| public List<ReportItem> getItems() { |
| return items; |
| } |
| |
| /** |
| * INTERNAL: |
| * @return ReportItems with the name |
| */ |
| public ReportItem getItem(String name) { |
| for (ReportItem item : this.items) { |
| if (item.getName().equals(name)) { |
| return item; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * INTERNAL: |
| * Set the ReportQueryItems defining the attributes to be read. |
| */ |
| public void setItems(List<ReportItem> items) { |
| this.items = items; |
| } |
| |
| /** |
| * INTERNAL: |
| * Sets a jakarta.persistence.LockModeType to used with this queries execution. |
| * The valid types are: |
| * - WRITE |
| * - READ |
| * - OPTIMISTIC |
| * - OPTIMISTIC_FORCE_INCREMENT |
| * - PESSIMISTIC |
| * - PESSIMISTIC_FORCE_INCREMENT |
| * - NONE |
| * Setting a null type will do nothing. |
| * @return returns a failure flag indicating that we were UNABLE to set the |
| * lock mode because of validation. Callers to this method should check the |
| * return value and throw the necessary exception. |
| */ |
| @Override |
| public boolean setLockModeType(String lockModeType, AbstractSession session) { |
| if (lockModeType != null) { |
| if (super.setLockModeType(lockModeType, session)) { |
| return true; |
| } else { |
| // When a lock mode is used, we must validate that our report items |
| // all have a version locking policy if the lock is set to anything |
| // but PESSIMISTIC and NONE. Validate only those report items that |
| // are expression builders (ignoring the others) |
| if (! lockModeType.equals(PESSIMISTIC_READ) && ! lockModeType.equals(PESSIMISTIC_WRITE) && ! lockModeType.equals(NONE)) { |
| for (ReportItem reportItem : getItems()) { |
| if (reportItem.getAttributeExpression() != null && reportItem.getAttributeExpression().isExpressionBuilder()) { |
| OptimisticLockingPolicy lockingPolicy = reportItem.getDescriptor().getOptimisticLockingPolicy(); |
| |
| if (lockingPolicy == null || !(lockingPolicy instanceof VersionLockingPolicy)) { |
| return true; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Clear the ReportQueryItems |
| */ |
| public void clearItems() { |
| this.items = new ArrayList<>(); |
| setIsPrepared(false); |
| } |
| |
| /** |
| * INTERNAL: |
| * Lazily initialize and return the names of the items requested for use in each result object. |
| */ |
| public List<String> getNames() { |
| if (this.names == null) { |
| this.names = new ArrayList<>(); |
| for (ReportItem item : getItems()) { |
| this.names.add(item.getName()); |
| } |
| } |
| return this.names; |
| } |
| |
| /** |
| * INTERNAL: |
| * Set the item names. |
| */ |
| protected void setNames(List<String> names) { |
| this.names = names; |
| } |
| |
| /** |
| * PUBLIC: |
| * Return if this is a report query. |
| */ |
| @Override |
| public boolean isReportQuery() { |
| return true; |
| } |
| |
| /** |
| * INTERNAL: |
| * Prepare the receiver for execution in a session. |
| * Initialize each item with its DTF mapping |
| */ |
| @Override |
| protected void prepare() throws QueryException { |
| if (prepareFromCachedQuery()) { |
| return; |
| } |
| // Oct 19, 2000 JED |
| // Added exception to be thrown if no attributes have been added to the query |
| if (getItems().size() > 0) { |
| try { |
| for (ReportItem item : getItems()) { |
| item.initialize(this); |
| } |
| } catch (QueryException exception) { |
| exception.setQuery(this); |
| throw exception; |
| } |
| } else { |
| if ((!shouldRetrievePrimaryKeys()) && (!shouldRetrieveFirstPrimaryKey()) && !(shouldSelectValue1())) { |
| throw QueryException.noAttributesForReportQuery(this); |
| } |
| } |
| |
| super.prepare(); |
| |
| } |
| |
| /** |
| * INTERNAL: |
| * ReportQuery doesn't support fetch groups. |
| */ |
| @Override |
| public void prepareFetchGroup() throws QueryException { |
| if(this.fetchGroup != null || this.fetchGroupName != null) { |
| throw QueryException.fetchGroupNotSupportOnReportQuery(); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Prepare the query from the prepared query. |
| * This allows a dynamic query to prepare itself directly from a prepared query instance. |
| * This is used in the EJBQL parse cache to allow preparsed queries to be used to prepare |
| * dynamic queries. |
| * This only copies over properties that are configured through EJBQL. |
| */ |
| @Override |
| public void prepareFromQuery(DatabaseQuery query) { |
| super.prepareFromQuery(query); |
| if (query.isReportQuery()) { |
| ReportQuery reportQuery = (ReportQuery)query; |
| this.names = reportQuery.names; |
| this.items = reportQuery.items; |
| this.groupByExpressions = reportQuery.groupByExpressions; |
| this.havingExpression = reportQuery.havingExpression; |
| this.returnChoice = reportQuery.returnChoice; |
| this.returnedKeys = reportQuery.returnedKeys; |
| this.shouldRetrievePrimaryKeys = reportQuery.shouldRetrievePrimaryKeys; |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Return if the query is equal to the other. |
| * This is used to allow dynamic expression query SQL to be cached. |
| */ |
| @Override |
| public boolean equals(Object object) { |
| if (this == object) { |
| return true; |
| } |
| if (!super.equals(object)) { |
| return false; |
| } |
| ReportQuery query = (ReportQuery) object; |
| List items = getItems(); |
| List otherItems = query.getItems(); |
| int size = items.size(); |
| if (size != otherItems.size()) { |
| return false; |
| } |
| for (int index = 0; index < size; index++) { |
| if (!items.get(index).equals(otherItems.get(index))) { |
| return false; |
| } |
| } |
| if (hasGroupByExpressions() && query.hasGroupByExpressions()) { |
| List groupBys = getGroupByExpressions(); |
| List otherGroupBys = query.getGroupByExpressions(); |
| size = groupBys.size(); |
| if (size != otherGroupBys.size()) { |
| return false; |
| } |
| for (int index = 0; index < size; index++) { |
| if (!groupBys.get(index).equals(otherGroupBys.get(index))) { |
| return false; |
| } |
| } |
| } else if (hasGroupByExpressions() || query.hasGroupByExpressions()) { |
| return false; |
| } |
| if ((getHavingExpression() != query.getHavingExpression()) |
| && (getHavingExpression() != null) |
| && (!getHavingExpression().equals(query.getHavingExpression()))) { |
| return false; |
| } |
| if (this.returnChoice != query.returnChoice) { |
| return false; |
| } |
| if (this.shouldRetrievePrimaryKeys != query.shouldRetrievePrimaryKeys) { |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * INTERNAL: |
| * Prepare a report query with a count defined on an object attribute. |
| * Added to fix bug 3268040, addCount(objectAttribute) not supported. |
| */ |
| protected void prepareObjectAttributeCount(Map clonedExpressions) { |
| prepareObjectAttributeCount(getItems(), clonedExpressions); |
| } |
| |
| /** |
| * JPQL allows count([distinct] e), where e can be an object, not just a single field, |
| * however the database only allows a single field, so object needs to be translated to a single field. |
| * If the descriptor has a single pk, it is used, otherwise any pk is used if distinct, otherwise a subselect is used. |
| * If the object was obtained through an outer join, then the subselect also will not work, so an error is thrown. |
| */ |
| private void prepareObjectAttributeCount(List<ReportItem> items, Map clonedExpressions) { |
| int numOfReportItems = items.size(); |
| //gf675: need to loop through all items to fix all count(..) instances |
| for (int i =0;i<numOfReportItems; i++){ |
| ReportItem item = items.get(i); |
| if (item == null) { |
| continue; |
| } else if (item instanceof ConstructorReportItem) { |
| // recursive call to process child ReportItems |
| prepareObjectAttributeCount(((ConstructorReportItem)item).getReportItems(), clonedExpressions); |
| } else if (item.getAttributeExpression() instanceof FunctionExpression) { |
| FunctionExpression count = (FunctionExpression)item.getAttributeExpression(); |
| count.prepareObjectAttributeCount(null, item, this, clonedExpressions); |
| } |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Prepare the mechanism. |
| */ |
| @Override |
| protected void prepareSelectAllRows() { |
| prepareObjectAttributeCount(null); |
| |
| getQueryMechanism().prepareReportQuerySelectAllRows(); |
| } |
| |
| /** |
| * INTERNAL: |
| * Prepare the receiver for being printed inside a subselect. |
| * This prepares the statement but not the call. |
| */ |
| public synchronized void prepareSubSelect(AbstractSession session, AbstractRecord translationRow, Map clonedExpressions) throws QueryException { |
| if (isPrepared()) { |
| return; |
| } |
| |
| setIsPrepared(true); |
| setSession(session); |
| setTranslationRow(translationRow); |
| |
| checkDescriptor(getSession()); |
| |
| if (descriptor.isAggregateDescriptor()) { |
| // Not allowed |
| throw QueryException.aggregateObjectCannotBeDeletedOrWritten(descriptor, this); |
| } |
| |
| try { |
| for (ReportItem item : getItems()) { |
| item.initialize(this); |
| } |
| } catch (QueryException exception) { |
| exception.setQuery(this); |
| throw exception; |
| } |
| |
| prepareObjectAttributeCount(clonedExpressions); |
| |
| getQueryMechanism().prepareReportQuerySubSelect(); |
| |
| setSession(null); |
| setTranslationRow(null); |
| } |
| |
| /** |
| * INTERNAL: |
| * replace the value holders in the specified result object(s) |
| */ |
| @Override |
| public Map replaceValueHoldersIn(Object object, RemoteSessionController controller) { |
| // do nothing, since report queries do not return domain objects |
| return null; |
| } |
| |
| /** |
| * PUBLIC: |
| * Set if the query results should contain the primary keys or each associated object. |
| * This make retrieving the real object easier. |
| * By default they are not retrieved. |
| */ |
| public void retrievePrimaryKeys() { |
| setShouldRetrievePrimaryKeys(true); |
| //Bug2804042 Must un-prepare if prepared as the SQL may change. |
| setIsPrepared(false); |
| } |
| |
| /** |
| * PUBLIC: |
| * Return the return type. |
| */ |
| public int getReturnType() { |
| return returnChoice; |
| } |
| |
| /** |
| * PUBLIC: |
| * Set the return type. |
| * This can be one of several constants, |
| * <ul> |
| * <li>ShouldReturnReportResult - return {@literal List<ReportQueryResult>} : ReportQueryResult (Map) of each row is returned. |
| * <li>ShouldReturnSingleResult - return ReportQueryResult : Only first row is returned. |
| * <li>ShouldReturnSingleAttribute - return {@literal List<Object>} : Only first column of (all) rows are returned. |
| * <li>ShouldReturnSingleValue - return Object : Only first value of first row is returned. |
| * <li>ShouldReturnWithoutReportQueryResult - return {@literal List<Object[]>} : Array of each row is returned. |
| * </ul> |
| */ |
| public void setReturnType(int returnChoice) { |
| this.returnChoice = returnChoice; |
| } |
| |
| /** |
| * PUBLIC: |
| * Simplify the result by returning a single attribute. Don't wrap in a ReportQueryResult. |
| */ |
| public void returnSingleAttribute() { |
| returnChoice = ShouldReturnSingleAttribute; |
| } |
| |
| /** |
| * PUBLIC: |
| * Simplifies the result by only returning the first result. |
| * This can be used if it known that only one row is returned by the report query. |
| */ |
| public void returnSingleResult() { |
| returnChoice = ShouldReturnSingleResult; |
| } |
| |
| /** |
| * PUBLIC: |
| * Simplifies the result by only returning a single value. |
| * This can be used if it known that only one row is returned by the report query and only a single item is added |
| * to the report. |
| */ |
| public void returnSingleValue() { |
| returnChoice = ShouldReturnSingleValue; |
| } |
| |
| /** |
| * PUBLIC: |
| * Simplifies the result by only returning a single value. |
| * This can be used if it known that only one row is returned by the report query and only a single item is added |
| * to the report. |
| */ |
| public void returnWithoutReportQueryResult() { |
| this.returnChoice = ShouldReturnWithoutReportQueryResult; |
| } |
| |
| /** |
| * PUBLIC: |
| * Simplifies the result by only returning a single value. |
| * This can be used if it known that only one row is returned by the report query and only a single item is added |
| * to the report. |
| */ |
| public void selectValue1() { |
| returnChoice = ShouldSelectValue1; |
| } |
| |
| /** |
| * PUBLIC: |
| * Set if the query results should contain the primary keys or each associated object. |
| * This make retrieving the real object easier. |
| * By default they are not retrieved. |
| */ |
| public void setShouldRetrievePrimaryKeys(boolean shouldRetrievePrimaryKeys) { |
| this.shouldRetrievePrimaryKeys = (shouldRetrievePrimaryKeys ? FULL_PRIMARY_KEY : NO_PRIMARY_KEY); |
| } |
| |
| /** |
| * ADVANCED: |
| * Sets if the query results should contain the first primary key of each associated object. |
| * Usefull if this is an EXISTS subquery and you don't care what fields are returned |
| * so long as it is a single field. |
| * The default value is false. |
| * This should only be used with a subquery. |
| */ |
| public void setShouldRetrieveFirstPrimaryKey(boolean shouldRetrieveFirstPrimaryKey) { |
| this.shouldRetrievePrimaryKeys = (shouldRetrieveFirstPrimaryKey ? FIRST_PRIMARY_KEY : NO_PRIMARY_KEY); |
| } |
| |
| /** |
| * PUBLIC: |
| * Simplifies the result by only returning the attribute (as opposed to wrapping in a ReportQueryResult). |
| * This can be used if it is known that only one attribute is returned by the report query. |
| */ |
| public void setShouldReturnSingleAttribute(boolean newChoice) { |
| if (newChoice) { |
| returnSingleAttribute(); |
| } else { |
| dontReturnSingleAttribute(); |
| } |
| } |
| |
| /** |
| * PUBLIC: |
| * Simplifies the result by only returning the first result. |
| * This can be used if it known that only one row is returned by the report query. |
| */ |
| public void setShouldReturnSingleResult(boolean newChoice) { |
| if (newChoice) { |
| returnSingleResult(); |
| } else { |
| dontReturnSingleResult(); |
| } |
| } |
| |
| /** |
| * PUBLIC: |
| * Simplifies the result by only returning a single value. |
| * This can be used if it known that only one row is returned by the report query and only a single item is added |
| * to the report. |
| */ |
| public void setShouldReturnSingleValue(boolean newChoice) { |
| if (newChoice) { |
| returnSingleValue(); |
| } else { |
| dontReturnSingleValue(); |
| } |
| } |
| |
| /** |
| * PUBLIC: |
| * Simplifies the result by returning a nested list instead of the ReportQueryResult. |
| * This is used by EJB 3. |
| */ |
| public void setShouldReturnWithoutReportQueryResult(boolean newChoice) { |
| if (newChoice) { |
| returnWithoutReportQueryResult(); |
| } else { |
| dontReturnWithoutReportQueryResult(); |
| } |
| } |
| |
| /** |
| * PUBLIC: |
| * Return if the query results should contain the primary keys or each associated object. |
| * This make retrieving the real object easier. |
| */ |
| public boolean shouldRetrievePrimaryKeys() { |
| return this.shouldRetrievePrimaryKeys == FULL_PRIMARY_KEY; |
| } |
| |
| /** |
| * PUBLIC: |
| * Return if the query results should contain the first primary key of each associated object. |
| * Usefull if this is an EXISTS subquery and you don't care what fields are returned |
| * so long as it is a single field. |
| */ |
| public boolean shouldRetrieveFirstPrimaryKey() { |
| return this.shouldRetrievePrimaryKeys == FIRST_PRIMARY_KEY; |
| } |
| |
| /** |
| * PUBLIC: |
| * Answer if we are only returning the attribute (as opposed to wrapping in a ReportQueryResult). |
| * This can be used if it is known that only one attribute is returned by the report query. |
| */ |
| public boolean shouldReturnSingleAttribute() { |
| return this.returnChoice == ShouldReturnSingleAttribute; |
| } |
| |
| /** |
| * PUBLIC: |
| * Simplifies the result by only returning the first result. |
| * This can be used if it known that only one row is returned by the report query. |
| */ |
| public boolean shouldReturnSingleResult() { |
| return this.returnChoice == ShouldReturnSingleResult; |
| } |
| |
| /** |
| * PUBLIC: |
| * Simplifies the result by only returning a single value. |
| * This can be used if it known that only one row is returned by the report query and only a single item is added |
| * to the report. |
| */ |
| public boolean shouldReturnSingleValue() { |
| return this.returnChoice == ShouldReturnSingleValue; |
| } |
| |
| /** |
| * PUBLIC: |
| * Simplifies the result by returning a nested list instead of the ReportQueryResult. |
| * This is used by EJB 3. |
| */ |
| public boolean shouldReturnWithoutReportQueryResult() { |
| return this.returnChoice == ShouldReturnWithoutReportQueryResult; |
| } |
| |
| /** |
| * PUBLIC: |
| * Returns true if results should be returned as an Object array. |
| */ |
| public boolean shouldReturnArray() { |
| return this.returnChoice == ShouldReturnArray; |
| } |
| |
| /** |
| * PUBLIC: |
| * Returns true if results should be returned as an Object array. |
| */ |
| public boolean shouldSelectValue1() { |
| return this.returnChoice == ShouldSelectValue1; |
| } |
| |
| } |