blob: bf9b074be37d16dc31a171f7d79f184a216f2610 [file] [log] [blame]
/*
* Copyright (c) 2006, 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
//
package org.eclipse.persistence.internal.jpa.jpql;
import org.eclipse.persistence.jpa.jpql.parser.CollectionExpression;
import org.eclipse.persistence.jpa.jpql.parser.EclipseLinkAnonymousExpressionVisitor;
import org.eclipse.persistence.jpa.jpql.parser.Expression;
import org.eclipse.persistence.jpa.jpql.parser.IdentificationVariable;
import org.eclipse.persistence.jpa.jpql.parser.NullExpression;
import org.eclipse.persistence.jpa.jpql.parser.ObjectExpression;
import org.eclipse.persistence.jpa.jpql.parser.ResultVariable;
import org.eclipse.persistence.jpa.jpql.parser.SelectClause;
import org.eclipse.persistence.jpa.jpql.parser.SelectStatement;
import org.eclipse.persistence.queries.ReadAllQuery;
import org.eclipse.persistence.queries.ReportQuery;
/**
* This visitor visits the select expression in order to create the correct {@link ReadAllQuery},
* which is either a {@link ReportQuery} or a {@link ReadAllQuery}.
*
* @version 2.5
* @since 2.3
* @author Pascal Filion
* @author John Bracken
*/
final class ReadAllQueryBuilder extends EclipseLinkAnonymousExpressionVisitor {
/**
* The query that was created based on the type of select clause.
*/
ReadAllQuery query;
/**
* The {@link JPQLQueryContext} is used to query information about the application metadata and
* cached information.
*/
private final JPQLQueryContext queryContext;
/**
* The {@link Expression} being visited.
*/
private SelectStatement selectStatement;
/**
* Creates a new <code>ReadAllQueryBuilder</code>.
*
* @param queryContext The context used to query information about the application metadata and
* cached information
*/
ReadAllQueryBuilder(JPQLQueryContext queryContext) {
super();
this.queryContext = queryContext;
}
private void initializeReadAllQuery() {
ReadAllQuery query = new ReadAllQuery();
query.dontUseDistinct();
this.query = query;
}
private void initializeReportQuery() {
ReportQuery query = new ReportQuery();
query.returnWithoutReportQueryResult();
query.dontUseDistinct();
this.query = query;
}
@Override
public void visit(CollectionExpression expression) {
// Multiple expressions in the select clause => ReportQuery
initializeReportQuery();
}
@Override
protected void visit(Expression expression) {
// Does not select an identification variable
// (e.g. projection or aggregate function) => ReportQuery
initializeReportQuery();
}
@Override
public void visit(IdentificationVariable expression) {
// Use ReadAllQuery if the variable of the SELECT clause expression is the base variable
// Example: ReadAllQuery = SELECT e FROM Employee e
// Example: ReportQuery = SELECT e FROM Department d JOIN d.employees e
String variableName = expression.getVariableName();
if (queryContext.isRangeIdentificationVariable(variableName)) {
if (selectStatement.hasGroupByClause() ||
selectStatement.hasHavingClause() ||
variableName != queryContext.getFirstDeclaration().getVariableName()) {
initializeReportQuery();
}
else {
initializeReadAllQuery();
}
}
else {
initializeReportQuery();
}
}
@Override
public void visit(NullExpression expression) {
// For from clause only JPQL the full object is always selected, so is ReadAllQuery.
initializeReadAllQuery();
}
@Override
public void visit(ObjectExpression expression) {
// Visit the identification variable directly
expression.getExpression().accept(this);
}
@Override
public void visit(ResultVariable expression) {
// Make sure to traverse the select expression since
// it has a result variable assigned to it
expression.getSelectExpression().accept(this);
}
@Override
public void visit(SelectClause expression) {
expression.getSelectExpression().accept(this);
}
@Override
public void visit(SelectStatement expression) {
this.selectStatement = expression;
expression.getSelectClause().accept(this);
}
}