blob: 5c2a88da9c02a88d4f374be72f078999d63b794e [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
//
// 09/02/2019-3.0 Alexandre Jacob
// - 527415: Fix code when locale is tr, az or lt
package org.eclipse.persistence.jpa.jpql.parser;
import java.util.List;
import java.util.Locale;
import org.eclipse.persistence.jpa.jpql.WordParser;
/**
* An identification variable is a valid identifier declared in the <b>FROM</b> clause of a query.
* <p>
* Requirements:
* <ul>
* <li>All identification variables must be declared in the <b>FROM</b> clause. Identification
* variables cannot be declared in other clauses.
* <li>An identification variable must not be a reserved identifier or have the same name as any
* entity in the same persistence unit.
* <li>Identification variables are case insensitive.
* <li>An identification variable evaluates to a value of the type of the expression used in
* declaring the variable.
* </ul>
* <p>
* An identification variable can range over an entity, embeddable, or basic abstract schema type.
* An identification variable designates an instance of an abstract schema type or an element of a
* collection of abstract schema type instances.
* <p>
* Note that for identification variables referring to an instance of an association or collection
* represented as a {@link java.util.Map}, the identification variable is of the abstract schema
* type of the map value.
* <p>
* An identification variable always designates a reference to a single value. It is declared in one
* of three ways:
* <ul>
* <li>In a range variable declaration;
* <li>In a join clause;
* <li>In a collection member declaration.
* </ul>
* The identification variable declarations are evaluated from left to right in the <b>FROM</b>
* clause, and an identification variable declaration can use the result of a preceding
* identification variable declaration of the query string.
* <p>
* All identification variables used in the <b>SELECT</b>, <b>WHERE</b>, <b>ORDER BY</b>,
* <b>GROUP BY</b>, or <b>HAVING</b> clause of a <b>SELECT</b> or <b>DELETE</b> statement must be
* declared in the <b>FROM</b> clause. The identification variables used in the <b>WHERE</b> clause
* of an <b>UPDATE</b> statement must be declared in the <b>UPDATE</b> clause.
* <p>
* An identification variable is scoped to the query (or subquery) in which it is defined and is
* also visible to any subqueries within that query scope that do not define an identification
* variable of the same name.
*
* @version 2.4
* @since 2.3
* @author Pascal Filion
*/
public final class IdentificationVariable extends AbstractExpression {
/**
* The virtual state field path expression having
*/
private StateFieldPathExpression stateFieldPathExpression;
/**
* The uppercase version of the identification variable.
*/
private String variableName;
/**
* Determines whether this identification variable is virtual, meaning it's not part of the query
* but is required for proper navigability.
*/
private boolean virtual;
/**
* Creates a new <code>IdentificationVariable</code>.
*
* @param parent The parent of this expression
* @param identificationVariable The actual identification variable
*/
public IdentificationVariable(AbstractExpression parent, String identificationVariable) {
super(parent, identificationVariable);
}
/**
* Creates a new <code>IdentificationVariable</code>.
*
* @param parent The parent of this expression
* @param identificationVariable The actual identification variable
* @param virtual Determines whether this identification variable is virtual, meaning it's not
* part of the query but is required for proper navigability
*/
public IdentificationVariable(AbstractExpression parent, String identificationVariable, boolean virtual) {
super(parent, identificationVariable);
this.virtual = virtual;
}
@Override
public void accept(ExpressionVisitor visitor) {
visitor.visit(this);
}
@Override
public void acceptChildren(ExpressionVisitor visitor) {
// Nothing to traverse
}
@Override
protected void addOrderedChildrenTo(List<Expression> children) {
children.add(buildStringExpression(getText()));
}
@Override
public JPQLQueryBNF getQueryBNF() {
return getQueryBNF(IdentificationVariableBNF.ID);
}
/**
* Returns the actual representation of the parsed information. This method should only be called
* if {@link #isVirtual()} returns <code>true</code>. This is valid in an <b>UPDATE</b> and
* <b>DELETE</b> queries where the identification variable is not specified.
*
* @return The path expression that is qualified by the virtual identification variable
* @throws IllegalAccessError If this expression does not have a virtual identification variable
*/
@SuppressWarnings("nls")
public StateFieldPathExpression getStateFieldPathExpression() {
if (!virtual) {
throw new IllegalAccessError("IdentificationVariable.getStateFieldPathExpression() can only be accessed when it represents an attribute that is not fully qualified, which can be present in an UPDATE or DELETE query.");
}
return stateFieldPathExpression;
}
@Override
public String getText() {
return super.getText();
}
/**
* Returns the identification variable, which has been changed to be upper case.
*
* @return The uppercase version of the identification variable
* @since 2.4
*/
public String getVariableName() {
if (variableName == null) {
variableName = getText().toUpperCase(Locale.ROOT).intern();
}
return variableName;
}
@Override
public boolean isVirtual() {
return virtual;
}
@Override
protected void parse(WordParser wordParser, boolean tolerant) {
wordParser.moveForward(getText());
}
/**
* Sets a virtual identification variable because the abstract schema name was parsed without
* one. This is valid in an <b>UPDATE</b> and <b>DELETE</b> queries. This internally transforms
* the what was thought to be an identification variable to a path expression.
*
* @param variableName The identification variable that was generated to identify the "root" object
*/
public void setVirtualIdentificationVariable(String variableName) {
virtual = true;
stateFieldPathExpression = new StateFieldPathExpression(getParent(), getText());
stateFieldPathExpression.setVirtualIdentificationVariable(variableName);
rebuildActualText();
rebuildParsedText();
}
@Override
public String toParsedText() {
return getText();
}
@Override
protected void toParsedText(StringBuilder writer, boolean actual) {
writer.append(getText());
}
}