diff --git a/pom.xml b/pom.xml index 0aea78d577..c2e2e8bd67 100755 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-jpa-parent - 3.4.0-SNAPSHOT + 3.4.0-GH-3536-SNAPSHOT pom Spring Data JPA Parent diff --git a/spring-data-envers/pom.xml b/spring-data-envers/pom.xml index 8b836ae2f3..fcfaed2fe2 100755 --- a/spring-data-envers/pom.xml +++ b/spring-data-envers/pom.xml @@ -5,12 +5,12 @@ org.springframework.data spring-data-envers - 3.4.0-SNAPSHOT + 3.4.0-GH-3536-SNAPSHOT org.springframework.data spring-data-jpa-parent - 3.4.0-SNAPSHOT + 3.4.0-GH-3536-SNAPSHOT ../pom.xml diff --git a/spring-data-jpa-distribution/pom.xml b/spring-data-jpa-distribution/pom.xml index e9e1754bc3..6857d29280 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.4.0-SNAPSHOT + 3.4.0-GH-3536-SNAPSHOT ../pom.xml diff --git a/spring-data-jpa-performance/pom.xml b/spring-data-jpa-performance/pom.xml index 38f130983e..1f890d3e8d 100644 --- a/spring-data-jpa-performance/pom.xml +++ b/spring-data-jpa-performance/pom.xml @@ -15,7 +15,7 @@ org.springframework.data spring-data-jpa-parent - 3.4.0-SNAPSHOT + 3.4.0-GH-3536-SNAPSHOT ../pom.xml diff --git a/spring-data-jpa/pom.xml b/spring-data-jpa/pom.xml index 3006702796..c40e355a4d 100644 --- a/spring-data-jpa/pom.xml +++ b/spring-data-jpa/pom.xml @@ -6,7 +6,7 @@ org.springframework.data spring-data-jpa - 3.4.0-SNAPSHOT + 3.4.0-GH-3536-SNAPSHOT Spring Data JPA Spring Data module for JPA repositories. @@ -15,7 +15,7 @@ org.springframework.data spring-data-jpa-parent - 3.4.0-SNAPSHOT + 3.4.0-GH-3536-SNAPSHOT ../pom.xml diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlCountQueryTransformer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlCountQueryTransformer.java index 6c328b1f36..aec9763fa0 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlCountQueryTransformer.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlCountQueryTransformer.java @@ -15,9 +15,7 @@ */ package org.springframework.data.jpa.repository.query; -import static org.springframework.data.jpa.repository.query.QueryTokens.TOKEN_CLOSE_PAREN; -import static org.springframework.data.jpa.repository.query.QueryTokens.TOKEN_COMMA; -import static org.springframework.data.jpa.repository.query.QueryTokens.TOKEN_COUNT_FUNC; +import static org.springframework.data.jpa.repository.query.QueryTokens.*; import org.springframework.data.jpa.repository.query.QueryRenderer.QueryRendererBuilder; import org.springframework.data.jpa.repository.query.QueryTransformers.CountSelectionTokenStream; @@ -98,7 +96,7 @@ public QueryTokenStream visitSelect_clause(EqlParser.Select_clauseContext ctx) { private QueryRendererBuilder getDistinctCountSelection(QueryTokenStream selectionListbuilder) { QueryRendererBuilder nested = new QueryRendererBuilder(); - CountSelectionTokenStream countSelection = QueryTransformers.filterCountSelection(selectionListbuilder); + CountSelectionTokenStream countSelection = CountSelectionTokenStream.create(selectionListbuilder); if (countSelection.requiresPrimaryAlias()) { // constructor diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlCountQueryTransformer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlCountQueryTransformer.java index 537da47e71..735bdae29c 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlCountQueryTransformer.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlCountQueryTransformer.java @@ -15,12 +15,7 @@ */ package org.springframework.data.jpa.repository.query; -import static org.springframework.data.jpa.repository.query.QueryTokens.TOKEN_AS; -import static org.springframework.data.jpa.repository.query.QueryTokens.TOKEN_CLOSE_PAREN; -import static org.springframework.data.jpa.repository.query.QueryTokens.TOKEN_COUNT_FUNC; -import static org.springframework.data.jpa.repository.query.QueryTokens.TOKEN_DOUBLE_UNDERSCORE; -import static org.springframework.data.jpa.repository.query.QueryTokens.TOKEN_OPEN_PAREN; -import static org.springframework.data.jpa.repository.query.QueryTokens.TOKEN_SELECT_COUNT; +import static org.springframework.data.jpa.repository.query.QueryTokens.*; import org.springframework.data.jpa.repository.query.HqlParser.SelectClauseContext; import org.springframework.data.jpa.repository.query.QueryRenderer.QueryRendererBuilder; @@ -208,6 +203,22 @@ public QueryTokenStream visitSelectClause(HqlParser.SelectClauseContext ctx) { return builder; } + @Override + public QueryTokenStream visitSelection(HqlParser.SelectionContext ctx) { + + if (isSubquery(ctx)) { + return super.visitSelection(ctx); + } + + QueryRendererBuilder builder = QueryRenderer.builder(); + + builder.append(visit(ctx.selectExpression())); + + // do not append variables to skip AS field aliasing + + return builder; + } + @Override public QueryRendererBuilder visitQueryOrder(HqlParser.QueryOrderContext ctx) { @@ -240,14 +251,14 @@ private QueryRendererBuilder visitSubQuerySelectClause(SelectClauseContext ctx, private QueryRendererBuilder getDistinctCountSelection(QueryTokenStream selectionListbuilder) { QueryRendererBuilder nested = new QueryRendererBuilder(); - CountSelectionTokenStream countSelection = QueryTransformers.filterCountSelection(selectionListbuilder); + CountSelectionTokenStream countSelection = CountSelectionTokenStream.create(selectionListbuilder); if (countSelection.requiresPrimaryAlias()) { // constructor nested.append(QueryTokens.token(primaryFromAlias)); } else { // keep all the select items to distinct against - nested.append(countSelection); + nested.append(selectionListbuilder); } return nested; } diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlCountQueryTransformer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlCountQueryTransformer.java index 6ceb6e171a..2adac83e9b 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlCountQueryTransformer.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlCountQueryTransformer.java @@ -96,7 +96,7 @@ public QueryRendererBuilder visitSelect_clause(JpqlParser.Select_clauseContext c private QueryRendererBuilder getDistinctCountSelection(QueryTokenStream selectionListbuilder) { QueryRendererBuilder nested = new QueryRendererBuilder(); - CountSelectionTokenStream countSelection = QueryTransformers.filterCountSelection(selectionListbuilder); + CountSelectionTokenStream countSelection = CountSelectionTokenStream.create(selectionListbuilder); if (countSelection.requiresPrimaryAlias()) { // constructor diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryTransformers.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryTransformers.java index 7481000ff8..46bdc36003 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryTransformers.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryTransformers.java @@ -29,46 +29,46 @@ */ class QueryTransformers { - static CountSelectionTokenStream filterCountSelection(QueryTokenStream selection) { + static class CountSelectionTokenStream implements QueryTokenStream { - List target = new ArrayList<>(selection.size()); - boolean skipNext = false; - boolean containsNew = false; + private final List tokens; + private final boolean requiresPrimaryAlias; - for (QueryToken token : selection) { + CountSelectionTokenStream(List tokens, boolean requiresPrimaryAlias) { + this.tokens = tokens; + this.requiresPrimaryAlias = requiresPrimaryAlias; + } - if (skipNext) { - skipNext = false; - continue; - } + static CountSelectionTokenStream create(QueryTokenStream selection) { - if (token.equals(TOKEN_AS)) { - skipNext = true; - continue; - } + List target = new ArrayList<>(selection.size()); + boolean skipNext = false; + boolean containsNew = false; - if (!token.equals(TOKEN_COMMA) && token.isExpression()) { - token = QueryTokens.token(token.value()); - } + for (QueryToken token : selection) { - if (!containsNew && token.value().contains("new")) { - containsNew = true; - } + if (skipNext) { + skipNext = false; + continue; + } - target.add(token); - } + if (token.equals(TOKEN_AS)) { + skipNext = true; + continue; + } - return new CountSelectionTokenStream(target, containsNew); - } + if (!token.equals(TOKEN_COMMA) && token.isExpression()) { + token = QueryTokens.token(token.value()); + } - static class CountSelectionTokenStream implements QueryTokenStream { + if (!containsNew && token.value().contains("new")) { + containsNew = true; + } - private final List tokens; - private final boolean requiresPrimaryAlias; + target.add(token); + } - public CountSelectionTokenStream(List tokens, boolean requiresPrimaryAlias) { - this.tokens = tokens; - this.requiresPrimaryAlias = requiresPrimaryAlias; + return new CountSelectionTokenStream(target, containsNew); } @Override diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryTransformerTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryTransformerTests.java index 52bdcd82d1..849c4abe5c 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryTransformerTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryTransformerTests.java @@ -98,7 +98,7 @@ void applyCountToMoreComplexQuery() { } @Test - void applyCountToAlreadySorteQuery() { + void applyCountToAlreadySortedQuery() { // given var original = "SELECT e FROM Employee e where e.name = :name ORDER BY e.modified_date"; diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryTransformerTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryTransformerTests.java index b4ce21db0a..759dfaf082 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryTransformerTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryTransformerTests.java @@ -86,6 +86,23 @@ void applyCountToSimpleQuery() { assertThat(results).isEqualTo("select count(e) FROM Employee e where e.name = :name"); } + @Test // GH-3536 + void shouldCreateCountQueryForDistinctCount() { + + // given + var original = """ + select distinct cast(e.timestampField as date) as foo + from ExampleEntity e + order by cast(e.timestampField as date) desc + """; + + // when + var results = createCountQueryFor(original); + + // then + assertThat(results).isEqualTo("select count(distinct cast(e.timestampField as date)) from ExampleEntity e"); + } + @Test void applyCountToMoreComplexQuery() { @@ -701,11 +718,9 @@ void applySortingAccountsForNativeWindowFunction() { .isEqualTo("select dense_rank() over (order by lastname) from user u order by u.lastname, u.age desc"); // partition by + order by in over clause - assertThat( - createQueryFor( - "select dense_rank() over (partition by active, age order by lastname range between 1.0 preceding and 1.0 following) from user u", - sort)) - .isEqualTo( + assertThat(createQueryFor( + "select dense_rank() over (partition by active, age order by lastname range between 1.0 preceding and 1.0 following) from user u", + sort)).isEqualTo( "select dense_rank() over (partition by active, age order by lastname range between 1.0 preceding and 1.0 following) from user u order by u.age desc"); // partition by + order by in over clause + order by at the end diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryTransformerTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryTransformerTests.java index eb04b8de07..59285245f2 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryTransformerTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryTransformerTests.java @@ -99,7 +99,7 @@ void applyCountToMoreComplexQuery() { } @Test - void applyCountToAlreadySorteQuery() { + void applyCountToAlreadySortedQuery() { // given var original = "SELECT e FROM Employee e where e.name = :name ORDER BY e.modified_date";