Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use * instead of primary alias in count queries with CTE #3730

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa-parent</artifactId>
<version>3.5.0-SNAPSHOT</version>
<version>3.5.x-GH-3726-SNAPSHOT</version>
<packaging>pom</packaging>

<name>Spring Data JPA Parent</name>
Expand All @@ -30,7 +30,7 @@
<antlr>4.13.0</antlr> <!-- align with Hibernate's parser -->
<eclipselink>4.0.4</eclipselink>
<eclipselink-next>4.0.5-SNAPSHOT</eclipselink-next>
<hibernate>6.6.2.Final</hibernate>
<hibernate>6.6.4.Final</hibernate>
<hibernate-62>6.2.31.Final</hibernate-62>
<hibernate-66-snapshots>6.6.3-SNAPSHOT</hibernate-66-snapshots>
<hibernate-70>7.0.0.Beta1</hibernate-70>
Expand Down
4 changes: 2 additions & 2 deletions spring-data-envers/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-envers</artifactId>
<version>3.5.0-SNAPSHOT</version>
<version>3.5.x-GH-3726-SNAPSHOT</version>

<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa-parent</artifactId>
<version>3.5.0-SNAPSHOT</version>
<version>3.5.x-GH-3726-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion spring-data-jpa-distribution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa-parent</artifactId>
<version>3.5.0-SNAPSHOT</version>
<version>3.5.x-GH-3726-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
10 changes: 8 additions & 2 deletions spring-data-jpa/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>3.5.0-SNAPSHOT</version>
<version>3.5.x-GH-3726-SNAPSHOT</version>

<name>Spring Data JPA</name>
<description>Spring Data module for JPA repositories.</description>
Expand All @@ -15,7 +15,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa-parent</artifactId>
<version>3.5.0-SNAPSHOT</version>
<version>3.5.x-GH-3726-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down Expand Up @@ -98,6 +98,12 @@
<artifactId>junit-platform-launcher</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit-pioneer</groupId>
<artifactId>junit-pioneer</artifactId>
<version>2.3.0</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.hsqldb</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

import static org.springframework.data.jpa.repository.query.QueryTokens.*;

import org.antlr.v4.runtime.ParserRuleContext;
import org.springframework.data.jpa.repository.query.HqlParser.CteContext;
import org.springframework.data.jpa.repository.query.HqlParser.SelectClauseContext;
import org.springframework.data.jpa.repository.query.QueryRenderer.QueryRendererBuilder;
import org.springframework.data.jpa.repository.query.QueryTransformers.CountSelectionTokenStream;
Expand All @@ -36,6 +38,7 @@ class HqlCountQueryTransformer extends HqlQueryRenderer {

private final @Nullable String countProjection;
private final @Nullable String primaryFromAlias;
private boolean containsCTE = false;

HqlCountQueryTransformer(@Nullable String countProjection, @Nullable String primaryFromAlias) {
this.countProjection = countProjection;
Expand Down Expand Up @@ -66,6 +69,12 @@ public QueryRendererBuilder visitOrderedQuery(HqlParser.OrderedQueryContext ctx)
return builder;
}

@Override
public QueryTokenStream visitCte(CteContext ctx) {
this.containsCTE = true;
return super.visitCte(ctx);
}

@Override
public QueryRendererBuilder visitFromQuery(HqlParser.FromQueryContext ctx) {

Expand Down Expand Up @@ -189,7 +198,9 @@ public QueryTokenStream visitSelectClause(HqlParser.SelectClauseContext ctx) {
nested.append(QueryTokens.expression(ctx.DISTINCT()));
nested.append(getDistinctCountSelection(visit(ctx.selectionList())));
} else {
nested.append(QueryTokens.token(primaryFromAlias));
// with CTE primary alias erors with hibernate
nested.append(containsCTE ? QueryTokens.token("*") : QueryTokens.token(primaryFromAlias));
// nested.append(QueryTokens.token(primaryFromAlias));
}
} else {
builder.append(QueryTokens.token(countProjection));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;

import org.springframework.core.SpringProperties;
import org.springframework.data.jpa.repository.QueryRewriter;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.ValueExpressionDelegate;
Expand Down Expand Up @@ -84,6 +85,10 @@ private void validateQuery(String query, String errorMessage, Object... argument
return;
}

if(SpringProperties.getFlag("spring.jpa.query.validation.disbaled")) {
return;
}

EntityManager validatingEm = null;

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junitpioneer.jupiter.SetSystemProperty;
import org.springframework.test.context.ContextConfiguration;

/**
* @author Oliver Gierke
* @author Christoph Strobl
*/
@ContextConfiguration("classpath:eclipselink.xml")
@SetSystemProperty(key = "spring.jpa.query.validation.disbaled", value = "true")
class EclipseLinkEntityGraphRepositoryMethodsIntegrationTests
extends EntityGraphRepositoryMethodsIntegrationTests {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
*/
package org.springframework.data.jpa.repository;

import org.junitpioneer.jupiter.SetSystemProperty;
import org.springframework.test.context.ContextConfiguration;

@ContextConfiguration("classpath:eclipselink.xml")
@SetSystemProperty(key = "spring.jpa.query.validation.disbaled", value = "true")
class EclipseLinkParentRepositoryIntegrationTests extends ParentRepositoryIntegrationTests {

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.springframework.data.jpa.repository;

import org.junitpioneer.jupiter.SetSystemProperty;
import org.springframework.context.annotation.ImportResource;
import org.springframework.test.context.ContextConfiguration;

Expand All @@ -24,6 +25,7 @@
* @author Mark Paluch
*/
@ContextConfiguration
@SetSystemProperty(key = "spring.jpa.query.validation.disbaled", value = "true")
class EclipseLinkRepositoryWithCompositeKeyIntegrationTests extends RepositoryWithIdClassKeyTests {

@ImportResource({ "classpath:infrastructure.xml", "classpath:eclipselink.xml" })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package org.springframework.data.jpa.repository;

import org.junit.jupiter.api.Disabled;
import org.junitpioneer.jupiter.SetSystemProperty;
import org.springframework.test.context.ContextConfiguration;

/**
Expand All @@ -26,6 +27,7 @@
* @author Greg Turnquist
*/
@ContextConfiguration("classpath:eclipselink-h2.xml")
@SetSystemProperty(key = "spring.jpa.query.validation.disbaled", value = "true")
class EclipseLinkUserRepositoryFinderTests extends UserRepositoryFinderTests {

@Disabled
Expand All @@ -40,4 +42,9 @@ void executesInKeywordForPageCorrectly() {}
@Override
void rawMapProjectionWithEntityAndAggregatedValue() {}

@Disabled
@Override
void testQueryWithCTE() {
super.testQueryWithCTE();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import org.springframework.data.jpa.domain.sample.User;
import org.springframework.data.jpa.provider.PersistenceProvider;
import org.springframework.data.jpa.repository.sample.RoleRepository;
import org.springframework.data.jpa.repository.sample.UserExcerptDto;
import org.springframework.data.jpa.repository.sample.UserRepository;
import org.springframework.data.jpa.repository.sample.UserRepository.IdOnly;
import org.springframework.data.jpa.repository.sample.UserRepository.NameOnly;
Expand Down Expand Up @@ -433,6 +434,13 @@ void dtoMultiselectProjectionShouldApplyConstructorExpressionRewriting() {
.contains("Dave", "Carter", "Oliver August");
}

@Test // GH-3726
void testQueryWithCTE() {

Page<UserExcerptDto> result = userRepository.findWithCTE(PageRequest.of(0, 1));
assertThat(result.getTotalElements()).isEqualTo(3);
}

@Test // GH-3076
void dynamicDtoProjection() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@
*/
package org.springframework.data.jpa.repository.query;

import org.junitpioneer.jupiter.SetSystemProperty;
import org.springframework.test.context.ContextConfiguration;

/**
* @author Christoph Strobl
*/
@ContextConfiguration("classpath:eclipselink.xml")
@SetSystemProperty(key = "spring.jpa.query.validation.disbaled", value = "true")
class EclipseLinkJpa21UtilsTests extends Jpa21UtilsTests {}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junitpioneer.jupiter.SetSystemProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand Down Expand Up @@ -69,6 +70,7 @@
@ExtendWith(SpringExtension.class)
@ContextConfiguration
@Transactional
@SetSystemProperty(key = "spring.jpa.query.validation.disbaled", value = "true")
class EclipseLinkMetaAnnotatedQueryMethodIntegrationTests {

@Autowired RoleRepositoryWithMeta repository;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ WITH maxId AS(select max(sr.snapshot.id) snapshotId from SnapshotReference sr
""");

assertThat(countQuery).startsWith("WITH maxId AS (select max(sr.snapshot.id) snapshotId from SnapshotReference sr")
.endsWith("select count(m) from maxId m join SnapshotReference sr on sr.snapshot.id = m.snapshotId");
.endsWith("select count(*) from maxId m join SnapshotReference sr on sr.snapshot.id = m.snapshotId");
}

@Test // GH-3504
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright 2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.jpa.repository.sample;

/**
* Hibernate is still a bit picky on records so let's use a class, just in case.
*
* @author Christoph Strobl
*/
public class UserExcerptDto {

private String firstname;
private String lastname;

public UserExcerptDto(String firstname, String lastname) {
this.firstname = firstname;
this.lastname = lastname;
}

public String getFirstname() {
return firstname;
}

public void setFirstname(String firstname) {
this.firstname = firstname;
}

public String getLastname() {
return lastname;
}

public void setLastname(String lastname) {
this.lastname = lastname;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,25 @@ List<String> findAllAndSortByFunctionResultNamedParameter(@Param("namedParameter
@Query("select u.firstname, u.lastname from User u")
List<UserExcerpt> findMultiselectRecordProjection();

/*
WITH entities AS (
SELECT
e.id as id,
e.number as number
FROM TestEntity e
)
SELECT new com.example.demo.Result('X', c.id, c.number)
FROM entities c
""")
*/

@Query("""
WITH cte_select AS (select u.firstname as firstname, u.lastname as lastname from User u)
SELECT new org.springframework.data.jpa.repository.sample.UserExcerptDto(c.firstname, c.lastname)
FROM cte_select c
""")
Page<UserExcerptDto> findWithCTE(Pageable page);

@UserRoleCountProjectingQuery
List<UserRoleCountDtoProjection> dtoProjectionEntityAndAggregatedValue();

Expand Down
Loading