}
public String getQueryString(boolean countQuery) {
StringBuilder results = new StringBuilder();
PageControl pc = getPageControl(criteria);
results.append("SELECT ");
List<String> fetchFields = getFetchFields(criteria);
boolean useJoinFetch = projection == null && pc.isUnlimited() && !fetchFields.isEmpty();
if (countQuery) {
if (countProjection != null) {
//just use whatever we are told
results.append(countProjection).append(NL);
} else if (groupByClause == null) { // non-grouped method
// use count(*) instead of count(alias) due to https://bugzilla.redhat.com/show_bug.cgi?id=699842
results.append("COUNT(*)").append(NL);
} else {
// gets the count of the number of aggregate/grouped rows
// NOTE: this only works when the groupBy is a single element, as opposed to a list of elements
results.append("COUNT(DISTINCT ").append(groupByClause).append(")").append(NL);
}
} else {
if (projection == null) {
//we need to just return distinct results when using JOIN FETCH otherwise we might see duplicates
//in the result set and create discrepancy between the data query and the count query (which doesn't
//use the JOIN FETCH but only the WHERE clause).
if (useJoinFetch) {
results.append("DISTINCT ");
}
results.append(alias).append(NL);
} else {
results.append(projection).append(NL);
}
}
results.append("FROM ").append(className).append(' ').append(alias).append(NL);
if (!countQuery) {
/*
* don't fetch in the count query to avoid: "query specified join fetching,
* but the owner of the fetched association was not present in the select list"
*/
for (String fetchField : fetchFields) {
if (isPersistentBag(fetchField)) {
addPersistentBag(fetchField);
} else {
if (this.projection == null) {
/*
* if not altering the projection, join fetching can be used
* to retrieve the associated instance in the same SELECT
*
* We further avoid a JOIN FETCH when executing queries with limits.
* Such execution has performance problems that we solve by initializing the fields
* "manually" in the CriteriaQueryRunner and by defining a default batch fetch size in the
* persistence.xml.
*/
if (useJoinFetch) {
results.append("LEFT JOIN FETCH ").append(alias).append('.').append(fetchField).append(NL);
} else {
addJoinFetch(fetchField);
}
} else {
/*
* if the projection is altered (perhaps converting it into a constructor query), then all
* fields specified in the fetch must be in the explicit return list. this is not possible
* today with constructor queries, so any altered projection will implicitly disable fetching.
* instead, we'll record which fields need to be explicitly fetched after the primary query
* returns the bulk of the data, and use a similar methodology at the SLSB layer to eagerly
* load those before returning the PageList back to the caller.
*/
addJoinFetch(fetchField);
}
}
}
}
// figure out the 'LEFT JOIN's needed for 'ORDER BY' tokens
List<String> orderingFieldRequiredJoins = new ArrayList<String>();
List<String> orderingFieldTokens = new ArrayList<String>();
for (OrderingField orderingField : pc.getOrderingFields()) {
PageOrdering ordering = orderingField.getOrdering();
String fieldName = orderingField.getField();
String override = criteria.getJPQLSortOverride(fieldName);
String suffix = (override == null) ? fieldName : override;