From 4bc46bb4d878cf2f31781dfa8b6b637881793420 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Thu, 1 Feb 2024 10:05:22 +0100 Subject: [PATCH] Fix query rendering for signed expressions & literals. This commit makes sure to retain signed expressions (hql, eql, jpql) and literals (eql, jpql) when rendering the query. Prior to the change singed expression/literal rendering added a space between the sign and the actual value so that `-1` would become `- 1` and `-count(u)` would be `- count(u)`. Additionally a minor glitch in the jpql rendering was resolved that would add an extra space before the closing bracket of a LENGTH expression. See: #3342 --- .../repository/query/EqlQueryRenderer.java | 2 +- .../repository/query/HqlQueryRenderer.java | 3 ++- .../repository/query/JpqlQueryRenderer.java | 3 ++- .../query/EqlQueryRendererTests.java | 26 +++++++++++++++++++ .../query/HqlQueryRendererTests.java | 10 +++++++ .../query/JpqlQueryRendererTests.java | 26 +++++++++++++++++++ 6 files changed, 67 insertions(+), 3 deletions(-) diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlQueryRenderer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlQueryRenderer.java index 6688d78f0..8ece7c965 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlQueryRenderer.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlQueryRenderer.java @@ -1609,7 +1609,7 @@ class EqlQueryRenderer extends EqlBaseVisitor> { List tokens = new ArrayList<>(); if (ctx.op != null) { - tokens.add(new JpaQueryParsingToken(ctx.op)); + tokens.add(new JpaQueryParsingToken(ctx.op, false)); } tokens.addAll(visit(ctx.arithmetic_primary())); 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 0795beaf9..5b8c990fe 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 @@ -24,6 +24,7 @@ import java.util.List; * An ANTLR {@link org.antlr.v4.runtime.tree.ParseTreeVisitor} that renders an HQL query without making any changes. * * @author Greg Turnquist + * @author Christoph Strobl * @since 3.1 */ @SuppressWarnings({ "ConstantConditions", "DuplicatedCode" }) @@ -1326,7 +1327,7 @@ class HqlQueryRenderer extends HqlBaseVisitor> { List tokens = new ArrayList<>(); - tokens.add(new JpaQueryParsingToken(ctx.op)); + tokens.add(new JpaQueryParsingToken(ctx.op, false)); tokens.addAll(visit(ctx.expression())); 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 46f5335cc..1061e102c 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 @@ -1469,7 +1469,7 @@ class JpqlQueryRenderer extends JpqlBaseVisitor> { List tokens = new ArrayList<>(); if (ctx.op != null) { - tokens.add(new JpaQueryParsingToken(ctx.op)); + tokens.add(new JpaQueryParsingToken(ctx.op, false)); } tokens.addAll(visit(ctx.arithmetic_primary())); @@ -1700,6 +1700,7 @@ class JpqlQueryRenderer extends JpqlBaseVisitor> { tokens.add(new JpaQueryParsingToken(ctx.LENGTH(), false)); tokens.add(TOKEN_OPEN_PAREN); tokens.addAll(visit(ctx.string_expression(0))); + NOSPACE(tokens); tokens.add(TOKEN_CLOSE_PAREN); } else if (ctx.LOCATE() != null) { diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java index b8a6030e2..326b53f6c 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java @@ -22,6 +22,8 @@ import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; /** * Tests built around examples of EQL found in the JPA spec @@ -30,6 +32,7 @@ import org.junit.jupiter.api.Test; * IMPORTANT: Purely verifies the parser without any transformations. * * @author Greg Turnquist + * @author Christoph Strobl */ class EqlQueryRendererTests { @@ -992,4 +995,27 @@ class EqlQueryRendererTests { void powerShouldBeLegalInAQuery() { assertQuery("select e.power.id from MyEntity e"); } + + @ParameterizedTest // GH-3342 + @ValueSource(strings = { + "select 1 from User u", + "select -1 from User u", + "select +1 from User u", + "select +1*-100 from User u", + "select count(u)*-0.7f from User u", + "select count(oi) + (-100) as perc from StockOrderItem oi", + "select p from Payment p where length(p.cardNumber) between +16 and -20" + }) + void signedLiteralShouldWork(String query) { + assertQuery(query); + } + + @ParameterizedTest // GH-3342 + @ValueSource(strings = { + "select -count(u) from User u", + "select +1*(-count(u)) from User u" + }) + void signedExpressionsShouldWork(String query) { + assertQuery(query); + } } diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java index 6715d4149..7b903cb1c 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java @@ -33,6 +33,7 @@ import org.junit.jupiter.params.provider.ValueSource; * IMPORTANT: Purely verifies the parser without any transformations. * * @author Greg Turnquist + * @author Christoph Strobl * @since 3.1 */ class HqlQueryRendererTests { @@ -1651,4 +1652,13 @@ class HqlQueryRendererTests { void signedLiteralShouldWork(String query) { assertQuery(query); } + + @ParameterizedTest // GH-3342 + @ValueSource(strings = { + "select -count(u) from User u", + "select +1*(-count(u)) from User u" + }) + void signedExpressionsShouldWork(String query) { + assertQuery(query); + } } diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryRendererTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryRendererTests.java index 141fde4f3..1cf24e1af 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryRendererTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryRendererTests.java @@ -22,6 +22,8 @@ import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; /** * Tests built around examples of JPQL found in the JPA spec @@ -30,6 +32,7 @@ import org.junit.jupiter.api.Test; * IMPORTANT: Purely verifies the parser without any transformations. * * @author Greg Turnquist + * @author Christoph Strobl * @since 3.1 */ class JpqlQueryRendererTests { @@ -993,4 +996,27 @@ class JpqlQueryRendererTests { void powerShouldBeLegalInAQuery() { assertQuery("select e.power.id from MyEntity e"); } + + @ParameterizedTest // GH-3342 + @ValueSource(strings = { + "select 1 as value from User u", + "select -1 as value from User u", + "select +1 as value from User u", + "select +1*-100 as value from User u", + "select count(u)*-0.7f as value from User u", + "select count(oi) + (-100) as perc from StockOrderItem oi", + "select p from Payment p where length(p.cardNumber) between +16 and -20" + }) + void signedLiteralShouldWork(String query) { + assertQuery(query); + } + + @ParameterizedTest // GH-3342 + @ValueSource(strings = { + "select -count(u) from User u", + "select +1*(-count(u)) from User u" + }) + void signedExpressionsShouldWork(String query) { + assertQuery(query); + } }