blob: c806900910af8f479ca43af2e6e24ba276686ee9 [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.jpa.jpql.tools.model;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.AND;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.AS;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.BETWEEN;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.CASE;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.COALESCE;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.CONCAT;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.DELETE;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.DISTINCT;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.DIVISION;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.ELSE;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.EMPTY;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.END;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.EQUAL;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.ESCAPE;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.EXISTS;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.FROM;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.FUNC;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.GROUP_BY;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.HAVING;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.IN;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.IS;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.LIKE;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.MEMBER;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.MINUS;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.MULTIPLICATION;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.NEW;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.NOT;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.NULL;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.OF;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.OR;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.ORDER_BY;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.PLUS;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.SELECT;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.SET;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.THEN;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.TREAT;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.UPDATE;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.WHEN;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.WHERE;
import java.util.ListIterator;
import org.eclipse.persistence.jpa.jpql.ExpressionTools;
import org.eclipse.persistence.jpa.jpql.parser.AbstractDoubleEncapsulatedExpression;
import org.eclipse.persistence.jpa.jpql.parser.AbstractFromClause;
import org.eclipse.persistence.jpa.jpql.parser.AbstractSelectStatement;
import org.eclipse.persistence.jpa.jpql.parser.AbstractSingleEncapsulatedExpression;
import org.eclipse.persistence.jpa.jpql.parser.AbstractTripleEncapsulatedExpression;
import org.eclipse.persistence.jpa.jpql.parser.AggregateFunction;
import org.eclipse.persistence.jpa.jpql.parser.BetweenExpression;
import org.eclipse.persistence.jpa.jpql.parser.CaseExpression;
import org.eclipse.persistence.jpa.jpql.parser.CoalesceExpression;
import org.eclipse.persistence.jpa.jpql.parser.CollectionMemberDeclaration;
import org.eclipse.persistence.jpa.jpql.parser.CollectionMemberExpression;
import org.eclipse.persistence.jpa.jpql.parser.CompoundExpression;
import org.eclipse.persistence.jpa.jpql.parser.ConcatExpression;
import org.eclipse.persistence.jpa.jpql.parser.ConstructorExpression;
import org.eclipse.persistence.jpa.jpql.parser.DateTime;
import org.eclipse.persistence.jpa.jpql.parser.DeleteClause;
import org.eclipse.persistence.jpa.jpql.parser.EmptyCollectionComparisonExpression;
import org.eclipse.persistence.jpa.jpql.parser.EncapsulatedIdentificationVariableExpression;
import org.eclipse.persistence.jpa.jpql.parser.ExistsExpression;
import org.eclipse.persistence.jpa.jpql.parser.Expression;
import org.eclipse.persistence.jpa.jpql.parser.FunctionExpression;
import org.eclipse.persistence.jpa.jpql.parser.GroupByClause;
import org.eclipse.persistence.jpa.jpql.parser.HavingClause;
import org.eclipse.persistence.jpa.jpql.parser.IdentificationVariableDeclaration;
import org.eclipse.persistence.jpa.jpql.parser.InExpression;
import org.eclipse.persistence.jpa.jpql.parser.Join;
import org.eclipse.persistence.jpa.jpql.parser.KeywordExpression;
import org.eclipse.persistence.jpa.jpql.parser.LikeExpression;
import org.eclipse.persistence.jpa.jpql.parser.NotExpression;
import org.eclipse.persistence.jpa.jpql.parser.NullComparisonExpression;
import org.eclipse.persistence.jpa.jpql.parser.OrderByClause;
import org.eclipse.persistence.jpa.jpql.parser.OrderByItem;
import org.eclipse.persistence.jpa.jpql.parser.RangeVariableDeclaration;
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.jpa.jpql.parser.SimpleSelectClause;
import org.eclipse.persistence.jpa.jpql.parser.TreatExpression;
import org.eclipse.persistence.jpa.jpql.parser.TrimExpression;
import org.eclipse.persistence.jpa.jpql.parser.UpdateClause;
import org.eclipse.persistence.jpa.jpql.parser.UpdateItem;
import org.eclipse.persistence.jpa.jpql.parser.WhenClause;
import org.eclipse.persistence.jpa.jpql.parser.WhereClause;
import org.eclipse.persistence.jpa.jpql.tools.model.query.AbsExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.AbstractDoubleEncapsulatedExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.AbstractFromClauseStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.AbstractIdentificationVariableDeclarationStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.AbstractModifyStatementStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.AbstractPathExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.AbstractRangeVariableDeclarationStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.AbstractSchemaNameStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.AbstractSelectStatementStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.AbstractSingleEncapsulatedExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.AbstractTripleEncapsulatedExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.AdditionExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.AggregateFunctionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.AllOrAnyExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.AndExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.ArithmeticFactorStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.AvgFunctionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.BadExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.BetweenExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.CaseExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.CoalesceExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.CollectionMemberDeclarationStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.CollectionMemberExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.CollectionValuedPathExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.ComparisonExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.CompoundExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.ConcatExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.ConstructorExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.CountFunctionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.DateTimeStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.DeleteClauseStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.DeleteStatementStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.DerivedPathIdentificationVariableDeclarationStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.DerivedPathVariableDeclarationStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.DivisionExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.EmptyCollectionComparisonExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.EncapsulatedIdentificationVariableExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.EntityTypeLiteralStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.EntryExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.EnumTypeStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.ExistsExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.FromClauseStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.FunctionExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.GroupByClauseStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.HavingClauseStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.IdentificationVariableDeclarationStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.IdentificationVariableStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.InExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.IndexExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.InputParameterStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.JPQLQueryStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.JoinStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.KeyExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.KeywordExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.LengthExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.LikeExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.ListHolderStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.LocateExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.LowerExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.MaxFunctionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.MinFunctionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.ModExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.MultiplicationExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.NotExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.NullComparisonExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.NullIfExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.NumericLiteralStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.ObjectExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.OrExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.OrderByClauseStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.OrderByItemStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.RangeVariableDeclarationStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.ResultVariableStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.SelectClauseStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.SelectStatementStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.SimpleFromClauseStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.SimpleSelectClauseStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.SimpleSelectStatementStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.SimpleStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.SizeExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.SqrtExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.StateFieldPathExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.StateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.StringLiteralStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.SubExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.SubstringExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.SubtractionExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.SumFunctionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.TreatExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.TrimExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.TypeExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.UnknownExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.UpdateClauseStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.UpdateItemStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.UpdateStatementStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.UpperExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.ValueExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.WhenClauseStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.WhereClauseStateObject;
/**
* This {@link IJPQLQueryFormatter} is used to generate a string representation of a {@link
* StateObject} based on how it was parsed, which means this formatter can only be used when the
* {@link StateObject} was created by parsing a JPQL query because it needs to retrieve parsing
* information from the corresponding {@link Expression}.
* <p>
* It is possible to partially match the JPQL query that was parsed, the value of <em>exactMatch</em>
* will determine whether the string representation of any given {@link StateObject} should reflect
* the exact string that was parsed. <code>true</code> will use every bit of information contained
* in the corresponding {@link Expression} to perfectly match what was parsed (case of JPQL
* identifiers and the presence of whitespace); <code>false</code> will only match the case
* sensitivity of the JPQL identifiers.
*
* @version 2.5
* @since 2.4
* @author Pascal Filion
*/
@SuppressWarnings("null")
public abstract class AbstractActualJPQLQueryFormatter extends BaseJPQLQueryFormatter {
/**
* Determines whether the string representation of any given {@link StateObject} should reflect
* the exact string that was parsed: <code>true</code> will use every bit of information
* contained in the corresponding {@link Expression} to perfectly match what was parsed;
* <code>false</code> will only match the case sensitivity of the JPQL identifiers.
*/
protected final boolean exactMatch;
/**
* Creates a new <code>AbstractActualJPQLQueryFormatter</code>.
*
* @param exactMatch Determines whether the string representation of any given {@link StateObject}
* should reflect the exact string that was parsed: <code>true</code> will use every bit of
* information contained in the corresponding {@link Expression} to perfectly match what was
* parsed (case of JPQL identifiers and the presence of whitespace); <code>false</code> will only
* match the case sensitivity of the JPQL identifiers
*/
protected AbstractActualJPQLQueryFormatter(boolean exactMatch) {
super(IdentifierStyle.UPPERCASE);
this.exactMatch = exactMatch;
}
/**
* Creates a new <code>AbstractActualJPQLQueryFormatter</code>.
*
* @param exactMatch Determines whether the string representation of any given {@link StateObject}
* should reflect the exact string that was parsed: <code>true</code> will use every bit of
* information contained in the corresponding {@link Expression} to perfectly match what was
* parsed (case of JPQL identifiers and the presence of whitespace); <code>false</code> will only
* match the case sensitivity of the JPQL identifiers
* @param style Determines how the JPQL identifiers are written out, which is used if the
* {@link StateObject} was modified after its creation
* @exception NullPointerException The IdentifierStyle cannot be <code>null</code>
*/
protected AbstractActualJPQLQueryFormatter(boolean exactMatch, IdentifierStyle style) {
super(style);
this.exactMatch = exactMatch;
}
/**
* Appends the given actual identifier if it's not an empty string, otherwise the second
* identifier will be appended.
*
* @param actualIdentifier The actual JPQL identifier to append to the writer if it's not an
* empty string
* @param identifier The uppercase constant of the JPQL identifier to append if the actual one is
* an empty string
*/
protected void appendIdentifier(String actualIdentifier, String identifier) {
if (!exactMatch || ExpressionTools.stringIsEmpty(actualIdentifier)) {
actualIdentifier = formatIdentifier(identifier);
}
writer.append(actualIdentifier);
}
/**
* Determines whether the string representation of any given {@link StateObject} should reflect
* the exact string that was parsed.
*
* @return <code>true</code> will use every bit of information contained in the corresponding
* {@link Expression} to perfectly match what was parsed; <code>false</code> will only match the
* case sensitivity of the JPQL identifiers
*/
public boolean isUsingExactMatch() {
return exactMatch;
}
protected boolean shouldOutput(Expression expression) {
return !exactMatch || (expression == null);
}
protected void toStringAggregateFunction(AggregateFunctionStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
AggregateFunction expression = stateObject.getExpression();
// Identifier
appendIdentifier((expression != null) ? expression.getActualIdentifier() : stateObject.getIdentifier(), stateObject.getIdentifier());
// '('
if (shouldOutput(expression) || expression.hasLeftParenthesis()) {
writer.append(formatIdentifier(LEFT_PARENTHESIS));
}
// 'DISTINCT'
if (stateObject.hasDistinct()) {
appendIdentifier((expression != null) ? expression.getActualDistinctIdentifier() : DISTINCT, DISTINCT);
if (shouldOutput(expression) || expression.hasSpaceAfterDistinct()) {
writer.append(SPACE);
}
}
// Encapsulated expression
if (stateObject.hasStateObject()) {
stateObject.getStateObject().accept(this);
}
// ')'
if (shouldOutput(expression) || expression.hasRightParenthesis()) {
writer.append(formatIdentifier(RIGHT_PARENTHESIS));
}
}
}
protected void toStringChildren(ListHolderStateObject<? extends StateObject> stateObject,
boolean comma) {
for (ListIterator<? extends StateObject> iter = stateObject.items().iterator(); iter.hasNext(); ) {
iter.next().accept(this);
if (iter.hasNext()) {
writer.append(comma ? COMMA_SPACE : SPACE);
}
}
}
protected void toStringCompound(CompoundExpressionStateObject stateObject, String identifier) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
CompoundExpression expression = stateObject.getExpression();
// Left expression
if (stateObject.hasLeft()) {
stateObject.getLeft().accept(this);
writer.append(SPACE);
}
// Identifier
appendIdentifier((expression != null) ? expression.getActualIdentifier() : identifier, identifier);
if (shouldOutput(expression) || expression.hasSpaceAfterIdentifier()) {
writer.append(SPACE);
}
// Right expression
if (stateObject.hasRight()) {
stateObject.getRight().accept(this);
}
}
}
protected void toStringDoubleEncapsulated(AbstractDoubleEncapsulatedExpressionStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
AbstractDoubleEncapsulatedExpression expression = stateObject.getExpression();
// Identifier
appendIdentifier((expression != null) ? expression.getActualIdentifier() : stateObject.getIdentifier(), stateObject.getIdentifier());
// '('
if (shouldOutput(expression) || expression.hasLeftParenthesis()) {
writer.append(LEFT_PARENTHESIS);
}
else if (expression.hasSpaceAfterIdentifier()) {
writer.append(COMMA);
}
// First expression
if (stateObject.hasFirst()) {
stateObject.getFirst().accept(this);
}
// ','
if (shouldOutput(expression) || expression.hasComma()) {
writer.append(COMMA);
}
if (shouldOutput(expression) || expression.hasSpaceAfterComma()) {
writer.append(SPACE);
}
// Second expression
if (stateObject.hasSecond()) {
stateObject.getSecond().accept(this);
}
// ')'
if (shouldOutput(expression) || expression.hasRightParenthesis()) {
writer.append(RIGHT_PARENTHESIS);
}
}
}
protected void toStringEncapsulatedIdentificationVariable(EncapsulatedIdentificationVariableExpressionStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
EncapsulatedIdentificationVariableExpression expression = stateObject.getExpression();
// Identifier
appendIdentifier((expression != null) ? expression.getActualIdentifier() : stateObject.getIdentifier(), stateObject.getIdentifier());
// '('
if (shouldOutput(expression) || expression.hasLeftParenthesis()) {
writer.append(LEFT_PARENTHESIS);
}
// Identification variable
if (stateObject.hasIdentificationVariable()) {
writer.append(stateObject.getIdentificationVariable());
}
// ')'
if (shouldOutput(expression) || expression.hasRightParenthesis()) {
writer.append(RIGHT_PARENTHESIS);
}
}
}
protected void toStringFromClause(AbstractFromClauseStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
AbstractFromClause expression = stateObject.getExpression();
// 'FROM'
appendIdentifier((expression != null) ? expression.getActualIdentifier() : FROM, FROM);
if (shouldOutput(expression) || expression.hasSpaceAfterFrom()) {
writer.append(SPACE);
}
// declaration
if (stateObject.hasItems()) {
toStringChildren(stateObject, true);
}
}
}
protected void toStringIdentificationVariableDeclaration(AbstractIdentificationVariableDeclarationStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
IdentificationVariableDeclaration expression = stateObject.getExpression();
// Range variable declaration
stateObject.getRangeVariableDeclaration().accept(this);
// Join | Join Fetch
if (stateObject.hasItems()) {
if (shouldOutput(expression) || expression.hasSpace()) {
writer.append(SPACE);
}
toStringChildren(stateObject, false);
}
}
}
protected void toStringModifyStatement(AbstractModifyStatementStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
stateObject.getModifyClause().accept(this);
if (stateObject.hasWhereClause()) {
// TODO: HANDLE SPACE
writer.append(SPACE);
stateObject.getWhereClause().accept(this);
}
}
}
protected void toStringPathExpression(AbstractPathExpressionStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
stateObject.toText(writer);
}
}
protected void toStringRangeVariableDeclaration(AbstractRangeVariableDeclarationStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
RangeVariableDeclaration expression = stateObject.getExpression();
// "Root" object (abstract schema name or derived declaration)
stateObject.getRootStateObject().accept(this);
if (exactMatch && (expression != null) && expression.hasSpaceAfterRootObject()) {
writer.append(SPACE);
}
// 'AS'
if (stateObject.hasAs()) {
if (!exactMatch || (expression == null)) {
writer.append(SPACE);
}
appendIdentifier((expression != null) ? expression.getActualAsIdentifier() : AS, AS);
}
if (exactMatch && (expression != null) && expression.hasSpaceAfterAs()) {
writer.append(SPACE);
}
// Identification variable
if (stateObject.hasIdentificationVariable() &&
!stateObject.isIdentificationVariableVirtual()) {
if (!exactMatch || (expression == null)) {
writer.append(SPACE);
}
writer.append(stateObject.getIdentificationVariable());
}
}
}
protected boolean toStringSelectStatement(AbstractSelectStatementStateObject stateObject) {
AbstractSelectStatement expression = stateObject.getExpression();
boolean spaceAdded = false;
// SELECT clause
stateObject.getSelectClause().accept(this);
// If no select items were parsed but they got added later, make sure a space is added
if (shouldOutput(expression) ||
expression.hasSpaceAfterSelect() ||
// TODO
(/*!expression.getSelectClause().hasSelectExpression() &&*/
stateObject.getSelectClause().hasSelectItem())) {
writer.append(SPACE);
}
// FROM clause
stateObject.getFromClause().accept(this);
// If no WHERE clause was parsed but was added later, make sure a space is added
if (exactMatch && (expression != null) && expression.hasSpaceAfterFrom() ||
stateObject.hasWhereClause()) {
writer.append(SPACE);
spaceAdded = true;
}
// WHERE clause
if (stateObject.hasWhereClause()) {
stateObject.getWhereClause().accept(this);
spaceAdded = false;
}
// If no GROUP BY clause was parsed but was added later, make sure a space is added
if (exactMatch && (expression != null) && expression.hasSpaceAfterWhere() ||
stateObject.hasGroupByClause()) {
if (!spaceAdded) {
writer.append(SPACE);
spaceAdded = true;
}
}
// GROUP BY clause
if (stateObject.hasGroupByClause()) {
stateObject.getGroupByClause().accept(this);
spaceAdded = false;
}
// If no HAVING clause was parsed but was added later, make sure a space is added
if (exactMatch && (expression != null) && expression.hasSpaceAfterGroupBy() ||
stateObject.hasHavingClause()) {
if (!spaceAdded) {
writer.append(SPACE);
spaceAdded = true;
}
}
// HAVING clause
if (stateObject.hasHavingClause()) {
stateObject.getHavingClause().accept(this);
spaceAdded = true;
}
return spaceAdded;
}
protected void toStringSimpleStateObject(SimpleStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else if (stateObject.hasText()) {
writer.append(stateObject.getText());
}
}
protected void toStringSingleEncapsulated(AbstractSingleEncapsulatedExpressionStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
AbstractSingleEncapsulatedExpression expression = stateObject.getExpression();
// Identifier
appendIdentifier((expression != null) ? expression.getActualIdentifier() : stateObject.getIdentifier(), stateObject.getIdentifier());
// '('
if (shouldOutput(expression) || expression.hasLeftParenthesis()) {
writer.append(LEFT_PARENTHESIS);
}
if (stateObject.hasStateObject()) {
stateObject.getStateObject().accept(this);
}
// ')'
if (shouldOutput(expression) || expression.hasRightParenthesis()) {
writer.append(RIGHT_PARENTHESIS);
}
}
}
protected void toStringTripleEncapsulated(AbstractTripleEncapsulatedExpressionStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
AbstractTripleEncapsulatedExpression expression = stateObject.getExpression();
// Identifier
appendIdentifier((expression != null) ? expression.getActualIdentifier() : stateObject.getIdentifier(), stateObject.getIdentifier());
// '('
if (shouldOutput(expression) || expression.hasLeftParenthesis()) {
writer.append(LEFT_PARENTHESIS);
}
// First expression
if (stateObject.hasFirst()) {
stateObject.getFirst().accept(this);
}
if (shouldOutput(expression) || expression.hasFirstComma()) {
writer.append(COMMA);
}
if (shouldOutput(expression) || expression.hasSpaceAfterFirstComma()) {
writer.append(SPACE);
}
// Second expression
if (stateObject.hasSecond()) {
stateObject.getSecond().accept(this);
}
// Third expression
if (stateObject.hasThird()) {
if (shouldOutput(expression) || expression.hasSecondComma()) {
writer.append(COMMA);
}
if (shouldOutput(expression) || expression.hasSpaceAfterSecondComma()) {
writer.append(SPACE);
}
stateObject.getThird().accept(this);
}
// ')'
if (shouldOutput(expression) || expression.hasRightParenthesis()) {
writer.append(RIGHT_PARENTHESIS);
}
}
}
@Override
public void visit(AbsExpressionStateObject stateObject) {
toStringSingleEncapsulated(stateObject);
}
@Override
public void visit(AbstractSchemaNameStateObject stateObject) {
toStringSimpleStateObject(stateObject);
}
@Override
public void visit(AdditionExpressionStateObject stateObject) {
toStringCompound(stateObject, PLUS);
}
@Override
public void visit(AllOrAnyExpressionStateObject stateObject) {
toStringSingleEncapsulated(stateObject);
}
@Override
public void visit(AndExpressionStateObject stateObject) {
toStringCompound(stateObject, AND);
}
@Override
public void visit(ArithmeticFactorStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
writer.append(stateObject.getArithmeticSign());
if (stateObject.hasStateObject()) {
stateObject.getStateObject().accept(this);
}
}
}
@Override
public void visit(AvgFunctionStateObject stateObject) {
toStringAggregateFunction(stateObject);
}
@Override
public void visit(BadExpressionStateObject stateObject) {
toStringSimpleStateObject(stateObject);
}
@Override
public void visit(BetweenExpressionStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
BetweenExpression expression = stateObject.getExpression();
// Expression
if (stateObject.hasStateObject()) {
stateObject.getStateObject().accept(this);
writer.append(SPACE);
}
// 'NOT
if (stateObject.hasNot()) {
appendIdentifier((expression != null) ? expression.getActualNotIdentifier() : NOT, NOT);
writer.append(SPACE);
}
// 'BETWEEN'
appendIdentifier((expression != null) ? expression.getActualBetweenIdentifier() : BETWEEN, BETWEEN);
if (shouldOutput(expression) || expression.hasSpaceAfterBetween()) {
writer.append(SPACE);
}
// Lower bound expression
if (stateObject.hasLowerBound()) {
stateObject.getLowerBound().accept(this);
}
if (shouldOutput(expression) || expression.hasSpaceAfterLowerBound()) {
writer.append(SPACE);
}
// 'AND'
if (shouldOutput(expression) || expression.hasAnd()) {
appendIdentifier((expression != null) ? expression.getActualAndIdentifier() : AND, AND);
}
if (shouldOutput(expression) || expression.hasSpaceAfterAnd()) {
writer.append(SPACE);
}
// Upper bound expression
if (stateObject.hasUpperBound()) {
stateObject.getUpperBound().accept(this);
}
}
}
@Override
public void visit(CaseExpressionStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
CaseExpression expression = stateObject.getExpression();
// 'CASE'
appendIdentifier((expression != null) ? expression.getActualCaseIdentifier() : CASE, CASE);
if (shouldOutput(expression) || expression.hasSpaceAfterCase()) {
writer.append(SPACE);
}
// Case operand
if (stateObject.hasCaseOperand()) {
stateObject.getCaseOperand().accept(this);
if (shouldOutput(expression) || expression.hasSpaceAfterCaseOperand()) {
writer.append(SPACE);
}
}
// WHEN clauses
if (stateObject.hasItems()) {
toStringChildren(stateObject, false);
}
if (shouldOutput(expression) || expression.hasSpaceAfterWhenClauses()) {
writer.append(SPACE);
}
// 'ELSE'
if (shouldOutput(expression) || expression.hasElse()) {
appendIdentifier((expression != null) ? expression.getActualElseIdentifier() : ELSE, ELSE);
}
if (shouldOutput(expression) || expression.hasSpaceAfterElse()) {
writer.append(SPACE);
}
// Else expression
if (stateObject.hasElse()) {
stateObject.getElse().accept(this);
}
if (shouldOutput(expression) || expression.hasSpaceAfterElseExpression()) {
writer.append(SPACE);
}
// END
if (shouldOutput(expression) || expression.hasEnd()) {
appendIdentifier((expression != null) ? expression.getActualEndIdentifier() : END, END);
}
}
}
@Override
public void visit(CoalesceExpressionStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
CoalesceExpression expression = stateObject.getExpression();
// 'COALESCE'
appendIdentifier((expression != null) ? expression.getActualIdentifier() : COALESCE, COALESCE);
// '('
if (shouldOutput(expression) || expression.hasLeftParenthesis()) {
writer.append(LEFT_PARENTHESIS);
}
else if (expression.hasSpaceAfterIdentifier()) {
writer.append(SPACE);
}
toStringChildren(stateObject, true);
// ')'
if (shouldOutput(expression) || expression.hasRightParenthesis()) {
writer.append(RIGHT_PARENTHESIS);
}
}
}
@Override
public void visit(CollectionMemberDeclarationStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
CollectionMemberDeclaration expression = stateObject.getExpression();
// 'IN'
appendIdentifier((expression != null) ? expression.getActualInIdentifier() : IN, IN);
// '('
if (!stateObject.isDerived() && (shouldOutput(expression) || expression.hasLeftParenthesis())) {
writer.append(LEFT_PARENTHESIS);
}
else if (stateObject.isDerived() && (shouldOutput(expression) || expression.hasSpaceAfterIn())) {
writer.append(SPACE);
}
// Collection-valued path expression
stateObject.getCollectionValuedPath().accept(this);
// ')'
if (!stateObject.isDerived() && (shouldOutput(expression) || expression.hasRightParenthesis())) {
writer.append(RIGHT_PARENTHESIS);
if (shouldOutput(expression) || expression.hasSpaceAfterRightParenthesis()) {
writer.append(SPACE);
}
}
else if (stateObject.isDerived() &&
stateObject.hasAs() &&
(shouldOutput(expression) || expression.hasSpaceAfterRightParenthesis())) {
writer.append(SPACE);
}
// 'AS'
if (stateObject.hasAs()) {
appendIdentifier((expression != null) ? expression.getActualAsIdentifier() : AS, AS);
if (shouldOutput(expression) || expression.hasSpaceAfterAs()) {
writer.append(SPACE);
}
}
// Identification variable
if (stateObject.hasIdentificationVariable()) {
stateObject.getIdentificationVariable().accept(this);
}
}
}
@Override
public void visit(CollectionMemberExpressionStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
CollectionMemberExpression expression = stateObject.getExpression();
// Entity or value expression
if (stateObject.hasEntityStateObject()) {
stateObject.getEntityStateObject().accept(this);
writer.append(SPACE);
}
// 'NOT'
if (stateObject.hasNot()) {
appendIdentifier((expression != null) ? expression.getActualNotIdentifier() : NOT, NOT);
writer.append(SPACE);
}
// 'MEMBER'
appendIdentifier((expression != null) ? expression.getActualMemberIdentifier() : MEMBER, MEMBER);
if (shouldOutput(expression) || expression.hasSpaceAfterMember()) {
writer.append(SPACE);
}
// 'OF'
if (stateObject.hasOf()) {
appendIdentifier((expression != null) ? expression.getActualOfIdentifier() : OF, OF);
if (shouldOutput(expression) || expression.hasSpaceAfterOf()) {
writer.append(SPACE);
}
}
// Collection-valued path expression
stateObject.getCollectionValuedPath().accept(this);
}
}
@Override
public void visit(CollectionValuedPathExpressionStateObject stateObject) {
toStringPathExpression(stateObject);
}
@Override
public void visit(ComparisonExpressionStateObject stateObject) {
toStringCompound(stateObject, stateObject.getIdentifier());
}
@Override
public void visit(ConcatExpressionStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
ConcatExpression expression = stateObject.getExpression();
// 'CONCAT'
appendIdentifier((expression != null) ? expression.getActualIdentifier() : CONCAT, CONCAT);
// '('
if (shouldOutput(expression) || expression.hasLeftParenthesis()) {
writer.append(LEFT_PARENTHESIS);
}
toStringChildren(stateObject, true);
// ')'
if (shouldOutput(expression) || expression.hasRightParenthesis()) {
writer.append(RIGHT_PARENTHESIS);
}
}
}
@Override
public void visit(ConstructorExpressionStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
ConstructorExpression expression = stateObject.getExpression();
// 'NEW'
appendIdentifier((expression != null) ? expression.getActualIdentifier() : NEW, NEW);
if (shouldOutput(expression) || expression.hasSpaceAfterNew()) {
writer.append(SPACE);
}
// Class name
writer.append(stateObject.getClassName());
// '('
if (shouldOutput(expression) || expression.hasLeftParenthesis()) {
writer.append(LEFT_PARENTHESIS);
}
toStringChildren(stateObject, true);
// ')'
if (shouldOutput(expression) || expression.hasRightParenthesis()) {
writer.append(RIGHT_PARENTHESIS);
}
}
}
@Override
public void visit(CountFunctionStateObject stateObject) {
toStringAggregateFunction(stateObject);
}
@Override
public void visit(DateTimeStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
DateTime expression = stateObject.getExpression();
appendIdentifier((expression != null) ? expression.getActualIdentifier() : stateObject.getText(), stateObject.getText());
}
}
@Override
public void visit(DeleteClauseStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
DeleteClause expression = stateObject.getExpression();
// 'DELETE'
appendIdentifier((expression != null) ? expression.getActualDeleteIdentifier() : DELETE, DELETE);
if (shouldOutput(expression) || expression.hasSpaceAfterDelete()) {
writer.append(SPACE);
}
// 'FROM'
if (shouldOutput(expression) || expression.hasFrom()) {
appendIdentifier((expression != null) ? expression.getActualFromIdentifier() : FROM, FROM);
}
if (shouldOutput(expression) || expression.hasSpaceAfterFrom()) {
writer.append(SPACE);
}
// Range variable declaration
stateObject.getRangeVariableDeclaration().accept(this);
}
}
@Override
public void visit(DeleteStatementStateObject stateObject) {
toStringModifyStatement(stateObject);
}
@Override
public void visit(DerivedPathIdentificationVariableDeclarationStateObject stateObject) {
toStringIdentificationVariableDeclaration(stateObject);
}
@Override
public void visit(DerivedPathVariableDeclarationStateObject stateObject) {
toStringRangeVariableDeclaration(stateObject);
}
@Override
public void visit(DivisionExpressionStateObject stateObject) {
toStringCompound(stateObject, DIVISION);
}
@Override
public void visit(EmptyCollectionComparisonExpressionStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
EmptyCollectionComparisonExpression expression = stateObject.getExpression();
stateObject.getStateObject().accept(this);
writer.append(SPACE);
// 'IS'
appendIdentifier((expression != null) ? expression.getActualIsIdentifier() : IS, IS);
writer.append(SPACE);
// 'NOT'
if (stateObject.hasNot()) {
appendIdentifier((expression != null) ? expression.getActualNotIdentifier() : NOT, NOT);
writer.append(SPACE);
}
// 'EMPTY'
appendIdentifier((expression != null) ? expression.getActualEmptyIdentifier() : EMPTY, EMPTY);
}
}
@Override
public void visit(EntityTypeLiteralStateObject stateObject) {
toStringSimpleStateObject(stateObject);
}
@Override
public void visit(EntryExpressionStateObject stateObject) {
toStringEncapsulatedIdentificationVariable(stateObject);
}
@Override
public void visit(EnumTypeStateObject stateObject) {
toStringSimpleStateObject(stateObject);
}
@Override
public void visit(ExistsExpressionStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
ExistsExpression expression = stateObject.getExpression();
// 'NOT'
if (stateObject.hasNot()) {
appendIdentifier((expression != null) ? expression.getActualNotIdentifier() : NOT, NOT);
writer.append(SPACE);
}
// 'EXISTS'
String actualIdentifier = (expression != null) ? expression.getActualIdentifier() : null;
if ((actualIdentifier != null) && actualIdentifier.startsWith(NOT)) {
actualIdentifier = actualIdentifier.substring(4);
}
appendIdentifier(actualIdentifier, EXISTS);
// '('
if (shouldOutput(expression) || expression.hasLeftParenthesis()) {
writer.append(formatIdentifier(LEFT_PARENTHESIS));
}
// Subquery
if (stateObject.hasStateObject()) {
stateObject.getStateObject().accept(this);
}
// ')'
if (shouldOutput(expression) || expression.hasRightParenthesis()) {
writer.append(formatIdentifier(RIGHT_PARENTHESIS));
}
}
}
@Override
public void visit(FromClauseStateObject stateObject) {
toStringFromClause(stateObject);
}
@Override
public void visit(FunctionExpressionStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
FunctionExpression expression = stateObject.getExpression();
// FUNC
appendIdentifier((expression != null) ? expression.getActualIdentifier() : FUNC, FUNC);
// (
if (shouldOutput(expression) || expression.hasLeftParenthesis()) {
writer.append(LEFT_PARENTHESIS);
}
else if (exactMatch && expression.hasSpaceAfterIdentifier()) {
writer.append(SPACE);
}
// Function name
if (stateObject.hasFunctionName()) {
writer.append(stateObject.getQuotedFunctionName());
if (shouldOutput(expression) || expression.hasComma()) {
writer.append(COMMA);
}
if (shouldOutput(expression) || expression.hasSpaceAfterComma()) {
writer.append(SPACE);
}
}
// Arguments
toStringChildren(stateObject, true);
// )
if (shouldOutput(expression) || expression.hasRightParenthesis()) {
writer.append(RIGHT_PARENTHESIS);
}
}
}
@Override
public void visit(GroupByClauseStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
GroupByClause expression = stateObject.getExpression();
// 'GROUP BY'
appendIdentifier((expression != null) ? expression.getActualIdentifier() : GROUP_BY, GROUP_BY);
if (shouldOutput(expression) || expression.hasSpaceAfterGroupBy()) {
writer.append(SPACE);
}
// Group by items
if (stateObject.hasItems()) {
toStringChildren(stateObject, true);
}
}
}
@Override
public void visit(HavingClauseStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
HavingClause expression = stateObject.getExpression();
// 'HAVING'
appendIdentifier((expression != null) ? expression.getActualIdentifier() : HAVING, HAVING);
if (exactMatch && (expression != null) && expression.hasSpaceAfterIdentifier() ||
stateObject.hasConditional()) {
writer.append(SPACE);
}
// Conditional expression
if (stateObject.hasConditional()) {
stateObject.getConditional().accept(this);
}
}
}
@Override
public void visit(IdentificationVariableDeclarationStateObject stateObject) {
toStringIdentificationVariableDeclaration(stateObject);
}
@Override
public void visit(IdentificationVariableStateObject stateObject) {
toStringSimpleStateObject(stateObject);
}
@Override
public void visit(IndexExpressionStateObject stateObject) {
toStringEncapsulatedIdentificationVariable(stateObject);
}
@Override
public void visit(InExpressionStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
InExpression expression = stateObject.getExpression();
if (stateObject.hasStateObject()) {
stateObject.getStateObject().accept(this);
writer.append(SPACE);
}
// 'NOT'
if (stateObject.hasNot()) {
appendIdentifier((expression != null) ? expression.getActualNotIdentifier() : NOT, NOT);
writer.append(SPACE);
}
// 'IN'
appendIdentifier((expression != null) ? expression.getActualInIdentifier() : IN, IN);
if (!stateObject.isSingleInputParameter()) {
writer.append(LEFT_PARENTHESIS);
}
else if (shouldOutput(expression) || expression.hasSpaceAfterIn()) {
writer.append(SPACE);
}
if (stateObject.hasItems()) {
toStringChildren(stateObject, true);
}
if (!stateObject.isSingleInputParameter()) {
writer.append(RIGHT_PARENTHESIS);
}
}
}
@Override
public void visit(InputParameterStateObject stateObject) {
toStringSimpleStateObject(stateObject);
}
@Override
public void visit(JoinStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
Join expression = stateObject.getExpression();
// JOIN
appendIdentifier((expression != null) ? expression.getActualIdentifier() : stateObject.getJoinType(), stateObject.getJoinType());
if (shouldOutput(expression) || expression.hasSpaceAfterJoin()) {
writer.append(SPACE);
}
// Join association path
stateObject.getJoinAssociationPathStateObject().accept(this);
// Check first if the JOIN FETCH is allowed to have an identification variable
if (stateObject.hasFetch()) {
if (expression.hasAs()) {
writer.append(SPACE);
}
}
// JOIN always needs a whitespace
else {
if (shouldOutput(expression) || expression.hasSpaceAfterJoinAssociation()) {
writer.append(SPACE);
}
}
// AS
if (stateObject.hasAs()) {
appendIdentifier((expression != null) ? expression.getActualAsIdentifier() : AS, AS);
if (shouldOutput(expression) || expression.hasSpaceAfterAs()) {
writer.append(SPACE);
}
}
// Identification variable
stateObject.getIdentificationVariableStateObject().accept(this);
}
}
@Override
public void visit(JPQLQueryStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else if (stateObject.hasQueryStatement()) {
stateObject.getQueryStatement().accept(this);
}
}
@Override
public void visit(KeyExpressionStateObject stateObject) {
toStringEncapsulatedIdentificationVariable(stateObject);
}
@Override
public void visit(KeywordExpressionStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
KeywordExpression expression = stateObject.getExpression();
appendIdentifier((expression != null) ? expression.getActualIdentifier() : stateObject.getText(), stateObject.getText());
}
}
@Override
public void visit(LengthExpressionStateObject stateObject) {
toStringSingleEncapsulated(stateObject);
}
@Override
public void visit(LikeExpressionStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
LikeExpression expression = stateObject.getExpression();
// String expression
if (stateObject.hasStringStateObject()) {
stateObject.getStringStateObject().accept(this);
}
if (shouldOutput(expression) || expression.hasSpaceAfterStringExpression()) {
writer.append(SPACE);
}
// 'NOT'
if (stateObject.hasNot()) {
appendIdentifier((expression != null) ? expression.getActualNotIdentifier() : NOT, NOT);
writer.append(SPACE);
}
// 'LIKE'
appendIdentifier((expression != null) ? expression.getActualLikeIdentifier() : LIKE, LIKE);
if (shouldOutput(expression) || expression.hasSpaceAfterLike()) {
writer.append(SPACE);
}
// Pattern value
if (stateObject.hasPatternValue()) {
stateObject.getPatternValue().accept(this);
}
if (exactMatch && (expression != null) && expression.hasSpaceAfterPatternValue()) {
writer.append(SPACE);
}
// Escape character
if (stateObject.hasEscapeCharacter()) {
if (!exactMatch) {
writer.append(SPACE);
}
appendIdentifier((expression != null) ? expression.getActualEscapeIdentifier() : ESCAPE, ESCAPE);
if (shouldOutput(expression) || expression.hasSpaceAfterEscape()) {
writer.append(SPACE);
}
writer.append(stateObject.getEscapeCharacter());
}
}
}
@Override
public void visit(LocateExpressionStateObject stateObject) {
toStringTripleEncapsulated(stateObject);
}
@Override
public void visit(LowerExpressionStateObject stateObject) {
toStringSingleEncapsulated(stateObject);
}
@Override
public void visit(MaxFunctionStateObject stateObject) {
toStringAggregateFunction(stateObject);
}
@Override
public void visit(MinFunctionStateObject stateObject) {
toStringAggregateFunction(stateObject);
}
@Override
public void visit(ModExpressionStateObject stateObject) {
toStringDoubleEncapsulated(stateObject);
}
@Override
public void visit(MultiplicationExpressionStateObject stateObject) {
toStringCompound(stateObject, MULTIPLICATION);
}
@Override
public void visit(NotExpressionStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
NotExpression expression = stateObject.getExpression();
// 'NOT'
appendIdentifier((expression != null) ? expression.getActualIdentifier() : NOT, NOT);
if (shouldOutput(expression) || expression.hasSpaceAfterNot()) {
writer.append(SPACE);
}
// Expression
if (stateObject.hasStateObject()) {
stateObject.getStateObject().accept(this);
}
}
}
@Override
public void visit(NullComparisonExpressionStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
NullComparisonExpression expression = stateObject.getExpression();
// Expression
if (stateObject.hasStateObject()) {
stateObject.getStateObject().accept(this);
writer.append(SPACE);
}
// 'IS'
appendIdentifier((expression != null) ? expression.getActualIsIdentifier() : IS, IS);
writer.append(SPACE);
// 'NOT'
if (stateObject.hasNot()) {
appendIdentifier((expression != null) ? expression.getActualNotIdentifier() : NOT, NOT);
writer.append(SPACE);
}
// 'NULL'
appendIdentifier((expression != null) ? expression.getActualNullIdentifier() : NULL, NULL);
}
}
@Override
public void visit(NullIfExpressionStateObject stateObject) {
toStringDoubleEncapsulated(stateObject);
}
@Override
public void visit(NumericLiteralStateObject stateObject) {
toStringSimpleStateObject(stateObject);
}
@Override
public void visit(ObjectExpressionStateObject stateObject) {
toStringEncapsulatedIdentificationVariable(stateObject);
}
@Override
public void visit(OrderByClauseStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
OrderByClause expression = stateObject.getExpression();
// 'ORDER BY'
appendIdentifier((expression != null) ? expression.getActualIdentifier() : ORDER_BY, ORDER_BY);
if (shouldOutput(expression) || expression.hasSpaceAfterIdentifier()) {
writer.append(SPACE);
}
// Order by items
if (stateObject.hasItems()) {
toStringChildren(stateObject, true);
}
}
}
@Override
public void visit(OrderByItemStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
OrderByItem expression = stateObject.getExpression();
// Order by item
if (stateObject.hasStateObject()) {
stateObject.getStateObject().accept(this);
}
// ASC/DESC
if (!stateObject.isDefault()) {
if (shouldOutput(expression) || expression.hasSpaceAfterExpression()) {
writer.append(SPACE);
}
String ordering = stateObject.getOrdering().name();
String actualOrdering = (expression != null) ? expression.getActualOrdering() : null;
if (!ordering.equalsIgnoreCase(actualOrdering)) {
actualOrdering = ordering;
}
appendIdentifier(actualOrdering, ordering);
}
}
}
@Override
public void visit(OrExpressionStateObject stateObject) {
toStringCompound(stateObject, OR);
}
@Override
public void visit(RangeVariableDeclarationStateObject stateObject) {
toStringRangeVariableDeclaration(stateObject);
}
@Override
public void visit(ResultVariableStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
ResultVariable expression = stateObject.getExpression();
// Select expression
if (stateObject.hasStateObject()) {
stateObject.getStateObject().accept(this);
}
if (exactMatch && (expression != null) && expression.hasSelectExpression()) {
writer.append(SPACE);
}
// 'AS'
if (stateObject.hasAs()) {
if (!exactMatch || (expression == null)) {
writer.append(SPACE);
}
appendIdentifier((expression != null) ? expression.getActualAsIdentifier() : AS, AS);
}
if (exactMatch && (expression != null) && expression.hasSpaceAfterAs()) {
writer.append(SPACE);
}
// Result variable
if (stateObject.hasResultVariable()) {
if (!exactMatch || (expression == null)) {
writer.append(SPACE);
}
writer.append(stateObject.getResultVariable());
}
}
}
@Override
public void visit(SelectClauseStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
SelectClause expression = stateObject.getExpression();
// SELECT
appendIdentifier((expression != null) ? expression.getActualIdentifier() : SELECT, SELECT);
if (shouldOutput(expression) || expression.hasSpaceAfterSelect()) {
writer.append(SPACE);
}
// DISTINCT
if (stateObject.hasDistinct()) {
appendIdentifier((expression != null) ? expression.getActualDistinctIdentifier() : DISTINCT, DISTINCT);
if (shouldOutput(expression) || expression.hasSpaceAfterDistinct()) {
writer.append(SPACE);
}
}
// Select expressions
if (stateObject.hasItems()) {
toStringChildren(stateObject, true);
}
}
}
@Override
public void visit(SelectStatementStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
boolean endWithSpace = toStringSelectStatement(stateObject);
SelectStatement expression = stateObject.getExpression();
// If no ORDER BY clause was parsed but was added later, make sure a space is added
if (exactMatch && (expression != null) && expression.hasSpaceBeforeOrderBy() ||
stateObject.hasOrderByClause()) {
if (!endWithSpace) {
writer.append(SPACE);
}
}
// ORDER BY clause
if (stateObject.hasOrderByClause()) {
stateObject.getOrderByClause().accept(this);
}
}
}
@Override
public void visit(SimpleFromClauseStateObject stateObject) {
toStringFromClause(stateObject);
}
@Override
public void visit(SimpleSelectClauseStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
SimpleSelectClause expression = stateObject.getExpression();
// SELECT
appendIdentifier((expression != null) ? expression.getActualIdentifier() : SELECT, SELECT);
if (shouldOutput(expression) || expression.hasSpaceAfterSelect()) {
writer.append(SPACE);
}
// DISTINCT
if (stateObject.hasDistinct()) {
appendIdentifier((expression != null) ? expression.getActualDistinctIdentifier() : DISTINCT, DISTINCT);
if (shouldOutput(expression) || expression.hasSpaceAfterDistinct()) {
writer.append(SPACE);
}
}
// Select expression
if (stateObject.hasSelectItem()) {
stateObject.getSelectItem().accept(this);
}
}
}
@Override
public void visit(SimpleSelectStatementStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
toStringSelectStatement(stateObject);
}
}
@Override
public void visit(SizeExpressionStateObject stateObject) {
toStringSingleEncapsulated(stateObject);
}
@Override
public void visit(SqrtExpressionStateObject stateObject) {
toStringSingleEncapsulated(stateObject);
}
@Override
public void visit(StateFieldPathExpressionStateObject stateObject) {
toStringPathExpression(stateObject);
}
@Override
public void visit(StringLiteralStateObject stateObject) {
toStringSimpleStateObject(stateObject);
}
@Override
public void visit(SubExpressionStateObject stateObject) {
toStringSingleEncapsulated(stateObject);
}
@Override
public void visit(SubstringExpressionStateObject stateObject) {
toStringTripleEncapsulated(stateObject);
}
@Override
public void visit(SubtractionExpressionStateObject stateObject) {
toStringCompound(stateObject, MINUS);
}
@Override
public void visit(SumFunctionStateObject stateObject) {
toStringAggregateFunction(stateObject);
}
@Override
public void visit(TreatExpressionStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
TreatExpression expression = stateObject.getExpression();
// TREAT
appendIdentifier((expression != null) ? expression.getActualIdentifier() : TREAT, TREAT);
// (
if (shouldOutput(expression) || expression.hasLeftParenthesis()) {
writer.append(LEFT_PARENTHESIS);
}
// Join association path expression
stateObject.getJoinAssociationPathStateObject().accept(this);
if (shouldOutput(expression) || expression.hasSpaceAfterCollectionValuedPathExpression()) {
writer.append(SPACE);
}
// AS
if (stateObject.hasAs()) {
appendIdentifier((expression != null) ? expression.getActualAsIdentifier() : AS, AS);
if (shouldOutput(expression) || expression.hasSpaceAfterAs()) {
writer.append(SPACE);
}
}
// Entity type name
writer.append(stateObject.getEntityTypeName());
// )
if (shouldOutput(expression) || expression.hasRightParenthesis()) {
writer.append(RIGHT_PARENTHESIS);
}
}
}
@Override
public void visit(TrimExpressionStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
TrimExpression expression = stateObject.getExpression();
// 'TRIM'
appendIdentifier((expression != null) ? expression.getActualIdentifier() : stateObject.getIdentifier(), stateObject.getIdentifier());
// '('
if (shouldOutput(expression) || ( expression != null && expression.hasLeftParenthesis())) {
writer.append(LEFT_PARENTHESIS);
}
else if ((expression != null) && expression.hasSpaceAfterIdentifier()) {
writer.append(SPACE);
}
// Trim specification
if (stateObject.hasSpecification()) {
String specification = stateObject.getSpecification().name();
String actualSpecification = (expression != null) ? expression.getActualSpecificationIdentifier() : null;
if (!specification.equalsIgnoreCase(actualSpecification)) {
actualSpecification = specification;
}
appendIdentifier(actualSpecification, specification);
}
if (shouldOutput(expression) || expression.hasSpaceAfterSpecification()) {
writer.append(SPACE);
}
// Trim character
if (stateObject.hasTrimCharacter()) {
stateObject.getTrimCharacter().accept(this);
if (shouldOutput(expression) || expression.hasSpaceAfterTrimCharacter()) {
writer.append(SPACE);
}
}
// 'FROM'
if (stateObject.hasSpecification() ||
stateObject.hasTrimCharacter()) {
appendIdentifier((expression != null) ? expression.getActualFromIdentifier() : FROM, FROM);
if (shouldOutput(expression) || expression.hasSpaceAfterFrom()) {
writer.append(SPACE);
}
}
// String primary
if (stateObject.hasStateObject()) {
stateObject.getStateObject().accept(this);
}
// ')'
if (shouldOutput(expression) || expression.hasRightParenthesis()) {
writer.append(RIGHT_PARENTHESIS);
}
}
}
@Override
public void visit(TypeExpressionStateObject stateObject) {
toStringSingleEncapsulated(stateObject);
}
@Override
public void visit(UnknownExpressionStateObject stateObject) {
toStringSimpleStateObject(stateObject);
}
@Override
public void visit(UpdateClauseStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
UpdateClause expression = stateObject.getExpression();
// 'UPDATE'
appendIdentifier((expression != null) ? expression.getActualUpdateIdentifier() : UPDATE, UPDATE);
if (shouldOutput(expression) || expression.hasSpaceAfterUpdate()) {
writer.append(SPACE);
}
// Range variable declaration
stateObject.getRangeVariableDeclaration().accept(this);
if (shouldOutput(expression) || expression.hasSpaceAfterRangeVariableDeclaration()) {
writer.append(SPACE);
}
// 'SET'
if (shouldOutput(expression) || expression.hasSet()) {
appendIdentifier((expression != null) ? expression.getActualSetIdentifier() : SET, SET);
if (shouldOutput(expression) || expression.hasSpaceAfterSet()) {
writer.append(SPACE);
}
}
// Update items
if (stateObject.hasItems()) {
toStringChildren(stateObject, true);
}
}
}
@Override
public void visit(UpdateItemStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
UpdateItem expression = stateObject.getExpression();
// Update item
stateObject.getStateFieldPath().accept(this);
if (shouldOutput(expression) || expression.hasSpaceAfterStateFieldPathExpression()) {
writer.append(SPACE);
}
// '='
if (shouldOutput(expression) || expression.hasEqualSign()) {
writer.append(EQUAL);
}
if (shouldOutput(expression) || expression.hasSpaceAfterEqualSign()) {
writer.append(SPACE);
}
// New value
if (stateObject.hasNewValue()) {
stateObject.getNewValue().accept(this);
}
}
}
@Override
public void visit(UpdateStatementStateObject stateObject) {
toStringModifyStatement(stateObject);
}
@Override
public void visit(UpperExpressionStateObject stateObject) {
toStringSingleEncapsulated(stateObject);
}
@Override
public void visit(ValueExpressionStateObject stateObject) {
toStringEncapsulatedIdentificationVariable(stateObject);
}
@Override
public void visit(WhenClauseStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
WhenClause expression = stateObject.getExpression();
// 'WHEN'
appendIdentifier((expression != null) ? expression.getActualWhenIdentifier() : WHEN, WHEN);
if (shouldOutput(expression) || expression.hasSpaceAfterWhen()) {
writer.append(SPACE);
}
// WHEN expression
if (stateObject.hasConditional()) {
stateObject.getConditional().accept(this);
}
if (shouldOutput(expression) || expression.hasSpaceAfterWhenExpression()) {
writer.append(SPACE);
}
// 'THEN'
if (shouldOutput(expression) || expression.hasThen()) {
appendIdentifier((expression != null) ? expression.getActualThenIdentifier() : THEN, THEN);
}
if (shouldOutput(expression) || expression.hasSpaceAfterThen()) {
writer.append(SPACE);
}
// THEN expression
if (stateObject.hasThen()) {
stateObject.getThen().accept(this);
}
}
}
@Override
public void visit(WhereClauseStateObject stateObject) {
if (stateObject.isDecorated()) {
toText(stateObject);
}
else {
WhereClause expression = stateObject.getExpression();
// 'WHERE
appendIdentifier((expression != null) ? expression.getActualIdentifier() : WHERE, WHERE);
if (exactMatch && (expression != null) && expression.hasSpaceAfterIdentifier() ||
stateObject.hasConditional()) {
writer.append(SPACE);
}
// Conditional expression
if (stateObject.hasConditional()) {
stateObject.getConditional().accept(this);
}
}
}
}