org.eclipse.persistence.jpa.jpql.parser.UpdateClause Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eclipselink Show documentation
Show all versions of eclipselink Show documentation
EclipseLink build based upon Git transaction f2b9fc5
/*
* 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.parser;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.persistence.jpa.jpql.ExpressionTools;
import org.eclipse.persistence.jpa.jpql.WordParser;
/**
* This is the update clause of the update statement.
*
* An UPDATE statement provides bulk operations over sets of entities of a single entity
* class (together with its subclasses, if any). Only one entity abstract schema type may be
* specified in the UPDATE clause.
*
*
BNF: update_clause ::= UPDATE abstract_schema_name [[AS] identification_variable] SET update_item {, update_item}*
*
* @see UpdateStatement
* @see UpdateItem
*
* @version 2.5
* @since 2.3
* @author Pascal Filion
*/
public final class UpdateClause extends AbstractExpression {
/**
* Determines whether a whitespace was parsed after the abstract schema name declaration.
*/
private boolean hasSpaceAfterRangeVariableDeclaration;
/**
* Determines whether a whitespace was parsed after SET.
*/
private boolean hasSpaceAfterSet;
/**
* Determines whether a whitespace was parsed after UPDATE.
*/
private boolean hasSpaceAfterUpdate;
/**
* The {@link Expression} representing the range variable declaration.
*/
private AbstractExpression rangeVariableDeclaration;
/**
* The actual SET identifier found in the string representation of the JPQL query.
*/
private String setIdentifier;
/**
* The actual UPDATE identifier found in the string representation of the JPQL query.
*/
private String updateIdentifier;
/**
* The expression containing the update items.
*/
private AbstractExpression updateItems;
/**
* Creates a new UpdateClause
.
*
* @param parent The parent of this expression
*/
public UpdateClause(AbstractExpression parent) {
super(parent, UPDATE);
}
@Override
public void accept(ExpressionVisitor visitor) {
visitor.visit(this);
}
@Override
public void acceptChildren(ExpressionVisitor visitor) {
getRangeVariableDeclaration().accept(visitor);
getUpdateItems().accept(visitor);
}
@Override
protected void addChildrenTo(Collection children) {
children.add(getRangeVariableDeclaration());
children.add(getUpdateItems());
}
@Override
protected void addOrderedChildrenTo(List children) {
// 'UPDATE'
children.add(buildStringExpression(UPDATE));
if (hasSpaceAfterUpdate) {
children.add(buildStringExpression(SPACE));
}
// Range variable declaration
if (rangeVariableDeclaration != null) {
children.add(rangeVariableDeclaration);
}
if (hasSpaceAfterRangeVariableDeclaration) {
children.add(buildStringExpression(SPACE));
}
// 'SET'
if (setIdentifier != null) {
children.add(buildStringExpression(SET));
}
if (hasSpaceAfterSet) {
children.add(buildStringExpression(SPACE));
}
// Update items
if (updateItems != null) {
children.add(updateItems);
}
}
/**
* Creates a new {@link CollectionExpression} that will wrap the single update item.
*
* @return The single update item represented by a temporary collection
*/
public CollectionExpression buildCollectionExpression() {
List children = new ArrayList<>(1);
children.add((AbstractExpression) getUpdateItems());
List commas = new ArrayList<>(1);
commas.add(Boolean.FALSE);
List spaces = new ArrayList<>(1);
spaces.add(Boolean.FALSE);
return new CollectionExpression(this, children, commas, spaces, true);
}
@Override
public JPQLQueryBNF findQueryBNF(Expression expression) {
if ((rangeVariableDeclaration != null) && rangeVariableDeclaration.isAncestor(expression)) {
return getQueryBNF(RangeVariableDeclarationBNF.ID);
}
if ((updateItems != null) && updateItems.isAncestor(expression)) {
return getQueryBNF(InternalUpdateClauseBNF.ID);
}
return super.findQueryBNF(expression);
}
/**
* Returns the actual SET found in the string representation of the JPQL query, which has
* the actual case that was used.
*
* @return The SET identifier that was actually parsed, or an empty string if it was not parsed
*/
public String getActualSetIdentifier() {
return (setIdentifier != null) ? setIdentifier : ExpressionTools.EMPTY_STRING;
}
/**
* Returns the actual UPDATE found in the string representation of the JPQL query, which
* has the actual case that was used.
*
* @return The UPDATE identifier that was actually parsed
*/
public String getActualUpdateIdentifier() {
return updateIdentifier;
}
@Override
public JPQLQueryBNF getQueryBNF() {
return getQueryBNF(UpdateClauseBNF.ID);
}
/**
* Returns the {@link Expression} representing the range variable declaration.
*
* @return The expression that was parsed representing the range variable declaration
*/
public Expression getRangeVariableDeclaration() {
if (rangeVariableDeclaration == null) {
rangeVariableDeclaration = buildNullExpression();
}
return rangeVariableDeclaration;
}
/**
* Returns the {@link Expression} representing the single update item or the collection of update items.
*
* @return The expression that was parsed representing the single or multiple update items
*/
public Expression getUpdateItems() {
if (updateItems == null) {
updateItems = buildNullExpression();
}
return updateItems;
}
/**
* Determines whether the range variable declaration was parsed.
*
* @return true
if the range variable declaration was parsed; false
otherwise
*/
public boolean hasRangeVariableDeclaration() {
return rangeVariableDeclaration != null &&
!rangeVariableDeclaration.isNull();
}
/**
* Determines whether SET was parsed or not.
*
* @return true
if SET was part of the query; false
otherwise
*/
public boolean hasSet() {
return setIdentifier != null;
}
/**
* Determines whether a whitespace was found after the abstract schema name declaration.
*
* @return true
if there was a whitespace after the abstract schema name declaration;
* false
otherwise
*/
public boolean hasSpaceAfterRangeVariableDeclaration() {
return hasSpaceAfterRangeVariableDeclaration;
}
/**
* Determines whether a whitespace was found after SET.
*
* @return true
if there was a whitespace after SET; false
otherwise
*/
public boolean hasSpaceAfterSet() {
return hasSpaceAfterSet;
}
/**
* Determines whether a whitespace was found after the identifier UPDATE.
*
* @return true
if there was a whitespace after the identifier UPDATE;
* false
otherwise
*/
public boolean hasSpaceAfterUpdate() {
return hasSpaceAfterUpdate;
}
/**
* Determines whether the update items section of the query was parsed.
*
* @return true
if something was parsed after SET even if it was a malformed
* expression; false
if nothing was parsed
*/
public boolean hasUpdateItems() {
return updateItems != null &&
!updateItems.isNull();
}
@Override
protected boolean isParsingComplete(WordParser wordParser, String word, Expression expression) {
return word.equalsIgnoreCase(SET) ||
super.isParsingComplete(wordParser, word, expression);
}
@Override
protected void parse(WordParser wordParser, boolean tolerant) {
// Parse 'UPDATE'
updateIdentifier = wordParser.moveForward(UPDATE);
hasSpaceAfterUpdate = wordParser.skipLeadingWhitespace() > 0;
// Parse the abstract schema name
if (tolerant && !wordParser.startsWithIdentifier(SET)) {
rangeVariableDeclaration = parse(
wordParser,
RangeVariableDeclarationBNF.ID,
tolerant
);
}
else if (!tolerant) {
rangeVariableDeclaration = new RangeVariableDeclaration(this);
rangeVariableDeclaration.parse(wordParser, tolerant);
}
hasSpaceAfterRangeVariableDeclaration = wordParser.skipLeadingWhitespace() > 0;
// Parse 'SET'
if (!tolerant || wordParser.startsWithIdentifier(SET)) {
setIdentifier = wordParser.moveForward(SET);
hasSpaceAfterSet = wordParser.skipLeadingWhitespace() > 0;
}
// Parse update items
updateItems = parse(wordParser, InternalUpdateClauseBNF.ID, tolerant);
}
@Override
protected void toParsedText(StringBuilder writer, boolean actual) {
// 'UPDATE'
writer.append(actual ? updateIdentifier : UPDATE);
if (hasSpaceAfterUpdate) {
writer.append(SPACE);
}
// Range variable declaration
if (rangeVariableDeclaration != null) {
rangeVariableDeclaration.toParsedText(writer, actual);
}
if (hasSpaceAfterRangeVariableDeclaration) {
writer.append(SPACE);
}
// 'SET'
if (setIdentifier != null) {
writer.append(actual ? setIdentifier : SET);
}
if (hasSpaceAfterSet) {
writer.append(SPACE);
}
// Update items
if (updateItems != null) {
updateItems.toParsedText(writer, actual);
}
}
}