eclipse-ee4j / eclipselink

Eclipselink project
https://eclipse.dev/eclipselink/
Other
196 stars 167 forks source link

Length entity attribute misinterpreted as LENGTH(...) operation in JPQL #2187

Open anija-anil opened 2 months ago

anija-anil commented 2 months ago

EclipseLink is misterpreting the length entity attribute as a LENGTH(...) operation in,

UPDATE Box SET length = length + ?1, width = width - ?1, height = height * ?2

If "length" were followed by an open parenthesis, then it would be a LENGTH(string_expression) operation, but it is not followed by ( in this query. The correct parsing ought to be an entity attribute named length which has the optional entity identification variable omitted.

[6/26/24, 14:31:58:458 CDT] 00000051 id=0458cc71 io.openliberty.data.internal.persistence.RepositoryImpl      3 QueryInfo@3ce96da9 long resizeAll(int, int) UPDATE Box SET length = length + ?1, width = width - ?1, height = height * ?2 [2 positional params]
[6/26/24, 14:31:58:458 CDT] 00000051 id=6f99ba0f enliberty.data.internal.persistence.service.DBStoreEMBuilder > createEntityManager Entry 
[6/26/24, 14:31:58:458 CDT] 00000051 id=4f7ca5d3 om.ibm.wsspi.persistence.internal.PersistenceServiceUnitImpl > createEntityManager Entry 
[6/26/24, 14:31:58:458 CDT] 00000051 id=4f7ca5d3 om.ibm.wsspi.persistence.internal.PersistenceServiceUnitImpl < createEntityManager Exit  
                                                                                                               org.eclipse.persistence.internal.jpa.EntityManagerImpl@63c97bfc
[6/26/24, 14:31:58:458 CDT] 00000051 id=6f99ba0f enliberty.data.internal.persistence.service.DBStoreEMBuilder < createEntityManager Exit  
                                                                                                               org.eclipse.persistence.internal.jpa.EntityManagerImpl@63c97bfc
[6/26/24, 14:31:58:461 CDT] 00000051 id=00000000 io.openliberty.data.internal.persistence.RepositoryImpl      3 java.lang.IllegalArgumentException replaced with jakarta.data.exceptions.MappingException
[6/26/24, 14:31:58:461 CDT] 00000051 id=0458cc71 io.openliberty.data.internal.persistence.RepositoryImpl      < invoke MultipleEntityRepo.resizeAll Exit  
                                                                                                               jakarta.data.exceptions.MappingException: java.lang.IllegalArgumentException: An exception occurred while creating a query in EntityManager: 
Exception Description: Syntax error parsing [UPDATE Box SET length = length + ?1, width = width - ?1, height = height * ?2]. 
[30, 30] The left parenthesis is missing from the LENGTH expression.
[45, 50] The left expression is not an arithmetic expression.
[66, 72] The left expression is not an arithmetic expression.

Caused by: java.lang.IllegalArgumentException: An exception occurred while creating a query in EntityManager: 
Exception Description: Syntax error parsing [UPDATE Box SET length = length + ?1, width = width - ?1, height = height * ?2]. 
[30, 30] The left parenthesis is missing from the LENGTH expression.
[45, 50] The left expression is not an arithmetic expression.
[66, 72] The left expression is not an arithmetic expression.
    at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1848)

    ... 40 more
Caused by: Exception [EclipseLink-0] (Eclipse Persistence Services - 5.0.0-B02.v202404111748): org.eclipse.persistence.exceptions.JPQLException
Exception Description: Syntax error parsing [UPDATE Box SET length = length + ?1, width = width - ?1, height = height * ?2]. 
[30, 30] The left parenthesis is missing from the LENGTH expression.
[45, 50] The left expression is not an arithmetic expression.
[66, 72] The left expression is not an arithmetic expression.
    at org.eclipse.persistence.internal.jpa.jpql.HermesParser.buildException(HermesParser.java:169)
    at org.eclipse.persistence.internal.jpa.jpql.HermesParser.validate(HermesParser.java:345)
    at org.eclipse.persistence.internal.jpa.jpql.HermesParser.populateQueryImp(HermesParser.java:292)
    at org.eclipse.persistence.internal.jpa.jpql.HermesParser.buildQuery(HermesParser.java:174)
    at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:144)
    at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:120)
    at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:107)
    at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:91)
    at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1846)
    ... 41 more
anija-anil commented 1 month ago

We were able to recreate this issue. Below is the Box entity we created by referencing the entity present in Jakarta Data.

@jakarta.persistence.Entity
public class Box {
    @jakarta.persistence.Id
    public String boxIdentifier;

    public int length;

    public int width;

    public int height;

    public static Box of(String id, int length, int width, int height) {
        Box box = new Box();
        box.boxIdentifier = id;
        box.length = length;
        box.width = width;
        box.height = height;
        return box;
    }

Here is the code where we executed the JPQL query:

tx.begin();
        try {
            em.createQuery("UPDATE Box SET length = length + ?1, width = width - ?1, height = height * ?2")
                            .setParameter(1, 1)
                            .setParameter(2, 2)
                            .executeUpdate();

            wall = em.createQuery("SELECT Box WHERE boxIdentifier = :id", Box.class)
                            .setParameter("id", "testOLGH28909")
                            .getSingleResult();

            tx.commit();

This resulted in the following exception stack, which is the same as described in the issue:

Exception Description: Syntax error parsing [UPDATE Box SET length = length + ?1, width = width - ?1, height = height * ?2].
[30, 30] The left parenthesis is missing from the LENGTH expression.
[45, 50] The left expression is not an arithmetic expression.
[66, 72] The left expression is not an arithmetic expression.
at org.eclipse.persistence.internal.jpa.jpql.HermesParser.buildException(HermesParser.java:169)
at org.eclipse.persistence.internal.jpa.jpql.HermesParser.validate(HermesParser.java:345)
at org.eclipse.persistence.internal.jpa.jpql.HermesParser.populateQueryImp(HermesParser.java:292)
at org.eclipse.persistence.internal.jpa.jpql.HermesParser.buildQuery(HermesParser.java:174)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:144)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:120)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:107)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:91)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1846)

at componenttest.topology.utils.FATServletClient.assertTestResponse(FATServletClient.java:106)
at componenttest.topology.utils.FATServletClient.runTest(FATServletClient.java:91)
at componenttest.custom.junit.runner.SyntheticServletTest.invokeExplosively(SyntheticServletTest.java:49)
at componenttest.custom.junit.runner.FATRunner$1.evaluate(FATRunner.java:204)
at componenttest.custom.junit.runner.FATRunner$2.evaluate(FATRunner.java:364)
at componenttest.custom.junit.runner.FATRunner.run(FATRunner.java:178)
at org.testcontainers.containers.FailureDetectingExternalResource$1.evaluate(FailureDetectingExternalResource.java:29)
at componenttest.rules.repeater.RepeatTests$CompositeRepeatTestActionStatement.evaluate(RepeatTests.java:145)