From 8be1a9fd044d4d11826e13868b51e10ffba12012 Mon Sep 17 00:00:00 2001 From: "Greg L. Turnquist" Date: Mon, 15 May 2023 14:12:04 -0500 Subject: [PATCH 1/3] Create new branch. --- pom.xml | 2 +- spring-data-envers/pom.xml | 4 ++-- spring-data-jpa-distribution/pom.xml | 2 +- spring-data-jpa/pom.xml | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 0bc96784c3..31737a609c 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-jpa-parent - 3.2.0-SNAPSHOT + 3.2.0-gh-2954-SNAPSHOT pom Spring Data JPA Parent diff --git a/spring-data-envers/pom.xml b/spring-data-envers/pom.xml index 0c3d16ef85..8a371e0649 100755 --- a/spring-data-envers/pom.xml +++ b/spring-data-envers/pom.xml @@ -5,12 +5,12 @@ org.springframework.data spring-data-envers - 3.2.0-SNAPSHOT + 3.2.0-gh-2954-SNAPSHOT org.springframework.data spring-data-jpa-parent - 3.2.0-SNAPSHOT + 3.2.0-gh-2954-SNAPSHOT ../pom.xml diff --git a/spring-data-jpa-distribution/pom.xml b/spring-data-jpa-distribution/pom.xml index 991cd8cbf0..068a03a67b 100644 --- a/spring-data-jpa-distribution/pom.xml +++ b/spring-data-jpa-distribution/pom.xml @@ -14,7 +14,7 @@ org.springframework.data spring-data-jpa-parent - 3.2.0-SNAPSHOT + 3.2.0-gh-2954-SNAPSHOT ../pom.xml diff --git a/spring-data-jpa/pom.xml b/spring-data-jpa/pom.xml index 248ac4b2fd..2191263010 100644 --- a/spring-data-jpa/pom.xml +++ b/spring-data-jpa/pom.xml @@ -6,7 +6,7 @@ org.springframework.data spring-data-jpa - 3.2.0-SNAPSHOT + 3.2.0-gh-2954-SNAPSHOT Spring Data JPA Spring Data module for JPA repositories. @@ -15,7 +15,7 @@ org.springframework.data spring-data-jpa-parent - 3.2.0-SNAPSHOT + 3.2.0-gh-2954-SNAPSHOT ../pom.xml From 8bf6c89ebb3eec3969628910c6522e02e099a897 Mon Sep 17 00:00:00 2001 From: "Greg L. Turnquist" Date: Mon, 15 May 2023 14:12:19 -0500 Subject: [PATCH 2/3] Resolve handling of ESCAPE clause with LIKE queries on Hibernate. The HQL parser has to handle parameters in addition to character values in order to support SpEL. See #2954 Original Pull Request: #2956. --- .../data/jpa/repository/query/Hql.g4 | 2 +- .../jpa/repository/query/HqlQueryRenderer.java | 2 +- .../repository/query/JpqlQueryRenderer.java | 6 ++++++ .../EclipseLinkUserRepositoryFinderTests.java | 18 ++++++++++++++++++ .../repository/UserRepositoryFinderTests.java | 7 +------ .../jpa/repository/sample/UserRepository.java | 2 +- 6 files changed, 28 insertions(+), 9 deletions(-) diff --git a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Hql.g4 b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Hql.g4 index 488031b42c..731bb16c7d 100644 --- a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Hql.g4 +++ b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Hql.g4 @@ -579,7 +579,7 @@ dealingWithNullExpression // https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-like-predicate stringPatternMatching - : expression NOT? (LIKE | ILIKE) expression (ESCAPE character)? + : expression NOT? (LIKE | ILIKE) expression (ESCAPE expression)? ; // https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-elements-indices diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlQueryRenderer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlQueryRenderer.java index 39d6271fe3..5446173ca2 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlQueryRenderer.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlQueryRenderer.java @@ -2124,7 +2124,7 @@ public List visitStringPatternMatching(HqlParser.StringPat if (ctx.ESCAPE() != null) { tokens.add(new JpaQueryParsingToken(ctx.ESCAPE())); - tokens.addAll(visit(ctx.character())); + tokens.addAll(visit(ctx.expression(2))); } return tokens; diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryRenderer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryRenderer.java index 0a148f145f..b5a41fe998 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryRenderer.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryRenderer.java @@ -1206,6 +1206,12 @@ public List visitLike_expression(JpqlParser.Like_expressio tokens.add(new JpaQueryParsingToken(ctx.LIKE())); tokens.addAll(visit(ctx.pattern_value())); + if (ctx.ESCAPE() != null) { + + tokens.add(new JpaQueryParsingToken(ctx.ESCAPE())); + tokens.addAll(visit(ctx.escape_character())); + } + return tokens; } diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkUserRepositoryFinderTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkUserRepositoryFinderTests.java index 0caf735d4e..1b6bc2a7bf 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkUserRepositoryFinderTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkUserRepositoryFinderTests.java @@ -34,4 +34,22 @@ void executesNotInQueryCorrectly() {} @Disabled @Override void executesInKeywordForPageCorrectly() {} + + @Disabled("Can't get ESCAPE clause working with EclipseLink. See #2955") + @Override + void escapingInLikeSpels() { + super.escapingInLikeSpels(); + } + + @Disabled("Can't get ESCAPE clause working with EclipseLink. See #2955") + @Override + void escapingInLikeSpelsInThePresenceOfEscapeCharacters() { + super.escapingInLikeSpelsInThePresenceOfEscapeCharacters(); + } + + @Disabled("Can't get ESCAPE clause working with EclipseLink. See #2955") + @Override + void escapingInLikeSpelsInThePresenceOfEscapedWildcards() { + super.escapingInLikeSpelsInThePresenceOfEscapedWildcards(); + } } diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryFinderTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryFinderTests.java index 6fa3e2b00f..bccc417ea0 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryFinderTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryFinderTests.java @@ -25,7 +25,6 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; @@ -235,7 +234,6 @@ void parametersForContainsGetProperlyEscaped() { .isEmpty(); } - @Disabled("Can't get ESCAPE clause working with Hibernate") @Test // DATAJPA-1519 void escapingInLikeSpels() { @@ -246,7 +244,6 @@ void escapingInLikeSpels() { assertThat(userRepository.findContainingEscaped("att_")).containsExactly(extra); } - @Disabled("Can't get ESCAPE clause working with Hibernate") @Test // DATAJPA-1522 void escapingInLikeSpelsInThePresenceOfEscapeCharacters() { @@ -256,7 +253,6 @@ void escapingInLikeSpelsInThePresenceOfEscapeCharacters() { assertThat(userRepository.findContainingEscaped("att\\x")).containsExactly(withEscapeCharacter); } - @Disabled("Can't get ESCAPE clause working with Hibernate") @Test // DATAJPA-1522 void escapingInLikeSpelsInThePresenceOfEscapedWildcards() { @@ -288,8 +284,7 @@ void executesQueryWithProjectionContainingReferenceToPluralAttribute() { List rolesAndFirstnameBy = userRepository.findRolesAndFirstnameBy(); - assertThat(rolesAndFirstnameBy) - .isNotNull(); + assertThat(rolesAndFirstnameBy).isNotNull(); for (RolesAndFirstname rolesAndFirstname : rolesAndFirstnameBy) { assertThat(rolesAndFirstname.getFirstname()).isNotNull(); diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java index 5eb7490398..821b119a73 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java @@ -625,7 +625,7 @@ List findUsersByFirstnameForSpELExpressionWithParameterIndexOnlyWithEntity List findByNamedQueryWithConstructorExpression(); // DATAJPA-1519 - @Query("select u from User u where u.lastname like '%?#{escape([0])}%' escape ?#{escapeCharacter()}") + @Query("select u from User u where u.lastname like %?#{escape([0])}% escape ?#{escapeCharacter()}") List findContainingEscaped(String namePart); // DATAJPA-1303 From 635997d80f3ba06b64523930d741faa187c3375d Mon Sep 17 00:00:00 2001 From: "Greg L. Turnquist" Date: Wed, 17 May 2023 15:47:19 -0500 Subject: [PATCH 3/3] Resolve handling of ESCAPE clause with LIKE queries on EclipseLink. Migrate tests to H2 to verify LIKE with ESCAPE works properly on EclipseLink with Spring Data JPA. See #2955 Original Pull Request: #2956. --- pom.xml | 1 + spring-data-jpa/pom.xml | 7 ++++ .../data/jpa/repository/query/Hql.g4 | 2 +- .../repository/query/HqlQueryRenderer.java | 6 +++- .../EclipseLinkUserRepositoryFinderTests.java | 20 ++--------- .../repository/UserRepositoryFinderTests.java | 3 +- .../namespace-application-context-h2.xml | 31 ++++++++++++++++ .../src/test/resources/eclipselink-h2.xml | 21 +++++++++++ .../src/test/resources/infrastructure-h2.xml | 35 +++++++++++++++++++ .../src/test/resources/scripts/h2-init.sql | 1 + .../scripts/h2-stored-procedures.sql | 9 +++++ 11 files changed, 115 insertions(+), 21 deletions(-) create mode 100644 spring-data-jpa/src/test/resources/config/namespace-application-context-h2.xml create mode 100644 spring-data-jpa/src/test/resources/eclipselink-h2.xml create mode 100644 spring-data-jpa/src/test/resources/infrastructure-h2.xml create mode 100644 spring-data-jpa/src/test/resources/scripts/h2-init.sql create mode 100644 spring-data-jpa/src/test/resources/scripts/h2-stored-procedures.sql diff --git a/pom.xml b/pom.xml index 31737a609c..2f9074a69d 100644 --- a/pom.xml +++ b/pom.xml @@ -31,6 +31,7 @@ 3.0.3 6.2.1.Final 2.7.1 +

2.1.214

4.5 8.0.31 42.5.0 diff --git a/spring-data-jpa/pom.xml b/spring-data-jpa/pom.xml index 2191263010..436db40431 100644 --- a/spring-data-jpa/pom.xml +++ b/spring-data-jpa/pom.xml @@ -100,6 +100,13 @@ test + + com.h2database + h2 + ${h2} + test + + com.mysql diff --git a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Hql.g4 b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Hql.g4 index 731bb16c7d..b702bad0c1 100644 --- a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Hql.g4 +++ b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Hql.g4 @@ -579,7 +579,7 @@ dealingWithNullExpression // https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-like-predicate stringPatternMatching - : expression NOT? (LIKE | ILIKE) expression (ESCAPE expression)? + : expression NOT? (LIKE | ILIKE) expression (ESCAPE (character|parameter))? ; // https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-elements-indices diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlQueryRenderer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlQueryRenderer.java index 5446173ca2..17458b20e6 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlQueryRenderer.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlQueryRenderer.java @@ -2124,7 +2124,11 @@ public List visitStringPatternMatching(HqlParser.StringPat if (ctx.ESCAPE() != null) { tokens.add(new JpaQueryParsingToken(ctx.ESCAPE())); - tokens.addAll(visit(ctx.expression(2))); + if (ctx.character() != null) { + tokens.addAll(visit(ctx.character())); + } else if (ctx.parameter() != null) { + tokens.addAll(visit(ctx.parameter())); + } } return tokens; diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkUserRepositoryFinderTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkUserRepositoryFinderTests.java index 1b6bc2a7bf..473331252a 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkUserRepositoryFinderTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkUserRepositoryFinderTests.java @@ -23,8 +23,9 @@ * https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477. * * @author Oliver Gierke + * @author Greg Turnquist */ -@ContextConfiguration("classpath:eclipselink.xml") +@ContextConfiguration("classpath:eclipselink-h2.xml") class EclipseLinkUserRepositoryFinderTests extends UserRepositoryFinderTests { @Disabled @@ -35,21 +36,4 @@ void executesNotInQueryCorrectly() {} @Override void executesInKeywordForPageCorrectly() {} - @Disabled("Can't get ESCAPE clause working with EclipseLink. See #2955") - @Override - void escapingInLikeSpels() { - super.escapingInLikeSpels(); - } - - @Disabled("Can't get ESCAPE clause working with EclipseLink. See #2955") - @Override - void escapingInLikeSpelsInThePresenceOfEscapeCharacters() { - super.escapingInLikeSpelsInThePresenceOfEscapeCharacters(); - } - - @Disabled("Can't get ESCAPE clause working with EclipseLink. See #2955") - @Override - void escapingInLikeSpelsInThePresenceOfEscapedWildcards() { - super.escapingInLikeSpelsInThePresenceOfEscapedWildcards(); - } } diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryFinderTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryFinderTests.java index bccc417ea0..4b6c4bb9eb 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryFinderTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryFinderTests.java @@ -52,10 +52,11 @@ * * @author Oliver Gierke * @author Krzysztof Krason + * @author Greg Turnquist * @see QueryLookupStrategy */ @ExtendWith(SpringExtension.class) -@ContextConfiguration(locations = "classpath:config/namespace-application-context.xml") +@ContextConfiguration(locations = "classpath:config/namespace-application-context-h2.xml") @Transactional class UserRepositoryFinderTests { diff --git a/spring-data-jpa/src/test/resources/config/namespace-application-context-h2.xml b/spring-data-jpa/src/test/resources/config/namespace-application-context-h2.xml new file mode 100644 index 0000000000..9cb3eab275 --- /dev/null +++ b/spring-data-jpa/src/test/resources/config/namespace-application-context-h2.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + diff --git a/spring-data-jpa/src/test/resources/eclipselink-h2.xml b/spring-data-jpa/src/test/resources/eclipselink-h2.xml new file mode 100644 index 0000000000..71d4ab6372 --- /dev/null +++ b/spring-data-jpa/src/test/resources/eclipselink-h2.xml @@ -0,0 +1,21 @@ + + + + + + + + org.h2.Driver + jdbc:h2:mem:hades + sa + + create-tables + false + SEVERE + + + diff --git a/spring-data-jpa/src/test/resources/infrastructure-h2.xml b/spring-data-jpa/src/test/resources/infrastructure-h2.xml new file mode 100644 index 0000000000..723454c015 --- /dev/null +++ b/spring-data-jpa/src/test/resources/infrastructure-h2.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-data-jpa/src/test/resources/scripts/h2-init.sql b/spring-data-jpa/src/test/resources/scripts/h2-init.sql new file mode 100644 index 0000000000..1c8a0e7976 --- /dev/null +++ b/spring-data-jpa/src/test/resources/scripts/h2-init.sql @@ -0,0 +1 @@ +; \ No newline at end of file diff --git a/spring-data-jpa/src/test/resources/scripts/h2-stored-procedures.sql b/spring-data-jpa/src/test/resources/scripts/h2-stored-procedures.sql new file mode 100644 index 0000000000..1023dc1a39 --- /dev/null +++ b/spring-data-jpa/src/test/resources/scripts/h2-stored-procedures.sql @@ -0,0 +1,9 @@ +/; +DROP alias IF EXISTS plus1inout +/; +CREATE alias plus1inout AS $$ +Integer plus1inout(Integer arg) { + return arg + 1; +} +$$ +/;