Skip to content

Commit 9a219c2

Browse files
committed
HHH-18850 fix count queries with 'distinct' and 'order by'
1 parent 7cdab31 commit 9a219c2

File tree

5 files changed

+69
-32
lines changed

5 files changed

+69
-32
lines changed

hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmOrderByClause.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66

77
import java.io.Serializable;
88
import java.util.ArrayList;
9-
import java.util.Collections;
109
import java.util.List;
1110

1211
import org.hibernate.query.sqm.tree.SqmCopyContext;
1312
import org.hibernate.query.sqm.tree.expression.SqmAliasedNodeRef;
1413
import org.hibernate.query.sqm.tree.expression.SqmExpression;
1514

15+
import static java.util.Collections.emptyList;
16+
import static java.util.Collections.unmodifiableList;
17+
1618
/**
1719
* @author Steve Ebersole
1820
*/
@@ -69,12 +71,7 @@ public SqmOrderByClause addSortSpecification(SqmExpression<?> expression) {
6971
}
7072

7173
public List<SqmSortSpecification> getSortSpecifications() {
72-
if ( sortSpecifications == null ) {
73-
return Collections.emptyList();
74-
}
75-
else {
76-
return Collections.unmodifiableList( sortSpecifications );
77-
}
74+
return sortSpecifications == null ? emptyList() : unmodifiableList( sortSpecifications );
7875
}
7976

8077
public void setSortSpecifications(List<SqmSortSpecification> sortSpecifications) {

hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQueryPart.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
*/
55
package org.hibernate.query.sqm.tree.select;
66

7-
import java.util.Collections;
87
import java.util.List;
98

109
import org.hibernate.query.common.FetchClauseType;
@@ -16,6 +15,8 @@
1615
import org.hibernate.query.sqm.tree.SqmVisitableNode;
1716
import org.hibernate.query.sqm.tree.expression.SqmExpression;
1817

18+
import static java.util.Collections.emptyList;
19+
1920
/**
2021
* Defines the ordering and fetch/offset part of a query which is shared with query groups.
2122
*
@@ -127,11 +128,7 @@ public FetchClauseType getFetchClauseType() {
127128

128129
@Override
129130
public List<SqmSortSpecification> getSortSpecifications() {
130-
if ( getOrderByClause() == null ) {
131-
return Collections.emptyList();
132-
}
133-
134-
return getOrderByClause().getSortSpecifications();
131+
return getOrderByClause() == null ? emptyList() : getOrderByClause().getSortSpecifications();
135132
}
136133

137134
@Override

hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSelectStatement.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,9 @@ public SqmSelectStatement<Long> createCountQuery() {
549549
final SqmSelectStatement<Long> query = nodeBuilder().createQuery( Long.class );
550550
query.from( subquery );
551551
query.select( nodeBuilder().count() );
552+
if ( subquery.getFetch() == null && subquery.getOffset() == null ) {
553+
subquery.getQueryPart().setOrderByClause( null );
554+
}
552555
return query;
553556
}
554557
}
Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
/*
2-
* Hibernate, Relational Persistence for Idiomatic Java
3-
*
4-
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5-
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
2+
* SPDX-License-Identifier: LGPL-2.1-or-later
3+
* Copyright Red Hat Inc. and Hibernate Authors
64
*/
75
package org.hibernate.orm.test.id.idClass;
86

@@ -16,23 +14,23 @@
1614
import static org.assertj.core.api.Assertions.assertThat;
1715

1816
@DomainModel(
19-
annotatedClasses = MyEntity.class
17+
annotatedClasses = MyEntity.class
2018
)
2119
@SessionFactory
2220
public class IdClassSyntheticAttributesTest {
2321

24-
@Jira("https://hibernate.atlassian.net/browse/HHH-18841")
25-
@Test
26-
public void test(DomainModelScope scope) {
27-
final PersistentClass entityBinding = scope.getDomainModel().getEntityBinding(MyEntity.class.getName());
28-
assertThat(entityBinding.getProperties()).hasSize(2)
29-
.anySatisfy(p -> {
30-
assertThat(p.isSynthetic()).isTrue();
31-
assertThat(p.getName()).isEqualTo("_identifierMapper");
32-
})
33-
.anySatisfy(p -> {
34-
assertThat(p.isSynthetic()).isFalse();
35-
assertThat(p.getName()).isEqualTo("notes");
36-
});
37-
}
22+
@Jira("https://hibernate.atlassian.net/browse/HHH-18841")
23+
@Test
24+
public void test(DomainModelScope scope) {
25+
final PersistentClass entityBinding = scope.getDomainModel().getEntityBinding(MyEntity.class.getName());
26+
assertThat(entityBinding.getProperties()).hasSize(2)
27+
.anySatisfy(p -> {
28+
assertThat(p.isSynthetic()).isTrue();
29+
assertThat(p.getName()).isEqualTo("_identifierMapper");
30+
})
31+
.anySatisfy(p -> {
32+
assertThat(p.isSynthetic()).isFalse();
33+
assertThat(p.getName()).isEqualTo("notes");
34+
});
35+
}
3836
}

hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/CountQueryTests.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,48 @@ public void testForHHH17967(SessionFactoryScope scope) {
8484
);
8585
}
8686

87+
@Test
88+
@JiraKey( "HHH-18850" )
89+
public void testForHHH18850(SessionFactoryScope scope) {
90+
scope.inTransaction(
91+
session -> {
92+
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
93+
JpaCriteriaQuery<Contract> cq = cb.createQuery( Contract.class );
94+
cq.distinct( true );
95+
Root<Contract> root = cq.from( Contract.class );
96+
cq.select( root );
97+
cq.orderBy( cb.asc( root.get( "customerName" ) ) );
98+
TypedQuery<Long> query = session.createQuery( cq.createCountQuery() );
99+
try {
100+
// Leads to NPE on pre-6.5 versions
101+
query.getSingleResult();
102+
}
103+
catch (Exception e) {
104+
fail( e );
105+
}
106+
}
107+
);
108+
109+
scope.inTransaction(
110+
session -> {
111+
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
112+
JpaCriteriaQuery<Contract> cq = cb.createQuery( Contract.class );
113+
cq.distinct( false );
114+
Root<Contract> root = cq.from( Contract.class );
115+
cq.select( root );
116+
cq.orderBy( cb.desc( root.get( "customerName" ) ) );
117+
TypedQuery<Long> query = session.createQuery( cq.createCountQuery() );
118+
try {
119+
// Leads to NPE on pre-6.5 versions
120+
query.getSingleResult();
121+
}
122+
catch (Exception e) {
123+
fail( e );
124+
}
125+
}
126+
);
127+
}
128+
87129
@Test
88130
@JiraKey("HHH-17410")
89131
public void testBasic(SessionFactoryScope scope) {

0 commit comments

Comments
 (0)