HHH-18850 fix count queries with 'distinct' and 'order by'

This commit is contained in:
Gavin King 2024-11-15 15:04:24 +01:00
parent 7cdab319fb
commit 9a219c2c30
5 changed files with 69 additions and 32 deletions

View File

@ -6,13 +6,15 @@ package org.hibernate.query.sqm.tree.select;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.expression.SqmAliasedNodeRef; import org.hibernate.query.sqm.tree.expression.SqmAliasedNodeRef;
import org.hibernate.query.sqm.tree.expression.SqmExpression; import org.hibernate.query.sqm.tree.expression.SqmExpression;
import static java.util.Collections.emptyList;
import static java.util.Collections.unmodifiableList;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@ -69,12 +71,7 @@ public class SqmOrderByClause implements Serializable {
} }
public List<SqmSortSpecification> getSortSpecifications() { public List<SqmSortSpecification> getSortSpecifications() {
if ( sortSpecifications == null ) { return sortSpecifications == null ? emptyList() : unmodifiableList( sortSpecifications );
return Collections.emptyList();
}
else {
return Collections.unmodifiableList( sortSpecifications );
}
} }
public void setSortSpecifications(List<SqmSortSpecification> sortSpecifications) { public void setSortSpecifications(List<SqmSortSpecification> sortSpecifications) {

View File

@ -4,7 +4,6 @@
*/ */
package org.hibernate.query.sqm.tree.select; package org.hibernate.query.sqm.tree.select;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.hibernate.query.common.FetchClauseType; import org.hibernate.query.common.FetchClauseType;
@ -16,6 +15,8 @@ import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmVisitableNode; import org.hibernate.query.sqm.tree.SqmVisitableNode;
import org.hibernate.query.sqm.tree.expression.SqmExpression; import org.hibernate.query.sqm.tree.expression.SqmExpression;
import static java.util.Collections.emptyList;
/** /**
* Defines the ordering and fetch/offset part of a query which is shared with query groups. * Defines the ordering and fetch/offset part of a query which is shared with query groups.
* *
@ -127,11 +128,7 @@ public abstract class SqmQueryPart<T> implements SqmVisitableNode, JpaQueryPart<
@Override @Override
public List<SqmSortSpecification> getSortSpecifications() { public List<SqmSortSpecification> getSortSpecifications() {
if ( getOrderByClause() == null ) { return getOrderByClause() == null ? emptyList() : getOrderByClause().getSortSpecifications();
return Collections.emptyList();
}
return getOrderByClause().getSortSpecifications();
} }
@Override @Override

View File

@ -549,6 +549,9 @@ public class SqmSelectStatement<T> extends AbstractSqmSelectQuery<T> implements
final SqmSelectStatement<Long> query = nodeBuilder().createQuery( Long.class ); final SqmSelectStatement<Long> query = nodeBuilder().createQuery( Long.class );
query.from( subquery ); query.from( subquery );
query.select( nodeBuilder().count() ); query.select( nodeBuilder().count() );
if ( subquery.getFetch() == null && subquery.getOffset() == null ) {
subquery.getQueryPart().setOrderByClause( null );
}
return query; return query;
} }
} }

View File

@ -1,8 +1,6 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * SPDX-License-Identifier: LGPL-2.1-or-later
* * Copyright Red Hat Inc. and Hibernate Authors
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/ */
package org.hibernate.orm.test.id.idClass; package org.hibernate.orm.test.id.idClass;

View File

@ -84,6 +84,48 @@ public class CountQueryTests {
); );
} }
@Test
@JiraKey( "HHH-18850" )
public void testForHHH18850(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
JpaCriteriaQuery<Contract> cq = cb.createQuery( Contract.class );
cq.distinct( true );
Root<Contract> root = cq.from( Contract.class );
cq.select( root );
cq.orderBy( cb.asc( root.get( "customerName" ) ) );
TypedQuery<Long> query = session.createQuery( cq.createCountQuery() );
try {
// Leads to NPE on pre-6.5 versions
query.getSingleResult();
}
catch (Exception e) {
fail( e );
}
}
);
scope.inTransaction(
session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
JpaCriteriaQuery<Contract> cq = cb.createQuery( Contract.class );
cq.distinct( false );
Root<Contract> root = cq.from( Contract.class );
cq.select( root );
cq.orderBy( cb.desc( root.get( "customerName" ) ) );
TypedQuery<Long> query = session.createQuery( cq.createCountQuery() );
try {
// Leads to NPE on pre-6.5 versions
query.getSingleResult();
}
catch (Exception e) {
fail( e );
}
}
);
}
@Test @Test
@JiraKey("HHH-17410") @JiraKey("HHH-17410")
public void testBasic(SessionFactoryScope scope) { public void testBasic(SessionFactoryScope scope) {