org.eclipse.persistence.internal.jpa.jpql.ReportItemBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.eclipse.persistence.core Show documentation
Show all versions of org.eclipse.persistence.core Show documentation
EclipseLink build based upon Git transaction ecdf3c32c4
/*
* Copyright (c) 2006, 2019 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019 IBM Corporation. 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 java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.persistence.expressions.Expression;
import org.eclipse.persistence.jpa.jpql.ExpressionTools;
import org.eclipse.persistence.jpa.jpql.parser.AbsExpression;
import org.eclipse.persistence.jpa.jpql.parser.AbstractSelectClause;
import org.eclipse.persistence.jpa.jpql.parser.AdditionExpression;
import org.eclipse.persistence.jpa.jpql.parser.ArithmeticFactor;
import org.eclipse.persistence.jpa.jpql.parser.AvgFunction;
import org.eclipse.persistence.jpa.jpql.parser.CaseExpression;
import org.eclipse.persistence.jpa.jpql.parser.CastExpression;
import org.eclipse.persistence.jpa.jpql.parser.CoalesceExpression;
import org.eclipse.persistence.jpa.jpql.parser.CollectionExpression;
import org.eclipse.persistence.jpa.jpql.parser.CollectionValuedPathExpression;
import org.eclipse.persistence.jpa.jpql.parser.ConcatExpression;
import org.eclipse.persistence.jpa.jpql.parser.ConstructorExpression;
import org.eclipse.persistence.jpa.jpql.parser.CountFunction;
import org.eclipse.persistence.jpa.jpql.parser.DateTime;
import org.eclipse.persistence.jpa.jpql.parser.DivisionExpression;
import org.eclipse.persistence.jpa.jpql.parser.EclipseLinkAnonymousExpressionVisitor;
import org.eclipse.persistence.jpa.jpql.parser.EntryExpression;
import org.eclipse.persistence.jpa.jpql.parser.ExtractExpression;
import org.eclipse.persistence.jpa.jpql.parser.FunctionExpression;
import org.eclipse.persistence.jpa.jpql.parser.IdentificationVariable;
import org.eclipse.persistence.jpa.jpql.parser.IndexExpression;
import org.eclipse.persistence.jpa.jpql.parser.Join;
import org.eclipse.persistence.jpa.jpql.parser.KeyExpression;
import org.eclipse.persistence.jpa.jpql.parser.KeywordExpression;
import org.eclipse.persistence.jpa.jpql.parser.LengthExpression;
import org.eclipse.persistence.jpa.jpql.parser.LocateExpression;
import org.eclipse.persistence.jpa.jpql.parser.LowerExpression;
import org.eclipse.persistence.jpa.jpql.parser.MaxFunction;
import org.eclipse.persistence.jpa.jpql.parser.MinFunction;
import org.eclipse.persistence.jpa.jpql.parser.ModExpression;
import org.eclipse.persistence.jpa.jpql.parser.MultiplicationExpression;
import org.eclipse.persistence.jpa.jpql.parser.NullIfExpression;
import org.eclipse.persistence.jpa.jpql.parser.NumericLiteral;
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.SimpleSelectClause;
import org.eclipse.persistence.jpa.jpql.parser.SizeExpression;
import org.eclipse.persistence.jpa.jpql.parser.SqrtExpression;
import org.eclipse.persistence.jpa.jpql.parser.StateFieldPathExpression;
import org.eclipse.persistence.jpa.jpql.parser.StringLiteral;
import org.eclipse.persistence.jpa.jpql.parser.SubExpression;
import org.eclipse.persistence.jpa.jpql.parser.SubstringExpression;
import org.eclipse.persistence.jpa.jpql.parser.SubtractionExpression;
import org.eclipse.persistence.jpa.jpql.parser.SumFunction;
import org.eclipse.persistence.jpa.jpql.parser.TreatExpression;
import org.eclipse.persistence.jpa.jpql.parser.TrimExpression;
import org.eclipse.persistence.jpa.jpql.parser.TypeExpression;
import org.eclipse.persistence.jpa.jpql.parser.UpperExpression;
import org.eclipse.persistence.jpa.jpql.parser.ValueExpression;
import org.eclipse.persistence.queries.ReportQuery;
import static org.eclipse.persistence.jpa.jpql.LiteralType.*;
/**
* This builder is responsible to create the EclipseLink {@link Expression Expressions} representing
* the select items of the SELECT
clause.
*
* @version 2.4
* @since 2.3
* @author Pascal Filion
* @author John Bracken
*/
@SuppressWarnings("nls")
final class ReportItemBuilder extends EclipseLinkAnonymousExpressionVisitor {
/**
* The visitor responsible to visit the constructor items.
*/
private ConstructorExpressionVisitor constructorExpressionVisitor;
/**
* Determines whether the SELECT
clause has more than one select item.
*/
private boolean multipleSelects;
/**
* The {@link ReportQuery} to add the select expressions.
*/
private ReportQuery query;
/**
* The {@link JPQLQueryContext} is used to query information about the application metadata and
* cached information.
*/
private final JPQLQueryContext queryContext;
/**
* If the select expression is aliased with a result variable, then temporarily cache it so it
* can be used as the attribute name.
*/
private String resultVariable;
/**
* This array is used to store the type of the select {@link Expression JPQL Expression} that is
* converted into an {@link Expression EclipseLink Expression}.
*/
final Class[] type;
/**
* Creates a new ReportItemBuilder
.
*
* @param queryContext The context used to query information about the application metadata and
* cached information
* @param query The {@link ReportQuery} to populate by using this visitor to visit the parsed
* tree representation of the JPQL query
*/
ReportItemBuilder(JPQLQueryContext queryContext, ReportQuery query) {
super();
this.query = query;
this.type = new Class[1];
this.queryContext = queryContext;
}
private void addAttribute(String generateName, Expression queryExpression) {
if (resultVariable != null) {
generateName = resultVariable;
queryContext.addQueryExpression(resultVariable.toUpperCase(), queryExpression);
}
query.addAttribute(generateName, queryExpression);
}
private void addAttribute(String generateName, Expression queryExpression, Class type) {
if (resultVariable != null) {
generateName = resultVariable;
queryContext.addQueryExpression(resultVariable.toUpperCase(), queryExpression);
}
query.addAttribute(generateName, queryExpression, type);
}
private ConstructorExpressionVisitor constructorExpressionVisitor() {
if (constructorExpressionVisitor == null) {
constructorExpressionVisitor = new ConstructorExpressionVisitor();
}
return constructorExpressionVisitor;
}
/**
* {@inheritDoc}
*/
@Override
public void visit(AbsExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute(ExpressionTools.EMPTY_STRING, queryExpression, type[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(AdditionExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
if (type[0] == Object.class) {
type[0] = null;
}
addAttribute("plus", queryExpression, type[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(ArithmeticFactor expression) {
// TODO: Anything to do other than the default behavior?
super.visit(expression);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(AvgFunction expression) {
String name = queryContext.literal(expression.getExpression(), PATH_EXPRESSION_LAST_PATH);
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute(name, queryExpression, type[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(CaseExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute("Case", queryExpression, type[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(CastExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute(ExpressionTools.EMPTY_STRING, queryExpression, type[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(CoalesceExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute("Coalesce", queryExpression);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(CollectionExpression expression) {
multipleSelects = true;
for (org.eclipse.persistence.jpa.jpql.parser.Expression child : expression.children()) {
child.accept(this);
type[0] = null;
}
}
/**
* {@inheritDoc}
*/
@Override
public void visit(ConcatExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute(ExpressionTools.EMPTY_STRING, queryExpression, type[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(ConstructorExpression expression) {
Class type = queryContext.getType(expression.getClassName());
query.beginAddingConstructorArguments(type);
expression.accept(constructorExpressionVisitor());
query.endAddingToConstructorItem();
}
/**
* {@inheritDoc}
*/
@Override
public void visit(CountFunction expression) {
// Retrieve the attribute name
String name = queryContext.literal(expression.getExpression(), PATH_EXPRESSION_LAST_PATH);
if (name == ExpressionTools.EMPTY_STRING) {
name = CountFunction.COUNT;
}
// Add the attribute
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute(name, queryExpression, type[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(DateTime expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
if (expression.isJDBCDate()) {
addAttribute("CONSTANT", queryExpression);
}
else {
addAttribute("date", queryExpression, type[0]);
}
}
/**
* {@inheritDoc}
*/
@Override
public void visit(DivisionExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
if (type[0] == Object.class) {
type[0] = null;
}
addAttribute("divide", queryExpression, type[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(EntryExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute(" MapEntry", queryExpression);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(ExtractExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute(ExpressionTools.EMPTY_STRING, queryExpression, type[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(FunctionExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute(ExpressionTools.EMPTY_STRING, queryExpression);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(IdentificationVariable expression) {
String variableName = expression.getVariableName();
// Retrieve the FETCH JOIN expressions using the identification variable
List joinFetchExpressions = null;
// Retrieve the join fetches that were defined in the same identification variable
// declaration, if the identification variable is mapped to a join, then there will
// not be any join fetch associated with it
Collection joinFetches = queryContext.getJoinFetches(variableName);
if (joinFetches != null) {
for (Join joinFetch : joinFetches) {
// Retrieve the join association path expression's identification variable
String joinFetchVariableName = queryContext.literal(
joinFetch,
PATH_EXPRESSION_IDENTIFICATION_VARIABLE
);
if (variableName.equals(joinFetchVariableName)) {
if (joinFetchExpressions == null) {
joinFetchExpressions = new ArrayList();
}
joinFetchExpressions.add(queryContext.buildExpression(joinFetch, type));
}
}
}
Expression queryExpression = queryContext.buildExpression(expression, type);
// Add the attribute without any JOIN FETCH
if (joinFetchExpressions == null) {
query.addAttribute(expression.getText(), queryExpression);
}
// Add the attribute with the JOIN FETCH expressions
else {
query.addItem(expression.getText(), queryExpression, joinFetchExpressions);
}
}
/**
* {@inheritDoc}
*/
@Override
public void visit(IndexExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute("Index", queryExpression, type[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(KeyExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute("MapKey", queryExpression);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(KeywordExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute("CONSTANT", queryExpression);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(LengthExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute(ExpressionTools.EMPTY_STRING, queryExpression, type[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(LocateExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute(ExpressionTools.EMPTY_STRING, queryExpression, type[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(LowerExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute(ExpressionTools.EMPTY_STRING, queryExpression, type[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(MaxFunction expression) {
String name = queryContext.literal(expression.getExpression(), PATH_EXPRESSION_LAST_PATH);
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute(name, queryExpression, type[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(MinFunction expression) {
String name = queryContext.literal(expression.getExpression(), PATH_EXPRESSION_LAST_PATH);
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute(name, queryExpression, type[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(ModExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute(ExpressionTools.EMPTY_STRING, queryExpression, type[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(MultiplicationExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
if (type[0] == Object.class) {
type[0] = null;
}
addAttribute("multiply", queryExpression, type[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(NullIfExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute(NullIfExpression.NULLIF, queryExpression);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(NumericLiteral expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute("CONSTANT", queryExpression);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(ObjectExpression expression) {
expression.getExpression().accept(this);
}
/**
* {@inheritDoc}
*/
@Override
protected void visit(org.eclipse.persistence.jpa.jpql.parser.Expression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute(ExpressionTools.EMPTY_STRING, queryExpression);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(ResultVariable expression) {
// Now cache the Expression for future retrieval by the ORDER BY clause
IdentificationVariable identificationVariable = (IdentificationVariable) expression.getResultVariable();
resultVariable = identificationVariable.getText();
// Create the Expression that is added to the query as an attribute
expression.getSelectExpression().accept(this);
resultVariable = null;
}
/**
* {@inheritDoc}
*/
@Override
public void visit(SelectClause expression) {
visitAbstractSelectClause(expression);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(SimpleSelectClause expression) {
visitAbstractSelectClause(expression);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(SizeExpression expression) {
// Add the attribute
Expression queryExpression = queryContext.buildExpression(expression.getExpression());
addAttribute("size", queryExpression.count(), Integer.class);
// Now add the GROUP BY expression
CollectionValuedPathExpression pathExpression = (CollectionValuedPathExpression) expression.getExpression();
queryExpression = queryContext.buildGroupByExpression(pathExpression);
query.addGrouping(queryExpression);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(SqrtExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute(ExpressionTools.EMPTY_STRING, queryExpression, type[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(StateFieldPathExpression expression) {
// Temporarily change the null allowed flag if the state field is a foreign reference mapping
Expression queryExpression = queryContext.buildModifiedPathExpression(expression);
// Register the EclipseLink Expression with the state field name
String name = expression.getPath(expression.pathSize() - 1);
addAttribute(name, queryExpression);
query.dontRetrievePrimaryKeys();
}
/**
* {@inheritDoc}
*/
@Override
public void visit(StringLiteral expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute("CONSTANT", queryExpression);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(SubExpression expression) {
expression.getExpression().accept(this);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(SubstringExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute(ExpressionTools.EMPTY_STRING, queryExpression, type[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(SubtractionExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
if (type[0] == Object.class) {
type[0] = null;
}
addAttribute("minus", queryExpression, type[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(SumFunction expression) {
String name = queryContext.literal(expression.getExpression(), PATH_EXPRESSION_LAST_PATH);
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute(name, queryExpression, type[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(TreatExpression expression) {
// Nothing to do
}
/**
* {@inheritDoc}
*/
@Override
public void visit(TrimExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute(ExpressionTools.EMPTY_STRING, queryExpression, type[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(TypeExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute(ExpressionTools.EMPTY_STRING, queryExpression);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(UpperExpression expression) {
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute(ExpressionTools.EMPTY_STRING, queryExpression, type[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(ValueExpression expression) {
IdentificationVariable identificationVariable = (IdentificationVariable) expression.getExpression();
Expression queryExpression = queryContext.buildExpression(expression, type);
addAttribute(identificationVariable.getText(), queryExpression);
}
private void visitAbstractSelectClause(AbstractSelectClause expression) {
multipleSelects = false;
expression.getSelectExpression().accept(this);
if (multipleSelects) {
query.returnWithoutReportQueryResult();
}
else {
query.returnSingleAttribute();
}
}
/**
* This visitor takes care of creating the {@link org.eclipse.persistence.expressions.Expression
* expressions} for the constructor arguments.
*/
private class ConstructorExpressionVisitor extends EclipseLinkAnonymousExpressionVisitor {
/**
* {@inheritDoc}
*/
@Override
public void visit(CollectionExpression expression) {
expression.acceptChildren(this);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(ConstructorExpression expression) {
expression.getConstructorItems().accept(this);
}
/**
* {@inheritDoc}
*/
@Override
protected void visit(org.eclipse.persistence.jpa.jpql.parser.Expression expression) {
expression.accept(ReportItemBuilder.this);
}
}
}