Skip to content

SubQuery & PageRequest : wrong alias used for sort #2518

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

Closed
MarneusCalgarXP opened this issue May 2, 2022 · 5 comments
Closed

SubQuery & PageRequest : wrong alias used for sort #2518

MarneusCalgarXP opened this issue May 2, 2022 · 5 comments
Assignees
Labels
status: duplicate A duplicate of another issue

Comments

@MarneusCalgarXP
Copy link

MarneusCalgarXP commented May 2, 2022

bug occurs in version : spring-data-jpa 2.6.4 (was ok in 2.6.3 and prior versions)

sample project to reproduce:

Model :

@Entity
public class Foo {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

}

Repository :

public interface FooRepository extends JpaRepository<Foo, Long> {

    @Query("SELECT f" +
            " FROM com.example.demo.model.Foo f " +
            "WHERE f.id = ( " +
            "    SELECT MIN(g.id)" +
            "    FROM com.example.demo.model.Foo g " +
            " ) ")
    Page<Foo> findCustomFoo(Pageable pageable);

}

call :

Page<Foo> page = fooRepository.findCustomFoo(
	PageRequest.of(0, 10, Sort.Direction.ASC, "id")
);

HQL generated in versions prior to 2.6.3 (included)

SELECT f FROM com.example.demo.model.Foo f WHERE f.id = ( SELECT MIN(g.id) FROM com.example.demo.model.Foo g ) 
order by f.id asc

HQL generated in version 2.6.4

SELECT f FROM com.example.demo.model.Foo f WHERE f.id = ( SELECT MIN(g.id) FROM com.example.demo.model.Foo g ) 
order by g.id asc

==> the alias used in order by points to the subquery table, which is not available at global level

which leads to a QuerySyntaxException :

org.hibernate.hql.internal.ast.QuerySyntaxException: 
Invalid path: 'g.id' 
[SELECT f FROM com.example.demo.model.Foo f WHERE f.id = (     SELECT MIN(g.id)    FROM com.example.demo.model.Foo g  )  order by g.id asc]
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label May 2, 2022
@DiegoKrupitza
Copy link
Contributor

I think this should be fixed with PR #2516 by @darinmanica.

@darinmanica
Copy link
Contributor

darinmanica commented May 2, 2022

I agree, @DiegoKrupitza. PR #2516 should resolve this issue, making this issue a duplicate of #2500 and the second half of #2260. @MarneusCalgarXP feel free to pull the PR and test with your examples. I was able to replace the 2.6.4 builds with the PR builds in my application, and everything is working again.

@MarneusCalgarXP
Copy link
Author

MarneusCalgarXP commented May 3, 2022

@darinmanica I copied the QueryUtils.java file in my project from PR #2516 , everything is OK, problem solved.

thank you ;-)

gregturn pushed a commit that referenced this issue May 4, 2022
In order to correctly identify aliases in the order by clause, we cannot process the from clauses left-to-right using regular expressions. These must be removed inner-to-outer. Commit c93aa25 resulted in a bug where the subquery would be incorrectly identified as the alias, as by the following query:

```
from Parent p join p.children c where not c.id not in (select c2.id from Child c2)
```

Passing in a Sort.by("name") would result in "order by c2.name" instead of "order by p.name". Thus, it was using the alias of the inner query instead of the outer query. [This comment](#2260 (comment)) suggests removing the content of the inner query, with the caveat of the entire query being surrounded by parenthesis. This commit does exactly that, by removing the subquery before the alias is identified. It also handles the case when the entire query is surrounded by parenthesis. Unit tests illustrate this along with several examples of removing the subquery to correctly identify the alias for the order by clause.

See #2260 (c93aa25), #2500, #2518.
gregturn added a commit that referenced this issue May 4, 2022
@gregturn gregturn self-assigned this May 4, 2022
@gregturn gregturn added status: duplicate A duplicate of another issue and removed status: waiting-for-triage An issue we've not yet triaged labels May 4, 2022
@gregturn
Copy link
Contributor

gregturn commented May 4, 2022

Duplicates #2260.

@gregturn gregturn closed this as completed May 4, 2022
gregturn pushed a commit that referenced this issue May 4, 2022
In order to correctly identify aliases in the order by clause, we cannot process the from clauses left-to-right using regular expressions. These must be removed inner-to-outer. Commit c93aa25 resulted in a bug where the subquery would be incorrectly identified as the alias, as by the following query:

```
from Parent p join p.children c where not c.id not in (select c2.id from Child c2)
```

Passing in a Sort.by("name") would result in "order by c2.name" instead of "order by p.name". Thus, it was using the alias of the inner query instead of the outer query. [This comment](#2260 (comment)) suggests removing the content of the inner query, with the caveat of the entire query being surrounded by parenthesis. This commit does exactly that, by removing the subquery before the alias is identified. It also handles the case when the entire query is surrounded by parenthesis. Unit tests illustrate this along with several examples of removing the subquery to correctly identify the alias for the order by clause.

See #2260 (c93aa25), #2500, #2518.
gregturn added a commit that referenced this issue May 4, 2022
gregturn pushed a commit that referenced this issue May 4, 2022
In order to correctly identify aliases in the order by clause, we cannot process the from clauses left-to-right using regular expressions. These must be removed inner-to-outer. Commit c93aa25 resulted in a bug where the subquery would be incorrectly identified as the alias, as by the following query:

```
from Parent p join p.children c where not c.id not in (select c2.id from Child c2)
```

Passing in a Sort.by("name") would result in "order by c2.name" instead of "order by p.name". Thus, it was using the alias of the inner query instead of the outer query. [This comment](#2260 (comment)) suggests removing the content of the inner query, with the caveat of the entire query being surrounded by parenthesis. This commit does exactly that, by removing the subquery before the alias is identified. It also handles the case when the entire query is surrounded by parenthesis. Unit tests illustrate this along with several examples of removing the subquery to correctly identify the alias for the order by clause.

See #2260 (c93aa25), #2500, #2518.
gregturn added a commit that referenced this issue May 4, 2022
gregturn pushed a commit that referenced this issue May 4, 2022
In order to correctly identify aliases in the order by clause, we cannot process the from clauses left-to-right using regular expressions. These must be removed inner-to-outer. Commit c93aa25 resulted in a bug where the subquery would be incorrectly identified as the alias, as by the following query:

```
from Parent p join p.children c where not c.id not in (select c2.id from Child c2)
```

Passing in a Sort.by("name") would result in "order by c2.name" instead of "order by p.name". Thus, it was using the alias of the inner query instead of the outer query. [This comment](#2260 (comment)) suggests removing the content of the inner query, with the caveat of the entire query being surrounded by parenthesis. This commit does exactly that, by removing the subquery before the alias is identified. It also handles the case when the entire query is surrounded by parenthesis. Unit tests illustrate this along with several examples of removing the subquery to correctly identify the alias for the order by clause.

See #2260 (c93aa25), #2500, #2518.
gregturn added a commit that referenced this issue May 4, 2022
@alexantonica
Copy link

alexantonica commented Sep 8, 2022

Still happening in 2.7.1. I've just upgraded from 2.6.3 and this started failing.
Stackoverflow post

Edit: found a workaround. I've read in the posts you posted above that it might be related with the multi lined query.
So instead of

     @Query("""
      SELECT x FROM X x
      WHERE x.fieldId IN (:fieldIds)
          AND ((:statusList) IS NULL OR t.status IN (:statusList))
          AND (:term IS NULL OR LOWER(x.name) LIKE :term OR LOWER(x.code) LIKE :term)
          AND (:excludeId is NULL OR NOT EXISTS (
              FROM Y y
              WHERE y.id.someId = x.id
                AND y.id.someOtherId = :excludeId
              )
          )
       """)

i've changed to

     @Query("""
      SELECT x FROM X x
      WHERE x.fieldId IN (:fieldIds)
          AND ((:statusList) IS NULL OR t.status IN (:statusList))
          AND (:term IS NULL OR LOWER(x.name) LIKE :term OR LOWER(x.code) LIKE :term)
          AND (:excludeId is NULL OR NOT EXISTS 
          ( FROM Y y WHERE y.id.someId = x.id AND 
           y.id.someOtherId = :excludeId)
          )
       """)

and it worked. 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: duplicate A duplicate of another issue
Projects
None yet
Development

No branches or pull requests

6 participants