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

Improve QueryUtils.applyAndBind(…) to avoid StackOverflowError with many entities #2870

Closed
ipavkovic opened this issue Mar 20, 2023 · 2 comments
Assignees
Labels
type: enhancement A general enhancement

Comments

@ipavkovic
Copy link

While using SimpleJpaRepository.deleteAllInBatch method with about 500 entities I noticed that the called hibernate library tends to throw a StackOverflowError due to its antlr parsing nature.

To prevent this spring data jpa should not create an sql statement like

delete entity where alias =?1 OR alias =?2 OR ...

Instead, sql in should be used:

delete entity where alias in (?1, ?2, ...)

https://github.com/spring-projects/spring-data-jpa/blob/main/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java#L522

diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java
index f581f191..ce9a74b8 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java
@@ -533,7 +533,7 @@ public abstract class QueryUtils {
 
                String alias = detectAlias(queryString);
                StringBuilder builder = new StringBuilder(queryString);
-               builder.append(" where");
+               builder.append(" where ").append(alias).append(" in (");
 
                int i = 0;
 
@@ -541,12 +541,13 @@ public abstract class QueryUtils {
 
                        iterator.next();
 
-                       builder.append(String.format(" %s = ?%d", alias, ++i));
+                       builder.append('?').append(++i);
 
                        if (iterator.hasNext()) {
-                               builder.append(" or");
+                               builder.append(", ");
                        }
                }
+               builder.append(")");
 
                Query query = entityManager.createQuery(builder.toString());
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Mar 20, 2023
@gregturn gregturn self-assigned this Mar 20, 2023
@gregturn gregturn added type: enhancement A general enhancement status: pending-design-work Needs design work before any code can be developed and removed status: waiting-for-triage An issue we've not yet triaged labels Mar 20, 2023
@posuhov
Copy link

posuhov commented Oct 24, 2024

@ipavkovic you can use repository.deleteAllByIdInBatch (https://github.com/spring-projects/spring-data-jpa/blob/ae2aa63be39b6434d3cf24c228e10d2e11e07294/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java#L226C14-L226C34) instead of repository.deleteAllInBatch

it generates a query like delete from table where alias in (?1, ?2, ...)

@mp911de mp911de changed the title suggestion: improve QueryUtils.applyAndBind Improve QueryUtils.applyAndBind(…) to avoid StackOverflowError with many entities Jan 23, 2025
@mp911de mp911de assigned mp911de and unassigned gregturn Jan 23, 2025
@mp911de mp911de removed the status: pending-design-work Needs design work before any code can be developed label Jan 23, 2025
@mp911de
Copy link
Member

mp911de commented Jan 23, 2025

Probably the easiest way is to use a IN (?1) predicate instead of creating a huge list of parameters.

mp911de added a commit that referenced this issue Jan 23, 2025
We now use an IN (?1) predicate to avoid repeated OR alias = … variants to ease on JPQL parsing. With a sufficient number of predicates, parsers dive into a very deep parsing tree risking a StackOverflowError.

Closes #2870
@mp911de mp911de added this to the 3.5 M1 (2025.0.0) milestone Jan 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

5 participants