Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The parser gives an error for a JPQL which refers to a "length" field with no entity alias #2217

Closed
OndroMih opened this issue Jul 23, 2024 · 3 comments

Comments

@OndroMih
Copy link
Contributor

OndroMih commented Jul 23, 2024

A duplicate of #2187.

Describe the bug

When an entity has a field named "length", it should be valid to use this field in a JPQL query. However, JPQL also supports a function of the same name "length". If the field "length" is used without an entity alias in a condition, Eclipselink confuses it with the function "length" and complains that the function is not followed by arguments in parentheses.

For example, with enitty Box that has an int field length, the following query is valid in Persistence 3.2 and 'length" should the Box entity:

UPDATE Box SET length = length + ?1

EclipseLink gives the following error when executing the query:

The left parenthesis is missing from the LENGTH expression.
The left expression is not an arithmetic expression.
The left expression is not an arithmetic expression. 

This is because Eclipselink parser treats "length" as a function and expects that it's followed by arguments.

To Reproduce

One way to reproduce is to create a simple application (e.g. a Java SE app or unit test with EclipseLink running against an embedded DB like Derby), with the following:

  • some entity, e.g. Box, with an int length field (the field must have a name that's equal to some supported function name, "length" is just one example)
  • execute a query without an alias, such as UPDATE Box SET length = length + ?1, or SELECT this Box WHERE length = ?1

Another, more complicate way, is to run the Jakarta Data TCK with Eclipselink as a backend. This is what I'm working on right now and that's how I discovered this bug. One of the Data TCK tests uses the query UPDATE Box SET length = length + ?1, width = width - ?1, height = height * ?2 (the source code of the query, the source code of the test that executes it and fails). Without fixing this, no Jakarta Data implementation on top of Eclipselink can pass the Data TCK.

  • EclipseLink version: 5.0.0-B02, main branch today
  • Java/JDK version: I use Java 21 but the same should happen on Java 17
  • Entity source (mainly applied annotations): any entity with a field whose name is the same as some function supported in JPQL. For example int length

Code example:

emf = new PersistenceConfiguration("test")
                .transactionType(RESOURCE_LOCAL)
                .provider(PersistenceProvider.class.getName())
                .property(PersistenceConfiguration.JDBC_DRIVER, ClientDataSource.class.getName())
                .property(PersistenceConfiguration.JDBC_URL, "jdbc:derby:memory:test-jpa;create=true")
                .property(PersistenceConfiguration.JDBC_USER, "APP")
                .property(PersistenceConfiguration.JDBC_PASSWORD, "APP")
                .property(PersistenceConfiguration.SCHEMAGEN_DATABASE_ACTION, "drop-and-create")
                .property("eclipselink.debug", "ALL")
                .property("eclipselink.target-database", "Derby")
                .property("eclipselink.weaving", "static")
                .property("eclipselink.logging.level", "FINEST")
                .property("eclipselink.logging.level.sql", "FINEST")
                .property("eclipselink.logging.level.cache", "FINEST")
                .property("eclipselink.jpql.validation", "JPA 3.2")
                .managedClass(Box.class)
                .createEntityManagerFactory();
        em = emf.createEntityManager();
        em.getTransaction().begin();

        Query query = em.createQuery("UPDATE Box SET length = this.length + 1");
        query.executeUpdate();

        EntityTransaction tx = em.getTransaction();
        if (tx.isActive() && !tx.getRollbackOnly()) {
            tx.commit();
        }

Box.java:

@Entity
public class Box {
    @Id
    long id;
    @Column
    long length;
}

Expected behavior
For example example code above, I would expect that with the query ("UPDATE Box SET length = this.length + 1", all rows in the Box table will have the "length" value increased by 1.

Additional context

I'm going to submit a pull request with a fix and additional test cases that cover cases like this

OndroMih added a commit to OmniFish-EE/eclipselink that referenced this issue Jul 23, 2024
…as a function

E.g., if Box entity has field "length", "delete from Box where length = 1" fails
This commit fixes it.

To do:
- fix copyright headers
OndroMih added a commit to OmniFish-EE/eclipselink that referenced this issue Jul 23, 2024
OndroMih added a commit to OmniFish-EE/eclipselink that referenced this issue Jul 23, 2024
OndroMih added a commit to OmniFish-EE/eclipselink that referenced this issue Jul 23, 2024
Tests with entityManager for SELECT, UPDATE, DELETE with implicit variable
OndroMih added a commit to OmniFish-EE/eclipselink that referenced this issue Jul 23, 2024
* fix tests in AbstractGrammarValidatorTest for invalid numeric literals. Simplified my previous changes. Recompute word type after reverting functions without arguments. This avoids a literal would be parsed as a number
* fix test advanced.JUnitJPQLModifyTest.updateUnqualifiedAttributeInWhere. An implicit variable was incorrectly added in a nested statement, in which an explicit variable was defined
OndroMih added a commit to OmniFish-EE/eclipselink that referenced this issue Jul 23, 2024
@pzygielo
Copy link

@OndroMih
Copy link
Contributor Author

Yes, it's the same thing, originated from a test in Jakarta Data. Looks like the OpenLiberty team hit the same issue as me. I didn't notice it before. I'll close my issue as a duplicate.

@Riva-Tholoor-Philip
Copy link
Contributor

Thanks @OndroMih , @pzygielo

OndroMih added a commit to OmniFish-EE/eclipselink that referenced this issue Aug 1, 2024
OndroMih added a commit to OmniFish-EE/eclipselink that referenced this issue Aug 1, 2024
Moved the check for invalid expression to general places in expression and factory.
OndroMih added a commit to OmniFish-EE/eclipselink that referenced this issue Aug 1, 2024
This method is no longer needed in NumericLiteral after fixes in the previous commit.
OndroMih added a commit to OmniFish-EE/eclipselink that referenced this issue Aug 1, 2024
Uses existing Room entity with a field named "length"

Note: the test "JUnitJPQLJakartaDataNoAliasTest.tesUpdateQueryWithThisVariable" is still failing
OndroMih added a commit to OmniFish-EE/eclipselink that referenced this issue Aug 1, 2024
lukasj pushed a commit that referenced this issue Aug 2, 2024
* (#2217) Fix when an unnamed entity has a field with name as a function
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants