Skip to content

Commit

Permalink
NullPointerException when JPQL UPDATE assignment operation omits opt…
Browse files Browse the repository at this point in the history
…ional identification variable eclipse-ee4j#2184  - bug fix (main + tests)

Signed-off-by: Radek Felcman <[email protected]>
  • Loading branch information
rfelcman committed Sep 9, 2024
1 parent 1b44275 commit c149d8a
Show file tree
Hide file tree
Showing 13 changed files with 108 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ public static Test suite() {
suite.addTest(new JUnitJPQLJakartaDataNoAliasTest("testDeleteQueryLengthInExpressionOnRight"));
suite.addTest(new JUnitJPQLJakartaDataNoAliasTest("tesUpdateQueryWithThisVariable"));
suite.addTest(new JUnitJPQLJakartaDataNoAliasTest("testThisVariableInPathExpressionUpdate"));
suite.addTest(new JUnitJPQLJakartaDataNoAliasTest("testThisVariableInPathAndIdFunctionExpressionUpdate"));
suite.addTest(new JUnitJPQLJakartaDataNoAliasTest("testThisVariableInPathExpressionDelete"));
suite.addTest(new JUnitJPQLJakartaDataNoAliasTest("testThisVariableInLikeExpressionDelete"));
return suite;
Expand Down Expand Up @@ -384,6 +385,18 @@ public void testThisVariableInPathExpressionUpdate() {
assertTrue("Length of room with ID = 1 is " + length, length == 10);
}

// Covers https://github.com/eclipse-ee4j/eclipselink/issues/2184
public void testThisVariableInPathAndIdFunctionExpressionUpdate() {
resetRooms();
int numberOfChanges = getEntityManagerFactory().callInTransaction(em -> em.createQuery(
"UPDATE Room SET length = 10 WHERE ID(this) = :idParam")
.setParameter("idParam", 1)
.executeUpdate());
assertTrue("Number of rooms with ID = 1 modified is " + numberOfChanges, numberOfChanges == 1);
int length = findRoomById(1).getLength();
assertTrue("Length of room with ID = 1 is " + length, length == 10);
}

// Covers https://github.com/eclipse-ee4j/eclipselink/issues/2198
public void testThisVariableInPathExpressionDelete() {
resetRooms();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, 2023 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2024 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
Expand Down Expand Up @@ -36,6 +36,7 @@
import org.eclipse.persistence.jpa.jpql.parser.FromClause;
import org.eclipse.persistence.jpa.jpql.parser.GroupByClause;
import org.eclipse.persistence.jpa.jpql.parser.HavingClause;
import org.eclipse.persistence.jpa.jpql.parser.IdentificationVariable;
import org.eclipse.persistence.jpa.jpql.parser.JPQLGrammar;
import org.eclipse.persistence.jpa.jpql.parser.JPQLQueryBNF;
import org.eclipse.persistence.jpa.jpql.parser.NullExpression;
Expand All @@ -45,6 +46,7 @@
import org.eclipse.persistence.jpa.jpql.parser.SimpleFromClause;
import org.eclipse.persistence.jpa.jpql.parser.SimpleSelectClause;
import org.eclipse.persistence.jpa.jpql.parser.SimpleSelectStatement;
import org.eclipse.persistence.jpa.jpql.parser.StateFieldPathExpression;
import org.eclipse.persistence.jpa.jpql.parser.SubExpression;
import org.eclipse.persistence.jpa.jpql.parser.UnionClause;
import org.eclipse.persistence.jpa.jpql.parser.UnknownExpression;
Expand Down Expand Up @@ -967,6 +969,19 @@ public void visit(NullExpression expression) {
valid = true;
}

@Override
public void visit(StateFieldPathExpression expression) {
JPQLQueryBNF originQueryBNF = queryBNF;
if (Expression.THIS.equalsIgnoreCase(expression.toString()) &&
expression.getParentExpression().isGenerateThisPrefix() &&
expression.getIdentificationVariable() != null &&
((IdentificationVariable)(expression.getIdentificationVariable())).isVirtual()) {
queryBNF = expression.getQueryBNF();
}
visit((Expression) expression);
queryBNF = originQueryBNF;
}

@Override
public void visit(SubExpression expression) {
if (expression.hasExpression()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, 2022 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2024 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
Expand Down Expand Up @@ -56,8 +56,8 @@ private GeneralIdentificationVariableVisitor generalIdentificationVariableVisito

@Override
public void visit(AbstractSchemaName expression) {
// The "virtual" variable name will be the entity name
variableName = expression.toActualText().toLowerCase(Locale.ROOT);
// The "virtual" variable name will be "this" entity name
variableName = Expression.THIS;
}

@Override
Expand All @@ -68,7 +68,7 @@ public void visit(CollectionMemberDeclaration expression) {
@Override
public void visit(CollectionValuedPathExpression expression) {
visitAbstractPathExpression(expression);
variableName = expression.toActualText().toLowerCase(Locale.ROOT);
variableName = Expression.THIS;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ protected void initializeBNFs() {
// ID function
addChildBNF(SelectExpressionBNF.ID, IdExpressionBNF.ID);
addChildBNF(ComparisonExpressionBNF.ID, IdExpressionBNF.ID);
addChildBNF(IdExpressionBNF.ID, GeneralIdentificationVariableBNF.ID);
addChildBNF(IdExpressionBNF.ID, SingleValuedObjectPathExpressionBNF.ID);

// VERSION function
addChildBNF(SelectExpressionBNF.ID, VersionExpressionBNF.ID);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2024 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
Expand Down Expand Up @@ -67,7 +67,7 @@ public void test_JPQLQuery_04() {

RangeVariableDeclarationTester rangeVariableDeclaration = rangeVariableDeclaration(
abstractSchemaName("Employee"),
virtualVariable("employee")
virtualVariable("this")
);
rangeVariableDeclaration.hasSpaceAfterAbstractSchemaName = false;

Expand All @@ -87,7 +87,7 @@ public void test_JPQLQuery_05() {
delete(
rangeVariableDeclaration(
abstractSchemaName("Employee"),
virtualVariable("employee")
virtualVariable("this")
)
)
);
Expand All @@ -102,7 +102,7 @@ public void test_JPQLQuery_06() {

RangeVariableDeclarationTester rangeVariableDeclaration = rangeVariableDeclarationAs(
abstractSchemaName("Employee"),
virtualVariable("employee")
virtualVariable("this")
);
rangeVariableDeclaration.hasSpaceAfterAs = false;

Expand Down Expand Up @@ -131,7 +131,7 @@ public void test_JPQLQuery_08() {
String query = "DELETE FROM Employee AS WHERE";

DeleteStatementTester deleteStatement = deleteStatement(
deleteAs(abstractSchemaName("Employee"), virtualVariable("employee")),
deleteAs(abstractSchemaName("Employee"), virtualVariable("this")),
where(nullExpression())
);

Expand Down Expand Up @@ -162,7 +162,7 @@ public void test_JPQLQuery_10() {
whereClause.hasSpaceAfterIdentifier = true;

DeleteStatementTester deleteStatement = deleteStatement(
deleteAs(abstractSchemaName("Employee"), virtualVariable("employee")),
deleteAs(abstractSchemaName("Employee"), virtualVariable("this")),
whereClause
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2024 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
Expand Down Expand Up @@ -201,11 +201,11 @@ public void test_Query_016() {

ExpressionTester updateStatement = updateStatement(
update(
"Employee",
set("{employee}.name", string("'JPQL'"))
"Employee", "this",
set("{this}.name", string("'JPQL'")), false
),
where(
virtualVariable("employee", "column").notEqual(string("'value'"))
virtualVariable("this", "column").notEqual(string("'value'"))
)
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2024 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
Expand Down Expand Up @@ -79,7 +79,7 @@ public void test_Query_006() {
// UPDATE DateTime SET timestamp = CURRENT_TIMESTAMP

ExpressionTester updateStatement = updateStatement(
update("DateTime", set("{datetime}.timestamp", CURRENT_TIMESTAMP()))
update("DateTime", "this", set("{this}.timestamp", CURRENT_TIMESTAMP()), false)
);

testQuery(query_006(), updateStatement, buildQueryFormatter_1());
Expand All @@ -91,7 +91,7 @@ public void test_Query_007() {
// UPDATE DateTime SET scn = CURRENT_TIMESTAMP

ExpressionTester updateStatement = updateStatement(
update("DateTime", set("{datetime}.scn", CURRENT_TIMESTAMP()))
update("DateTime", "this", set("{this}.scn", CURRENT_TIMESTAMP()), false)
);

testQuery(query_007(), updateStatement, buildQueryFormatter_2());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
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.id;
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;
Expand Down Expand Up @@ -177,11 +178,32 @@ public void testUpdateFunctionNameAsImplicitStateFieldInNumericExpression() {

UpdateStatementTester selectStatement = updateStatement(
update(
"Order",
set(path("{order}.length"),
virtualVariable("order", "length")
"Order", "this",
set(path("{this}.length"),
virtualVariable("this", "length")
.add(numeric(1))
))
), false)
);

testJakartaDataQuery(inputJPQLQuery, selectStatement);
}

@Test
public void testUpdateFunctionNameAsImplicitStateFieldInIdFunction() {

String inputJPQLQuery = "UPDATE Order SET length = length + 1 WHERE ID(this) = 1";

UpdateStatementTester selectStatement = updateStatement(
update(
"Order", "this",
set(path("{this}.length"),
virtualVariable("this", "length")
.add(numeric(1))
), false),
where(equal(
id(virtualVariable("this", "this")),
numeric(1)
))
);

testJakartaDataQuery(inputJPQLQuery, selectStatement);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4034,6 +4034,22 @@ public static UpdateClauseTester update(String abstractSchemaName,
return updateClause;
}

public static UpdateClauseTester update(String abstractSchemaName,
String virtualVariable,
ExpressionTester updateItem,
boolean dummy) {

UpdateClauseTester updateClause = update(
rangeVariableDeclaration(
abstractSchemaName(abstractSchemaName),
virtualVariable(virtualVariable)
),
updateItem
);
updateClause.hasSpaceAfterRangeVariableDeclaration = false;
return updateClause;
}

public static UpdateClauseTester update(String abstractSchemaName,
ExpressionTester... updateItems) {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2024 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
Expand Down Expand Up @@ -4176,7 +4176,7 @@ final void test_Query_177(JPQLGrammar jpqlGrammar) {
// UPDATE DateTime SET date = CURRENT_DATE

ExpressionTester updateStatement = updateStatement(
update("DateTime", set("{datetime}.date", CURRENT_DATE()))
update("DateTime", "this", set("{this}.date", CURRENT_DATE()), false)
);

testQuery(query_177(), updateStatement, jpqlGrammar);
Expand Down Expand Up @@ -5248,7 +5248,7 @@ final void test_Query_216(JPQLGrammar jpqlGrammar) {
String jpqlQuery = "UPDATE Employee SET avg = 'JPQL'";

UpdateStatementTester updateStatement = updateStatement(
update("Employee", set("{employee}.avg", string("'JPQL'")))
update("Employee", "this", set("{this}.avg", string("'JPQL'")), false)
);

testQuery(jpqlQuery, updateStatement, jpqlGrammar, buildStringFormatter_1());
Expand All @@ -5264,7 +5264,7 @@ final void test_Query_217(JPQLGrammar jpqlGrammar) {
String jpqlQuery = "UPDATE Employee SET current_timestamp = 'JPQL'";

UpdateStatementTester updateStatement = updateStatement(
update("Employee", set("{employee}.current_timestamp", string("'JPQL'")))
update("Employee", "this", set("{this}.current_timestamp", string("'JPQL'")), false)
);

testQuery(jpqlQuery, updateStatement, jpqlGrammar, buildStringFormatter_2());
Expand All @@ -5280,7 +5280,7 @@ final void test_Query_218(JPQLGrammar jpqlGrammar) {
String jpqlQuery = "UPDATE Employee SET end = 'JPQL'";

UpdateStatementTester updateStatement = updateStatement(
update("Employee", set("{employee}.end", string("'JPQL'")))
update("Employee", "this", set("{this}.end", string("'JPQL'")), false)
);

testQuery(jpqlQuery, updateStatement, jpqlGrammar, buildStringFormatter_3());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2024 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
Expand Down Expand Up @@ -73,7 +73,7 @@ public void test_JPQLQuery_04() {

RangeVariableDeclarationTester rangeVariableDeclaration = rangeVariableDeclaration(
abstractSchemaName("Employee"),
virtualVariable("employee")
virtualVariable("this")
);
rangeVariableDeclaration.hasSpaceAfterAbstractSchemaName = false;
rangeVariableDeclaration.hasSpaceAfterAs = false;
Expand All @@ -94,7 +94,7 @@ public void test_JPQLQuery_05() {

RangeVariableDeclarationTester rangeVariableDeclaration = rangeVariableDeclaration(
abstractSchemaName("Employee"),
virtualVariable("employee")
virtualVariable("this")
);
rangeVariableDeclaration.hasSpaceAfterAbstractSchemaName = true;
rangeVariableDeclaration.hasSpaceAfterAs = false;
Expand All @@ -115,7 +115,7 @@ public void test_JPQLQuery_06() {

RangeVariableDeclarationTester rangeVariableDeclaration = rangeVariableDeclarationAs(
abstractSchemaName("Employee"),
virtualVariable("employee")
virtualVariable("this")
);
rangeVariableDeclaration.hasSpaceAfterAs = false;

Expand Down Expand Up @@ -147,7 +147,7 @@ public void test_JPQLQuery_08() {

String query = "UPDATE Employee AS SET";

UpdateClauseTester updateClause = updateAs("Employee", "{employee}");
UpdateClauseTester updateClause = updateAs("Employee", "{this}");
updateClause.hasSet = true;
updateClause.hasSpaceAfterSet = false;
updateClause.hasSpaceAfterRangeVariableDeclaration = false;
Expand Down Expand Up @@ -175,7 +175,7 @@ public void test_JPQLQuery_10() {

String query = "UPDATE Employee AS SET ";

UpdateClauseTester updateClause = updateAs("Employee", "{employee}");
UpdateClauseTester updateClause = updateAs("Employee", "{this}");
updateClause.hasSet = true;
updateClause.hasSpaceAfterSet = true;
updateClause.hasSpaceAfterRangeVariableDeclaration = false;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2024 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
Expand Down Expand Up @@ -68,8 +68,8 @@ public void test_JPQLQuery_03() {

UpdateStatementTester updateStatement = updateStatement(
update(
"Employee",
set(bad(avg(numeric(2))), string("'Pascal'"))
"Employee", "this",
set(bad(avg(numeric(2))), string("'Pascal'")), false
)
);

Expand All @@ -83,8 +83,8 @@ public void test_JPQLQuery_04() {

UpdateStatementTester updateStatement = updateStatement(
update(
"Employee",
set("{employee}.avg", string("'Pascal'"))
"Employee", "this",
set("{this}.avg", string("'Pascal'")), false
)
);

Expand Down
Loading

0 comments on commit c149d8a

Please sign in to comment.