/******************************************************************************* | |
* Copyright (c) 1998, 2013 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 v1.0 and Eclipse Distribution License v. 1.0 | |
* which accompanies this distribution. | |
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html | |
* and the Eclipse Distribution License is available at | |
* http://www.eclipse.org/org/documents/edl-v10.php. | |
* | |
* 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() | |
* @see #readObject(Class, Session) | |
* 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 | |
protected static final Boolean RESULT_IGNORED = Boolean.TRUE; | |
//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<ReportItem>(); | |
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 ConstructorReportItem - 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: | |
* <pre><blockquote> | |
* TopLink: reportQuery.addCount("id"); | |
* SQL: SELECT COUNT (t0.EMP_ID) FROM EMPLOYEE t0, ... | |
* </blockquote></pre> | |
* @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: | |
* <pre><blockquote> | |
* TopLink: reportQuery.addCount("id", Long.class); | |
* SQL: SELECT COUNT (t0.EMP_ID) FROM EMPLOYEE t0, ... | |
* </blockquote></pre> | |
* @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: | |
* <pre><blockquote> | |
* TopLink: reportQuery.addCount("Count", getExpressionBuilder().get("id")); | |
* SQL: SELECT COUNT (t0.EMP_ID) FROM EMPLOYEE t0, ... | |
* </blockquote></pre> | |
* <p>Example: counting only distinct values of an attribute. | |
* <pre><blockquote> | |
* TopLink: reportQuery.addCount("Count", getExpressionBuilder().get("address").distinct()); | |
* SQL: SELECT COUNT (DISTINCT t0.ADDR_ID) FROM EMPLOYEE t0, ... | |
* </blockquote></pre> | |
* 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: | |
* <pre><blockquote> | |
* TopLink: reportQuery.addCount("Count", getExpressionBuilder().get("id"), Integer.class); | |
* SQL: SELECT COUNT (t0.EMP_ID) FROM EMPLOYEE t0, ... | |
* </blockquote></pre> | |
* <p>Example: counting only distinct values of an attribute. | |
* <pre><blockquote> | |
* TopLink: reportQuery.addCount("Count", getExpressionBuilder().get("address").distinct()); | |
* SQL: SELECT COUNT (DISTINCT t0.ADDR_ID) FROM EMPLOYEE t0, ... | |
* </blockquote></pre> | |
* 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("managerSalary", expBuilder.get("manager").get("salary")); | |
*/ | |
public void addMaximum(String itemName, Expression attributeExpression) { | |
addItem(itemName, attributeExpression.maximum()); | |
} | |
/** | |
* 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("managerSalary", expBuilder.get("manager").get("salary")); | |
*/ | |
public void addMinimum(String itemName, Expression attributeExpression) { | |
addItem(itemName, attributeExpression.minimum()); | |
} | |
/** | |
* 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. | |
* @param constructorClass | |
*/ | |
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 constructorClass | |
* @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) { | |
return buildObject(row, (Vector)null); | |
} | |
/** | |
* INTERNAL: | |
* Construct a result from a row. Either return a ReportQueryResult or just the attribute. | |
*/ | |
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 RESULT_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 != RESULT_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<ReportItem>(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<Expression>(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<ReportItem>(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<Expression>(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<Expression>(); | |
} | |
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(new Integer(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 javax.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<ReportItem>(); | |
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<String>(); | |
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 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 = (ReportItem)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 List<ReportQueryResult> : ReportQueryResult (Map) of each row is returned. | |
* <li>ShouldReturnSingleResult - return ReportQueryResult : Only first row is returned. | |
* <li>ShouldReturnSingleAttribute - return 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 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; | |
} | |
} |