diff --git a/jpa/eclipselink.jpa.testapps/jpa.test.jpql/src/test/java/org/eclipse/persistence/testing/tests/jpa/jpql/advanced/JUnitJPQLJakartaDataNoAliasTest.java b/jpa/eclipselink.jpa.testapps/jpa.test.jpql/src/test/java/org/eclipse/persistence/testing/tests/jpa/jpql/advanced/JUnitJPQLJakartaDataNoAliasTest.java
index 8a65a870280..d056cac9e3c 100644
--- a/jpa/eclipselink.jpa.testapps/jpa.test.jpql/src/test/java/org/eclipse/persistence/testing/tests/jpa/jpql/advanced/JUnitJPQLJakartaDataNoAliasTest.java
+++ b/jpa/eclipselink.jpa.testapps/jpa.test.jpql/src/test/java/org/eclipse/persistence/testing/tests/jpa/jpql/advanced/JUnitJPQLJakartaDataNoAliasTest.java
@@ -20,8 +20,11 @@
import junit.framework.Test;
import junit.framework.TestSuite;
import org.eclipse.persistence.queries.ReadObjectQuery;
+import org.eclipse.persistence.sessions.server.ServerSession;
import org.eclipse.persistence.testing.framework.jpa.junit.JUnitTestCase;
+import org.eclipse.persistence.testing.models.jpa.advanced.AdvancedTableCreator;
import org.eclipse.persistence.testing.models.jpa.advanced.EmployeePopulator;
+import org.eclipse.persistence.testing.models.jpa.advanced.Room;
import org.eclipse.persistence.testing.models.jpa.datatypes.DataTypesTableCreator;
import org.eclipse.persistence.testing.models.jpa.datatypes.WrapperTypes;
import org.eclipse.persistence.testing.tests.jpa.jpql.JUnitDomainObjectComparer;
@@ -29,11 +32,7 @@
import java.math.BigDecimal;
import java.math.BigInteger;
-import java.util.List;
import java.util.stream.Stream;
-import org.eclipse.persistence.sessions.server.ServerSession;
-import org.eclipse.persistence.testing.models.jpa.advanced.AdvancedTableCreator;
-import org.eclipse.persistence.testing.models.jpa.advanced.Room;
/**
*
@@ -53,14 +52,14 @@ public class JUnitJPQLJakartaDataNoAliasTest extends JUnitTestCase {
private static final String STRING_DATA = "A String";
private static final String STRING_DATA_LIKE_EXPRESSION = "A%"; // should match STRING_DATA
- private static final Room[] ROOMS = new Room[]{
- null, // Skip array index 0
- aRoom(1, 1, 1, 1),
- aRoom(2, 1, 1, 1),
- aRoom(3, 1, 1, 1),
- aRoom(4, 1, 1, 1)
+ private static final Room[] ROOMS = new Room[] {
+ null, // Skip array index 0
+ aRoom(1, 1, 1, 1),
+ aRoom(2, 1, 1, 1),
+ aRoom(3, 1, 1, 1),
+ aRoom(4, 1, 1, 1)
};
- private static final long ROOMS_COUNT = ROOMS.length - 1; // we ignore the first one with index 0
+ private static final long ROOMS_COUNT = ROOMS.length -1; // we ignore the first one with index 0
private static int wrapperId;
@@ -102,11 +101,6 @@ public static Test suite() {
suite.addTest(new JUnitJPQLJakartaDataNoAliasTest("testNoAliasFromWhereAndUPPER"));
suite.addTest(new JUnitJPQLJakartaDataNoAliasTest("testGeneratedSelectNoAliasFromWhere"));
suite.addTest(new JUnitJPQLJakartaDataNoAliasTest("testGeneratedSelect"));
- suite.addTest(new JUnitJPQLJakartaDataNoAliasTest("testUpdateQueryLengthInAssignmentAndExpression"));
- suite.addTest(new JUnitJPQLJakartaDataNoAliasTest("testSelectQueryLengthInAssignmentAndExpression"));
- suite.addTest(new JUnitJPQLJakartaDataNoAliasTest("testUpdateImplicitVariableInArithmeticExpression"));
- suite.addTest(new JUnitJPQLJakartaDataNoAliasTest("testDeleteQueryLengthInExpressionOnLeft"));
- suite.addTest(new JUnitJPQLJakartaDataNoAliasTest("testDeleteQueryLengthInExpressionOnRight"));
suite.addTest(new JUnitJPQLJakartaDataNoAliasTest("tesUpdateQueryWithThisVariable"));
suite.addTest(new JUnitJPQLJakartaDataNoAliasTest("testThisVariableInPathExpressionUpdate"));
suite.addTest(new JUnitJPQLJakartaDataNoAliasTest("testThisVariableInPathExpressionDelete"));
@@ -265,55 +259,6 @@ public void testGeneratedSelectNoAliasFromWhere() {
Assert.assertTrue("GeneratedSelectNoAliasFromWhere Test Failed", comparer.compareObjects(wrapperTypes, tlWrapperTypes));
}
- public void testUpdateQueryLengthInAssignmentAndExpression() {
- resetRooms();
- long numberOfChanges = getEntityManagerFactory().callInTransaction(em -> em.createQuery(
- "UPDATE Room SET length = length + 1").executeUpdate());
- assertTrue("All rooms should be updated", numberOfChanges == ROOMS_COUNT);
-
- long numberOfRoomsWithLengthChanged = getAllRooms()
- .filter(room -> room.getLength() == 2)
- .count();
- assertTrue("All rooms should have increased length", numberOfRoomsWithLengthChanged == ROOMS_COUNT);
- }
-
- public void testSelectQueryLengthInAssignmentAndExpression() {
- resetRooms();
- List roomsWithIdOne = getEntityManagerFactory().callInTransaction(em -> em.createQuery(
- "SELECT this FROM Room WHERE id + length = length + 1", Room.class).getResultList());
- assertTrue("Number of rooms with ID = 1", roomsWithIdOne.size() == 1);
- }
-
- public void testUpdateImplicitVariableInArithmeticExpression() {
- resetRooms();
- int numberOfChanges = getEntityManagerFactory().callInTransaction(em -> em.createQuery(
- "UPDATE Room SET width = width * :widthMultiplicator WHERE id = :id")
- .setParameter("widthMultiplicator", 5)
- .setParameter("id", 1)
- .executeUpdate());
- assertTrue("Number of rooms with ID = 1 updated", numberOfChanges == 1);
- int roomWidth = findRoomById(1).getWidth();
- assertTrue("Room ID = 1 has width of ", roomWidth == 5);
- }
-
- public void testDeleteQueryLengthInExpressionOnLeft() {
- resetRooms();
- assertTrue("Number of remaining rooms", getAllRooms().count() == ROOMS_COUNT);
- int numberOfChanges = getEntityManagerFactory().callInTransaction(em -> em.createQuery(
- "DELETE FROM Room WHERE length = id - 1").executeUpdate());
- long allRoomsCount = getAllRooms().count();
- assertTrue("Number of rooms with ID = 1 deleted", numberOfChanges == 1);
- assertTrue("Number of remaining rooms", allRoomsCount == ROOMS_COUNT - 1);
- }
-
- public void testDeleteQueryLengthInExpressionOnRight() {
- resetRooms();
- int numberOfChanges = getEntityManagerFactory().callInTransaction(em -> em.createQuery(
- "DELETE FROM Room WHERE id = length + 1").executeUpdate());
- assertTrue("Number of rooms with ID = 1 deleted", numberOfChanges == 1);
- assertTrue("Number of remaining rooms", getAllRooms().count() == ROOMS_COUNT - 1);
- }
-
public void tesUpdateQueryWithThisVariable() {
resetRooms();
long numberOfChanges = getEntityManagerFactory().callInTransaction(em -> em.createQuery(
diff --git a/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/WordParser.java b/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/WordParser.java
index 58a3343db4f..57265e47bde 100644
--- a/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/WordParser.java
+++ b/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/WordParser.java
@@ -1,7 +1,6 @@
/*
* Copyright (c) 2006, 2022 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022 IBM Corporation. All rights reserved.
- * Copyright (c) 2024 Contributors to the Eclipse Foundation. 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
@@ -257,7 +256,6 @@ public int length() {
*/
public void moveBackward(CharSequence word) {
cursor -= word.length();
- wordEndPosition();
}
/**
diff --git a/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/AbstractEncapsulatedExpression.java b/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/AbstractEncapsulatedExpression.java
index f4126450b6c..c62cc48b58b 100644
--- a/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/AbstractEncapsulatedExpression.java
+++ b/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/AbstractEncapsulatedExpression.java
@@ -1,6 +1,5 @@
/*
* Copyright (c) 2006, 2023 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2024 Contributors to the Eclipse Foundation. 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
@@ -307,19 +306,4 @@ else if (hasSpaceAfterIdentifier) {
* like content assist
*/
protected abstract void toParsedTextEncapsulatedExpression(StringBuilder writer, boolean actual);
-
- /**
- * Should be reverted if Jakarta Data mode is enabled and the expression doesn't contain parenthesis.
- * For example, the query {@code delete from Box where length = 1} contains function name {@code length}.
- * The function {@code length} expects parameters but there are not parameters in the query.
- * Then {@code length} is not a function but a state field with an implicit identification variable this, ie.
- * the query is equivalent to {@code delete from Box where this.length = 1}.
- *
- * @return Should be reverted and parsed again as a different expression or should be accepted as parsed expression
- */
- @Override
- protected boolean isInvalid() {
- return getRoot().isJakartaData() && !hasLeftParenthesis();
- }
-
}
diff --git a/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/AbstractExpression.java b/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/AbstractExpression.java
index a6e2e034a04..bb77a0becc1 100644
--- a/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/AbstractExpression.java
+++ b/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/AbstractExpression.java
@@ -1,6 +1,5 @@
/*
* Copyright (c) 2006, 2024 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2024 Contributors to the Eclipse Foundation. 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
@@ -16,7 +15,6 @@
//
package org.eclipse.persistence.jpa.jpql.parser;
-
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.AccessController;
@@ -518,22 +516,6 @@ public final JPQLExpression getRoot() {
return (parent == null) ? (JPQLExpression) this : parent.getRoot();
}
- /**
- * Returns closest nested expression that encapsulates this expression,
- * or the root expression if not inside a nested expression.
- *
- * @return Parent expression
- */
- public final ParentExpression getParentExpression() {
- if (this instanceof ParentExpression parentExpression) {
- return parentExpression;
- } else if (parent == null) {
- return null;
- } else {
- return parent.getParentExpression();
- }
- }
-
/**
* Returns the encapsulated text of this {@link AbstractExpression}, which can be used in various
* ways, it can be a keyword, a literal, etc.
@@ -787,9 +769,6 @@ tolerant && isParsingComplete(wordParser, word, expression)) {
if (factory != null) {
child = factory.buildExpression(this, wordParser, word, queryBNF, expression, tolerant);
- // if an invalid expression came from the factory, ignore it and try fallback
- child = revertExpressionIfInvalid(child, wordParser, word);
-
if (child != null) {
// The new expression is a child of the previous expression,
@@ -1009,14 +988,6 @@ else if (currentInfo != null) {
);
}
- static AbstractExpression revertExpressionIfInvalid(AbstractExpression expression, WordParser wordParser, String word) {
- if (expression != null && expression.isInvalid()) {
- wordParser.moveBackward(word);
- return null;
- }
- return expression;
- }
-
/**
* Right away parses the text by retrieving the {@link ExpressionFactory} for the first word that
* is extracted from {@link WordParser} at the current location.
@@ -1162,17 +1133,6 @@ public String toParsedText() {
*/
protected abstract void toParsedText(StringBuilder writer, boolean actual);
- /**
- * Whether this expression is not valid and should be discarded. If it returns true,
- * the parser will be reverted to the state before this expression was parsed
- * and it will attempt to parse a different expression.
- *
- * @return True if this expression is invalid and should be discarded, otherwise false. By default returns false, should be overriden if expression should be reverted.
- */
- protected boolean isInvalid() {
- return false;
- }
-
@Override
public final String toString() {
// toString() should only be called during debugging, thus the cached parsed text
diff --git a/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/AbstractFromClause.java b/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/AbstractFromClause.java
index de7cc021dae..5a1af5a8ef9 100644
--- a/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/AbstractFromClause.java
+++ b/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/AbstractFromClause.java
@@ -1,6 +1,5 @@
/*
* Copyright (c) 2006, 2024 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2024 Contributors to the Eclipse Foundation. 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
@@ -344,7 +343,7 @@ else if (hierarchicalQueryClause == null) {
identificationVariableDeclaration.hasRangeVariableDeclaration() && identificationVariableDeclaration.getRangeVariableDeclaration() instanceof RangeVariableDeclaration rangeVariableDeclaration &&
rangeVariableDeclaration.hasIdentificationVariable() && rangeVariableDeclaration.getIdentificationVariable() instanceof IdentificationVariable identificationVariable &&
Expression.THIS.equals(identificationVariable.getText())) {
- this.getParentExpression().setGenerateThisPrefix(true);
+ this.getRoot().setGenerateThisPrefix(true);
}
}
diff --git a/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/AbstractLiteralExpressionFactory.java b/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/AbstractLiteralExpressionFactory.java
index d98729261b2..5044ec99180 100644
--- a/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/AbstractLiteralExpressionFactory.java
+++ b/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/AbstractLiteralExpressionFactory.java
@@ -1,7 +1,6 @@
/*
* Copyright (c) 2006, 2021 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2024 Contributors to the Eclipse Foundation. 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,
@@ -65,64 +64,67 @@ protected AbstractExpression buildExpression(AbstractExpression parent,
WordParser wordParser,
String word,
JPQLQueryBNF queryBNF,
- final AbstractExpression expression,
+ AbstractExpression expression,
boolean tolerant) {
switch (wordParser.getWordType()) {
case NUMERIC_LITERAL: {
- NumericLiteral numericLiteral = new NumericLiteral(parent, word);
- numericLiteral.parse(wordParser, tolerant);
- return numericLiteral;
+ expression = new NumericLiteral(parent, word);
+ expression.parse(wordParser, tolerant);
+ return expression;
}
case STRING_LITERAL: {
- StringLiteral stringLiteral = new StringLiteral(parent, word);
- stringLiteral.parse(wordParser, tolerant);
- return stringLiteral;
+ expression = new StringLiteral(parent, word);
+ expression.parse(wordParser, tolerant);
+ return expression;
}
case INPUT_PARAMETER: {
- InputParameter inputParameter = new InputParameter(parent, word);
- inputParameter.parse(wordParser, tolerant);
- return inputParameter;
+ expression = new InputParameter(parent, word);
+ expression.parse(wordParser, tolerant);
+ return expression;
}
+ }
- default: {
- // Path expression
- if (word.indexOf(AbstractExpression.DOT) > -1) {
- char character = word.charAt(0);
- AbstractPathExpression pathExpression;
-
- if ((expression != null) && (character == AbstractExpression.DOT)) {
- if (isCollection()) {
- pathExpression = new CollectionValuedPathExpression(parent, expression, word);
- } else {
- pathExpression = new StateFieldPathExpression(parent, expression, word);
- }
- } else {
- if (isCollection()) {
- pathExpression = new CollectionValuedPathExpression(parent, word);
- } else {
- pathExpression = new StateFieldPathExpression(parent, word);
- }
- }
-
- pathExpression.parse(wordParser, tolerant);
- return pathExpression;
+ // Path expression
+ if (word.indexOf(AbstractExpression.DOT) > -1) {
+ char character = word.charAt(0);
+
+ if ((expression != null) && (character == AbstractExpression.DOT)) {
+ if (isCollection()) {
+ expression = new CollectionValuedPathExpression(parent, expression, word);
+ }
+ else {
+ expression = new StateFieldPathExpression(parent, expression, word);
}
+ }
+ else {
+ if (isCollection()) {
+ expression = new CollectionValuedPathExpression(parent, word);
+ }
+ else {
+ expression = new StateFieldPathExpression(parent, word);
+ }
+ }
- // Checks for invalid JPQL queries
+ expression.parse(wordParser, tolerant);
+ return expression;
+ }
- if (tolerant && getExpressionRegistry().isIdentifier(word)) {
- // Before creating the expression, check to make sure it's not a function: 'identifier('
- AbstractExpression identifierExpression;
- identifierExpression = getIdentifierExpression(parent, wordParser, word, queryBNF, expression, tolerant);
- if (identifierExpression != null) {
- return new BadExpression(parent, identifierExpression);
- }
- }
+ // Checks for invalid JPQL queries
+ ExpressionRegistry registry = getExpressionRegistry();
+ if (tolerant && registry.isIdentifier(word)) {
+ ExpressionFactory factory = registry.expressionFactoryForIdentifier(word);
+ // TODO: Before creating the expression, check to make sure it's not a function: 'identifier('
+ if (factory != null) {
+ expression = factory.buildExpression(parent, wordParser, word, queryBNF, expression, tolerant);
+
+ if (expression != null) {
+ return new BadExpression(parent, expression);
+ }
}
}
@@ -136,16 +138,4 @@ protected AbstractExpression buildExpression(AbstractExpression parent,
protected boolean isCollection() {
return false;
}
-
- private AbstractExpression getIdentifierExpression(AbstractExpression parent, WordParser wordParser, String word, JPQLQueryBNF queryBNF, AbstractExpression expression, boolean tolerant) {
- ExpressionFactory factory = getExpressionRegistry().expressionFactoryForIdentifier(word);
- // TODO: Before creating the expression, check to make sure it's not a function: 'identifier('
- if (factory != null) {
- final AbstractExpression identifierExpression = factory.buildExpression(parent, wordParser, word, queryBNF, expression, tolerant);
-
- // if an invalid expression came from the factory, e.g. a function without expected arguments, ignore it
- return AbstractExpression.revertExpressionIfInvalid(identifierExpression, wordParser, word);
- }
- return null;
- }
}
diff --git a/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/ExpressionFactory.java b/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/ExpressionFactory.java
index 3eb7c089145..ca6a990605a 100644
--- a/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/ExpressionFactory.java
+++ b/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/ExpressionFactory.java
@@ -1,6 +1,5 @@
/*
* Copyright (c) 2006, 2024 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2024 Contributors to the Eclipse Foundation. 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
diff --git a/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/IdentificationVariable.java b/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/IdentificationVariable.java
index 822da4d76f0..84ab752f195 100644
--- a/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/IdentificationVariable.java
+++ b/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/IdentificationVariable.java
@@ -1,6 +1,5 @@
/*
* Copyright (c) 2006, 2024 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2024 Contributors to the Eclipse Foundation. 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
@@ -95,7 +94,7 @@ public final class IdentificationVariable extends AbstractExpression {
*/
public IdentificationVariable(AbstractExpression parent, String identificationVariable) {
super(parent, identificationVariable);
- if (!Expression.THIS.equalsIgnoreCase(identificationVariable) && getParentExpression().isGenerateThisPrefix()) {
+ if (!Expression.THIS.equalsIgnoreCase(identificationVariable) && getRoot().isGenerateThisPrefix()) {
this.setVirtualIdentificationVariable(Expression.THIS);
}
}
@@ -117,7 +116,7 @@ public IdentificationVariable(AbstractExpression parent, String identificationVa
public void accept(ExpressionVisitor visitor) {
//In "this" (Jakarta Data) generation mode pass for a validation stateFieldPathExpression
//generated by this.setVirtualIdentificationVariable(Expression.THIS); in constructor above
- if (getParentExpression().isGenerateThisPrefix() && isVirtual() && stateFieldPathExpression != null) {
+ if (getRoot().isGenerateThisPrefix() && isVirtual() && stateFieldPathExpression != null) {
visitor.visit(getStateFieldPathExpression());
} else {
visitor.visit(this);
diff --git a/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/JPQLExpression.java b/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/JPQLExpression.java
index e31a0e75e15..0bcd22f92d4 100644
--- a/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/JPQLExpression.java
+++ b/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/JPQLExpression.java
@@ -1,6 +1,5 @@
/*
* Copyright (c) 2006, 2024 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2024 Contributors to the Eclipse Foundation. 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
@@ -42,7 +41,7 @@
* @author Pascal Filion
*/
@SuppressWarnings("nls")
-public final class JPQLExpression extends AbstractExpression implements ParentExpression {
+public final class JPQLExpression extends AbstractExpression {
/**
* The JPQL grammar that defines how to parse a JPQL query.
@@ -89,6 +88,9 @@ public final class JPQLExpression extends AbstractExpression implements ParentEx
*/
private boolean jakartaData = false;
+ /**
+ * Automatically add missing "this" prefixes into where field variables if it doesn't exist.
+ */
private boolean generateThisPrefix = false;
/**
@@ -256,12 +258,10 @@ public JPQLQueryBNF getQueryBNF() {
return getQueryBNF(queryBNFId);
}
- @Override
public boolean isGenerateThisPrefix() {
return generateThisPrefix;
}
- @Override
public void setGenerateThisPrefix(boolean generateThisPrefix) {
this.generateThisPrefix = generateThisPrefix;
}
diff --git a/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/LengthExpressionFactory.java b/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/LengthExpressionFactory.java
index f989be011b9..b6aa05a11ba 100644
--- a/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/LengthExpressionFactory.java
+++ b/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/LengthExpressionFactory.java
@@ -1,6 +1,5 @@
/*
* Copyright (c) 2006, 2021 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2024 Contributors to the Eclipse Foundation. 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
@@ -54,5 +53,4 @@ protected AbstractExpression buildExpression(AbstractExpression parent,
expression.parse(wordParser, tolerant);
return expression;
}
-
}
diff --git a/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/ParentExpression.java b/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/ParentExpression.java
deleted file mode 100644
index a036090fa8d..00000000000
--- a/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/ParentExpression.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2024 Contributors to the Eclipse Foundation.
- *
- * 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:
-// 21/07/2024: Ondro Mihalyi - implicit variable in sub-expressions
-package org.eclipse.persistence.jpa.jpql.parser;
-
-public interface ParentExpression extends Expression {
-
- /**
- * Whether should automatically add missing "this" prefix into where field variables if it doesn't exist.
- */
- boolean isGenerateThisPrefix();
-
- void setGenerateThisPrefix(boolean generateThisPrefix);
-
-}
diff --git a/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/RangeVariableDeclaration.java b/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/RangeVariableDeclaration.java
index 6d74dd38351..8dfff4f2e4a 100644
--- a/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/RangeVariableDeclaration.java
+++ b/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/RangeVariableDeclaration.java
@@ -1,6 +1,5 @@
/*
* Copyright (c) 2006, 2024 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2024 Contributors to the Eclipse Foundation. 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
@@ -276,16 +275,19 @@ protected void parse(WordParser wordParser, boolean tolerant) {
hasSpaceAfterAs = wordParser.skipLeadingWhitespace() > 0;
}
- if (tolerant) {
- identificationVariable = parse(wordParser, IdentificationVariableBNF.ID, tolerant);
- if (identificationVariable == null && this.getRoot().isJakartaData()) {
- addMissingAlias(Expression.THIS);
+ // Special case when parsing the range variable declaration of an UPDATE clause that does
+ // not have an identification variable, e.g. "UPDATE DateTime SET date = CURRENT_DATE"
+ if (!wordParser.startsWithIdentifier(SET)) {
+ if (tolerant) {
+ identificationVariable = parse(wordParser, IdentificationVariableBNF.ID, tolerant);
+ if (identificationVariable == null && this.getRoot().isJakartaData()) {
+ addMissingAlias(Expression.THIS);
+ }
+ }
+ else {
+ identificationVariable = new IdentificationVariable(this, wordParser.word());
+ identificationVariable.parse(wordParser, tolerant);
}
- } else if (!wordParser.startsWithIdentifier(SET)) {
- // We need to avoid the special valid case when parsing the range variable declaration of an UPDATE clause that does
- // not have an identification variable, e.g. "UPDATE DateTime SET date = CURRENT_DATE"
- identificationVariable = new IdentificationVariable(this, wordParser.word());
- identificationVariable.parse(wordParser, tolerant);
}
}
@@ -363,27 +365,11 @@ protected void toParsedText(StringBuilder writer, boolean actual) {
* @param aliasName Entity alias.
*/
private void addMissingAlias(String aliasName) {
- if (isMissingAliasInSelectFromClause()
- || isMissingAliasInUpdateClause()
- || isMissingAliasInDeleteFromClause()) {
+ if (this.getParent() instanceof IdentificationVariableDeclaration identificationVariableDeclaration &&
+ identificationVariableDeclaration.getParent() instanceof FromClause &&
+ this.getIdentificationVariable() instanceof NullExpression) {
this.setVirtualIdentificationVariable(aliasName);
- this.getParentExpression().setGenerateThisPrefix(true);
+ this.getRoot().setGenerateThisPrefix(true);
}
}
-
- private boolean isMissingAliasInSelectFromClause() {
- return this.getParent() instanceof IdentificationVariableDeclaration identificationVariableDeclaration
- && identificationVariableDeclaration.getParent() instanceof FromClause
- && this.getIdentificationVariable() instanceof NullExpression;
- }
-
- private boolean isMissingAliasInUpdateClause() {
- return this.getParent() instanceof UpdateClause
- && this.getIdentificationVariable() instanceof NullExpression;
- }
-
- private boolean isMissingAliasInDeleteFromClause() {
- return this.getParent() instanceof DeleteClause deleteClause
- && this.getIdentificationVariable() instanceof NullExpression;
- }
}
diff --git a/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/SubExpression.java b/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/SubExpression.java
index 037043aaf50..ba5024b6d38 100644
--- a/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/SubExpression.java
+++ b/jpa/org.eclipse.persistence.jpa.jpql/src/main/java/org/eclipse/persistence/jpa/jpql/parser/SubExpression.java
@@ -1,6 +1,5 @@
/*
* Copyright (c) 2006, 2021 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2024 Contributors to the Eclipse Foundation. 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
@@ -27,15 +26,13 @@
* @since 2.3
* @author Pascal Filion
*/
-public final class SubExpression extends AbstractSingleEncapsulatedExpression implements ParentExpression {
+public final class SubExpression extends AbstractSingleEncapsulatedExpression {
/**
* The {@link JPQLQueryBNF} coming from the parent that is used to parse the next portion of the query.
*/
private JPQLQueryBNF queryBNF;
- private boolean generateThisPrefix = false;
-
/**
* Creates a new SubExpression
.
*
@@ -47,16 +44,6 @@ public SubExpression(AbstractExpression parent, JPQLQueryBNF queryBNF) {
this.queryBNF = queryBNF;
}
- @Override
- public boolean isGenerateThisPrefix() {
- return generateThisPrefix;
- }
-
- @Override
- public void setGenerateThisPrefix(boolean generateThisPrefix) {
- this.generateThisPrefix = generateThisPrefix;
- }
-
@Override
public void accept(ExpressionVisitor visitor) {
visitor.visit(this);
diff --git a/jpa/org.eclipse.persistence.jpa.jpql/src/test/java/jpql/query/Order.java b/jpa/org.eclipse.persistence.jpa.jpql/src/test/java/jpql/query/Order.java
index 1c47c5ad07d..aca03e901b7 100644
--- a/jpa/org.eclipse.persistence.jpa.jpql/src/test/java/jpql/query/Order.java
+++ b/jpa/org.eclipse.persistence.jpa.jpql/src/test/java/jpql/query/Order.java
@@ -1,6 +1,5 @@
/*
* Copyright (c) 2018, 2020 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2024 Contributors to the Eclipse Foundation. 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
@@ -42,5 +41,4 @@ public class Order {
private double totalPrice;
@Id private int id;
private String number;
- private int length;
}
diff --git a/jpa/org.eclipse.persistence.jpa.jpql/src/test/java/org/eclipse/persistence/jpa/tests/jpql/parser/JPQLExpressionTestJakartaData.java b/jpa/org.eclipse.persistence.jpa.jpql/src/test/java/org/eclipse/persistence/jpa/tests/jpql/parser/JPQLExpressionTestJakartaData.java
index f39540dbd10..f18607f2430 100644
--- a/jpa/org.eclipse.persistence.jpa.jpql/src/test/java/org/eclipse/persistence/jpa/tests/jpql/parser/JPQLExpressionTestJakartaData.java
+++ b/jpa/org.eclipse.persistence.jpa.jpql/src/test/java/org/eclipse/persistence/jpa/tests/jpql/parser/JPQLExpressionTestJakartaData.java
@@ -1,6 +1,5 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2024 Contributors to the Eclipse Foundation. 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
@@ -16,19 +15,6 @@
//
package org.eclipse.persistence.jpa.tests.jpql.parser;
-import static org.eclipse.persistence.jpa.tests.jpql.parser.JPQLParserTester.equal;
-import static org.eclipse.persistence.jpa.tests.jpql.parser.JPQLParserTester.from;
-import static org.eclipse.persistence.jpa.tests.jpql.parser.JPQLParserTester.numeric;
-import static org.eclipse.persistence.jpa.tests.jpql.parser.JPQLParserTester.path;
-import static org.eclipse.persistence.jpa.tests.jpql.parser.JPQLParserTester.select;
-import static org.eclipse.persistence.jpa.tests.jpql.parser.JPQLParserTester.selectStatement;
-import static org.eclipse.persistence.jpa.tests.jpql.parser.JPQLParserTester.set;
-import static org.eclipse.persistence.jpa.tests.jpql.parser.JPQLParserTester.update;
-import static org.eclipse.persistence.jpa.tests.jpql.parser.JPQLParserTester.updateStatement;
-import static org.eclipse.persistence.jpa.tests.jpql.parser.JPQLParserTester.variable;
-import static org.eclipse.persistence.jpa.tests.jpql.parser.JPQLParserTester.virtualVariable;
-import static org.eclipse.persistence.jpa.tests.jpql.parser.JPQLParserTester.where;
-
import org.eclipse.persistence.jpa.jpql.parser.Expression;
import org.eclipse.persistence.jpa.jpql.parser.FromClause;
import org.eclipse.persistence.jpa.jpql.parser.IdentificationVariableDeclaration;
@@ -121,73 +107,25 @@ public void testGeneratedSelect() {
assertEquals(expectedJPQLQuery, jpqlExpression.toActualText());
}
- @Test
- public void testFunctionNameAsImplicitStateField() {
-
- String inputJPQLQuery = "SELECT this FROM Order WHERE length = 1";
-
- SelectStatementTester selectStatement = selectStatement(
- select(variable("this")),
- from("Order", "{this}"),
- where(equal(virtualVariable("this", "length"), numeric(1)))
- );
-
- testJakartaDataQuery(inputJPQLQuery, selectStatement);
- }
-
- @Test
- public void testFunctionNameAsImplicitStateFieldInNumericExpression() {
-
- String inputJPQLQuery = "SELECT this FROM Order WHERE id = length + 1";
-
- SelectStatementTester selectStatement = selectStatement(
- select(variable("this")),
- from("Order", "{this}"),
- where(equal(
- virtualVariable("this", "id"),
- virtualVariable("this", "length").add(numeric(1))
- ))
- );
-
- testJakartaDataQuery(inputJPQLQuery, selectStatement);
- }
-
- @Test
- public void testUpdateFunctionNameAsImplicitStateFieldInNumericExpression() {
-
- String inputJPQLQuery = "UPDATE Order SET length = length + 1";
-
- UpdateStatementTester selectStatement = updateStatement(
- update(
- "Order",
- set(path("{order}.length"),
- virtualVariable("order", "length")
- .add(numeric(1))
- ))
- );
-
- testJakartaDataQuery(inputJPQLQuery, selectStatement);
- }
-
private JPQLExpression checkAliasFrom(String actualQuery, String expectedAlias) {
JPQLExpression jpqlExpression = JPQLQueryBuilder.buildQuery(actualQuery, JPQLGrammar3_2.instance(), JPQLStatementBNF.ID, true, true);
- SelectStatement selectStatement = (SelectStatement) jpqlExpression.getQueryStatement();
- FromClause fromClause = (FromClause) selectStatement.getFromClause();
- IdentificationVariableDeclaration identificationVariableDeclaration = (IdentificationVariableDeclaration) fromClause.getDeclaration();
- RangeVariableDeclaration rangeVariableDeclaration = (RangeVariableDeclaration) identificationVariableDeclaration.getRangeVariableDeclaration();
- IdentificationVariable identificationVariable = (IdentificationVariable) rangeVariableDeclaration.getIdentificationVariable();
+ SelectStatement selectStatement = (SelectStatement)jpqlExpression.getQueryStatement();
+ FromClause fromClause = (FromClause)selectStatement.getFromClause();
+ IdentificationVariableDeclaration identificationVariableDeclaration = (IdentificationVariableDeclaration)fromClause.getDeclaration();
+ RangeVariableDeclaration rangeVariableDeclaration = (RangeVariableDeclaration)identificationVariableDeclaration.getRangeVariableDeclaration();
+ IdentificationVariable identificationVariable = (IdentificationVariable)rangeVariableDeclaration.getIdentificationVariable();
String alias = identificationVariable.getText();
assertEquals(expectedAlias, alias);
return jpqlExpression;
}
private void checkAliasesWhere(JPQLExpression jpqlExpression, String expectedAlias) {
- SelectStatement selectStatement = (SelectStatement) jpqlExpression.getQueryStatement();
- WhereClause whereClause = (WhereClause) selectStatement.getWhereClause();
+ SelectStatement selectStatement = (SelectStatement)jpqlExpression.getQueryStatement();
+ WhereClause whereClause = (WhereClause)selectStatement.getWhereClause();
ListIterable expressions = whereClause.children();
List identificationVariableList = new ArrayList<>();
collectIdentificationVariables(expressions, identificationVariableList);
- for (IdentificationVariable identificationVariable : identificationVariableList) {
+ for (IdentificationVariable identificationVariable: identificationVariableList) {
if (expectedAlias.equals(identificationVariable.getText())) {
assertEquals(expectedAlias, identificationVariable.getText());
} else {
@@ -198,7 +136,7 @@ private void checkAliasesWhere(JPQLExpression jpqlExpression, String expectedAli
}
private void collectIdentificationVariables(ListIterable expressions, List identificationVariableList) {
- for (Expression expression : expressions) {
+ for (Expression expression: expressions) {
if (expression.children() != null) {
collectIdentificationVariables(expression.children(), identificationVariableList);
}
diff --git a/jpa/org.eclipse.persistence.jpa.jpql/src/test/java/org/eclipse/persistence/jpa/tests/jpql/parser/JPQLParserTest.java b/jpa/org.eclipse.persistence.jpa.jpql/src/test/java/org/eclipse/persistence/jpa/tests/jpql/parser/JPQLParserTest.java
index 5ee690e8f2a..fce23df66e4 100644
--- a/jpa/org.eclipse.persistence.jpa.jpql/src/test/java/org/eclipse/persistence/jpa/tests/jpql/parser/JPQLParserTest.java
+++ b/jpa/org.eclipse.persistence.jpa.jpql/src/test/java/org/eclipse/persistence/jpa/tests/jpql/parser/JPQLParserTest.java
@@ -1,6 +1,5 @@
/*
* Copyright (c) 2006, 2024 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2024 Contributors to the Eclipse Foundation. 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
@@ -152,8 +151,6 @@
import static org.junit.Assert.assertSame;
import static org.junit.Assert.fail;
-import org.eclipse.persistence.jpa.jpql.parser.JPQLGrammar3_2;
-
/**
* This abstract class provides the functionality to test the parsed tree representation of a JPQL
* query by traversing the tree and comparing each node.
@@ -502,24 +499,6 @@ protected void testQuery(String jpqlQuery,
testQuery(jpqlQuery, expressionTester, jpqlGrammar, jpqlQueryBNFId, formatter, tolerant);
}
- /**
- * Tests the parsing of the given JPQL query by comparing the parsed tree ({@link JPQLExpression})
- * with the given tester, which is an equivalent representation of the parsed tree.
- *
- * @param jpqlQuery The JPQL query to parse and to test the parsed tree representation
- * @param expressionTester The tester used to verify the parsed tree is correctly representing the
- * JPQL query
- */
- protected void testJakartaDataQuery(String jpqlQuery,
- ExpressionTester expressionTester) {
-
- JPQLExpression jpqlExpression = new JPQLExpression(jpqlQuery, JPQLGrammar3_2.instance(), JPQLStatementBNF.ID, true, true);
- if (expressionTester.getClass() != JPQLExpressionTester.class) {
- expressionTester = jpqlExpression(expressionTester);
- }
- expressionTester.test(jpqlExpression);
- }
-
/**
* Tests the parsing of the given JPQL query by comparing the parsed tree ({@link JPQLExpression})
* with the given tester, which is an equivalent representation of the parsed tree.
diff --git a/jpa/org.eclipse.persistence.jpa.jpql/src/test/java/org/eclipse/persistence/jpa/tests/jpql/parser/JPQLParserTester.java b/jpa/org.eclipse.persistence.jpa.jpql/src/test/java/org/eclipse/persistence/jpa/tests/jpql/parser/JPQLParserTester.java
index 94feabe3bcc..45d223f0a3a 100644
--- a/jpa/org.eclipse.persistence.jpa.jpql/src/test/java/org/eclipse/persistence/jpa/tests/jpql/parser/JPQLParserTester.java
+++ b/jpa/org.eclipse.persistence.jpa.jpql/src/test/java/org/eclipse/persistence/jpa/tests/jpql/parser/JPQLParserTester.java
@@ -1,6 +1,5 @@
/*
* Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2024 Contributors to the Eclipse Foundation. 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
@@ -2854,7 +2853,7 @@ public static StateFieldPathExpressionTester path(String pathExpression) {
int dotIndex = pathExpression.indexOf('.');
if (dotIndex == 0) {
- return path(nullExpression(), false, pathExpression.substring(1));
+ return path(nullExpression(), false, pathExpression);
}
String variable = pathExpression.substring(0, dotIndex);