Skip to content

Commit

Permalink
Use IN predicate for deleteAllInBatch(…).
Browse files Browse the repository at this point in the history
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 committed Jan 23, 2025
1 parent 90d7d69 commit ef226e9
Showing 2 changed files with 11 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -15,10 +15,10 @@
*/
package org.springframework.data.jpa.repository;

import java.util.List;

import jakarta.persistence.EntityManager;

import java.util.List;

import org.springframework.data.domain.Example;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.ListCrudRepository;
@@ -38,7 +38,8 @@
* @author Jens Schauder
*/
@NoRepositoryBean
public interface JpaRepository<T, ID> extends ListCrudRepository<T, ID>, ListPagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
public interface JpaRepository<T, ID>
extends ListCrudRepository<T, ID>, ListPagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {

/**
* Flushes all pending changes to the database.
@@ -66,6 +67,8 @@ public interface JpaRepository<T, ID> extends ListCrudRepository<T, ID>, ListPag
* Deletes the given entities in a batch which means it will create a single query. This kind of operation leaves JPAs
* first level cache and the database out of sync. Consider flushing the {@link EntityManager} before calling this
* method.
* <p>
* It will also NOT honor cascade semantics of JPA, nor will it emit JPA lifecycle events.
*
* @param entities entities to be deleted. Must not be {@literal null}.
* @deprecated Use {@link #deleteAllInBatch(Iterable)} instead.
@@ -80,8 +83,8 @@ default void deleteInBatch(Iterable<T> entities) {
* first level cache and the database out of sync. Consider flushing the {@link EntityManager} before calling this
* method.
* <p>
* It will also NOT honor cascade semantics of JPA, nor will it emit JPA lifecycle events.
*</p>
* It will also NOT honor cascade semantics of JPA, nor will it emit JPA lifecycle events.
*
* @param entities entities to be deleted. Must not be {@literal null}.
* @since 2.5
*/
Original file line number Diff line number Diff line change
@@ -41,16 +41,7 @@
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Member;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -532,7 +523,6 @@ private static Integer findClose(final Integer open, final List<Integer> closes,
* @param entityManager must not be {@literal null}.
* @return Guaranteed to be not {@literal null}.
*/

public static <T> Query applyAndBind(String queryString, Iterable<T> entities, EntityManager entityManager) {

Assert.notNull(queryString, "Querystring must not be null");
@@ -546,30 +536,8 @@ public static <T> Query applyAndBind(String queryString, Iterable<T> entities, E
}

String alias = detectAlias(queryString);
StringBuilder builder = new StringBuilder(queryString);
builder.append(" where");

int i = 0;

while (iterator.hasNext()) {

iterator.next();

builder.append(String.format(" %s = ?%d", alias, ++i));

if (iterator.hasNext()) {
builder.append(" or");
}
}

Query query = entityManager.createQuery(builder.toString());

iterator = entities.iterator();
i = 0;

while (iterator.hasNext()) {
query.setParameter(++i, iterator.next());
}
Query query = entityManager.createQuery("%s where %s IN (?1)".formatted(queryString, alias));
query.setParameter(1, entities instanceof Collection<T> ? entities : Streamable.of(entities).toList());

return query;
}

0 comments on commit ef226e9

Please sign in to comment.