From a9279c729dc14b4ace80971d1c3f3b08c6cf83a7 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 25 Aug 2023 09:16:06 +0200 Subject: [PATCH] Register individual bindings for IN bindings if parameter is already bound differently. We now register a new parameter binding if the named/positional parameter is already bound in an incompatible style. Closes #3126 --- .../jpa/repository/query/StringQuery.java | 26 +++++--------- .../query/StringQueryUnitTests.java | 35 ++++++++++++++++--- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StringQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StringQuery.java index ada8793f29..ad1a25cb97 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StringQuery.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StringQuery.java @@ -288,36 +288,28 @@ private String parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(St : ParameterOrigin.ofExpression(expression); BindingIdentifier targetBinding = queryParameter; + Function bindingFactory; switch (ParameterBindingType.of(typeSource)) { case LIKE: Type likeType = LikeParameterBinding.getLikeTypeFrom(matcher.group(2)); - - if (origin.isExpression()) { - parameterBindings.register(new LikeParameterBinding(queryParameter, origin, likeType)); - } else { - targetBinding = parameterBindings.register(queryParameter, origin, - (identifier) -> new LikeParameterBinding(identifier, origin, likeType)); - } - + bindingFactory = (identifier) -> new LikeParameterBinding(identifier, origin, likeType); break; case IN: - - parameterBindings.register(new InParameterBinding(queryParameter, origin)); - + bindingFactory = (identifier) -> new InParameterBinding(identifier, origin); break; case AS_IS: // fall-through we don't need a special parameter queryParameter for the given parameter. default: + bindingFactory = (identifier) -> new ParameterBinding(identifier, origin); + } - if (origin.isExpression()) { - parameterBindings.register(new ParameterBinding(queryParameter, origin)); - } else { - targetBinding = parameterBindings.register(queryParameter, origin, - (identifier) -> new ParameterBinding(identifier, origin)); - } + if (origin.isExpression()) { + parameterBindings.register(bindingFactory.apply(queryParameter)); + } else { + targetBinding = parameterBindings.register(queryParameter, origin, bindingFactory); } replacement = targetBinding.hasName() ? ":" + targetBinding.getName() diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/StringQueryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/StringQueryUnitTests.java index 7b4f6e54a1..cde06804a0 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/StringQueryUnitTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/StringQueryUnitTests.java @@ -246,8 +246,6 @@ void detectsNamedInParameterBindings() { assertThat(bindings).hasSize(1); assertNamedBinding(InParameterBinding.class, "ids", bindings.get(0)); - - softly.assertAll(); } @Test // DATAJPA-461 @@ -282,8 +280,37 @@ void detectsPositionalInParameterBindings() { assertThat(bindings).hasSize(1); assertPositionalBinding(InParameterBinding.class, 1, bindings.get(0)); + } - softly.assertAll(); + @Test // GH-3126 + void allowsReuseOfParameterWithInAndRegularBinding() { + + StringQuery query = new StringQuery( + "select u from User u where COALESCE(?1) is null OR u.id in ?1 OR COALESCE(?1) is null OR u.id in ?1", true); + + assertThat(query.hasParameterBindings()).isTrue(); + assertThat(query.getQueryString()).isEqualTo( + "select u from User u where COALESCE(?1) is null OR u.id in ?2 OR COALESCE(?1) is null OR u.id in ?2"); + + List bindings = query.getParameterBindings(); + assertThat(bindings).hasSize(2); + + assertPositionalBinding(ParameterBinding.class, 1, bindings.get(0)); + assertPositionalBinding(InParameterBinding.class, 2, bindings.get(1)); + + query = new StringQuery( + "select u from User u where COALESCE(:foo) is null OR u.id in :foo OR COALESCE(:foo) is null OR u.id in :foo", + true); + + assertThat(query.hasParameterBindings()).isTrue(); + assertThat(query.getQueryString()).isEqualTo( + "select u from User u where COALESCE(:foo) is null OR u.id in :foo_1 OR COALESCE(:foo) is null OR u.id in :foo_1"); + + bindings = query.getParameterBindings(); + assertThat(bindings).hasSize(2); + + assertNamedBinding(ParameterBinding.class, "foo", bindings.get(0)); + assertNamedBinding(InParameterBinding.class, "foo_1", bindings.get(1)); } @Test // DATAJPA-461 @@ -360,8 +387,6 @@ void detectsInBindingWithSpecialFrenchCharactersInParentheses() { assertThat(bindings).hasSize(1); assertNamedBinding(InParameterBinding.class, "abonnés", bindings.get(0)); - - softly.assertAll(); } @Test // DATAJPA-545