From e5d61e10da42017a31ca7e4e4795dc9b87781dd0 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, jpql) and literals (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/HqlQueryRenderer.java | 3 ++- .../repository/query/JpqlQueryRenderer.java | 3 ++- .../query/HqlQueryRendererTests.java | 10 +++++++ .../query/JpqlQueryRendererTests.java | 26 +++++++++++++++++++ 4 files changed, 40 insertions(+), 2 deletions(-) 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 2a07083eb1..4c4b7ac265 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 @@ * 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 */ class HqlQueryRenderer extends HqlBaseVisitor> { @@ -1325,7 +1326,7 @@ public List visitSignedExpression(HqlParser.SignedExpressi 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 aae3924692..2c5e00fd48 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 @@ -1468,7 +1468,7 @@ public List visitArithmetic_factor(JpqlParser.Arithmetic_f 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())); @@ -1699,6 +1699,7 @@ public List visitFunctions_returning_numerics( 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/HqlQueryRendererTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java index 6715d4149a..7b903cb1ca 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 @@ * IMPORTANT: Purely verifies the parser without any transformations. * * @author Greg Turnquist + * @author Christoph Strobl * @since 3.1 */ class HqlQueryRendererTests { @@ -1651,4 +1652,13 @@ group by extract(epoch from departureTime) 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 020db01758..4509435979 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.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 @@ * IMPORTANT: Purely verifies the parser without any transformations. * * @author Greg Turnquist + * @author Christoph Strobl * @since 3.1 */ class JpqlQueryRendererTests { @@ -988,4 +991,27 @@ void newShouldBeLegalAsPartOfAStateFieldPathExpression() { 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); + } }