HHH-4957 HHH-3096 : Fix COUNT( DISTINCT ...) for single and multiple arguments

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@19319 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Gail Badner 2010-04-28 17:54:43 +00:00
parent 95de10caf0
commit 1286804335
3 changed files with 242 additions and 6 deletions

View File

@ -23,6 +23,14 @@
*/
package org.hibernate.criterion;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.QueryException;
/**
* A count
* @author Gavin King
@ -43,6 +51,18 @@ public class CountProjection extends AggregateProjection {
}
}
protected List buildFunctionParameterList(Criteria criteria, CriteriaQuery criteriaQuery) {
String cols[] = criteriaQuery.getColumns( propertyName, criteria );
return ( distinct ? buildCountDistinctParameterList( cols ) : Arrays.asList( cols ) );
}
private List buildCountDistinctParameterList(String[] cols) {
List params = new ArrayList( cols.length + 1 );
params.add( "distinct" );
params.addAll( Arrays.asList( cols ) );
return params;
}
public CountProjection setDistinct() {
distinct = true;
return this;

View File

@ -27,6 +27,8 @@ import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.Subqueries;
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.exception.SQLGrammarException;
import org.hibernate.junit.functional.FunctionalTestCase;
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
import org.hibernate.test.hql.Animal;
@ -515,6 +517,16 @@ public class CriteriaQueryTest extends FunctionalTestCase {
.uniqueResult();
assertEquals(count, new Long(2));
count = (Long) s.createCriteria(Enrolment.class)
.setProjection( Projections.countDistinct("studentNumber") )
.uniqueResult();
assertEquals(count, new Long(2));
count = (Long) s.createCriteria(Enrolment.class)
.setProjection( Projections.countDistinct("courseCode").as( "cnt" ) )
.uniqueResult();
assertEquals(count, new Long(1));
Object object = s.createCriteria(Enrolment.class)
.setProjection( Projections.projectionList()
.add( Projections.count("studentNumber") )
@ -955,6 +967,15 @@ public class CriteriaQueryTest extends FunctionalTestCase {
assertEquals( ( ( CityState ) result ).getCity(), "Odessa" );
assertEquals( ( ( CityState ) result ).getState(), "WA" );
result = s.createCriteria( Student.class )
.setProjection( Projections.count( "cityState.city" ) )
.uniqueResult();
assertEquals( 2, ( ( Long ) result ).longValue() );
result = s.createCriteria( Student.class )
.setProjection( Projections.countDistinct( "cityState.city" ) )
.uniqueResult();
assertEquals( 1, ( ( Long ) result ).longValue() );
t.commit();
s.close();
@ -964,15 +985,34 @@ public class CriteriaQueryTest extends FunctionalTestCase {
result = s.createCriteria( Student.class )
.setProjection( Projections.count( "cityState" ) )
.uniqueResult();
fail( "should have failed with QueryException" );
fail( "expected SQLGrammarException" );
}
catch ( QueryException ex ) {
//expected
catch ( SQLGrammarException ex ) {
// expected
}
finally {
t.rollback();
s.close();
}
s = openSession();
t = s.beginTransaction();
try {
result = s.createCriteria( Student.class )
.setProjection( Projections.countDistinct( "cityState" ) )
.uniqueResult();
assertEquals( 1, ( ( Long ) result ).longValue() );
}
catch ( SQLGrammarException ex ) {
// HSQLDB's cannot handle more than 1 argument in SELECT COUNT( DISTINCT ... ) )
if ( ! ( getDialect() instanceof HSQLDialect ) ) {
throw ex;
}
}
finally {
t.rollback();
s.close();
}
s.close();
s = openSession();
t = s.beginTransaction();
@ -1214,9 +1254,45 @@ public class CriteriaQueryTest extends FunctionalTestCase {
course.getCourseMeetings().add( new CourseMeeting( course, "Monday", 1, "1313 Mockingbird Lane" ) );
s.save(course);
s.flush();
s.clear();
List data = ( List ) s.createCriteria( CourseMeeting.class).setProjection( Projections.id() ).list();
t.rollback();
t.commit();
s.close();
s = openSession();
t = s.beginTransaction();
try {
s.createCriteria( CourseMeeting.class).setProjection( Projections.count( "id" ) ).list();
fail( "should have thrown SQLGrammarException" );
}
catch ( SQLGrammarException ex ) {
// expected
}
finally {
t.rollback();
s.close();
}
s = openSession();
t = s.beginTransaction();
try {
Object result = s.createCriteria( CourseMeeting.class).setProjection( Projections.countDistinct( "id" ) ).list();
}
catch ( SQLGrammarException ex ) {
// HSQLDB's cannot handle more than 1 argument in SELECT COUNT( DISTINCT ... ) )
if ( ! ( getDialect() instanceof HSQLDialect ) ) {
throw ex;
}
}
finally {
t.rollback();
s.close();
}
s = openSession();
t = s.beginTransaction();
s.delete( course );
t.commit();
s.close();
}

View File

@ -8,6 +8,10 @@ import java.util.Collections;
import junit.framework.Test;
import org.hibernate.Hibernate;
import org.hibernate.QueryException;
import org.hibernate.Transaction;
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.exception.SQLGrammarException;
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
import org.hibernate.classic.Session;
import org.hibernate.criterion.Projections;
@ -171,4 +175,140 @@ public class CriteriaHQLAlignmentTest extends QueryTranslatorTestCase {
s.close();
}
public void testCountReturnValues() {
Session s = openSession();
Transaction t = s.beginTransaction();
Human human1 = new Human();
human1.setName( new Name( "John", 'Q', "Public" ) );
human1.setNickName( "Johnny" );
s.save(human1);
Human human2 = new Human();
human2.setName( new Name( "John", 'A', "Doe" ) );
human2.setNickName( "Johnny" );
s.save( human2 );
Human human3 = new Human();
human3.setName( new Name( "John", 'A', "Doe" ) );
human3.setNickName( "Jack" );
s.save( human3 );
Human human4 = new Human();
human4.setName( new Name( "John", 'A', "Doe" ) );
s.save( human4 );
t.commit();
s.close();
s = openSession();
t = s.beginTransaction();
Long count = ( Long ) s.createQuery( "select count( * ) from Human" ).uniqueResult();
assertEquals( 4, count.longValue() );
s.clear();
count = ( Long ) s.createCriteria( Human.class )
.setProjection( Projections.rowCount() )
.uniqueResult();
assertEquals( 4, count.longValue() );
s.clear();
count = ( Long ) s.createQuery( "select count( nickName ) from Human" ).uniqueResult();
assertEquals( 3, count.longValue() );
s.clear();
count = ( Long ) s.createCriteria( Human.class )
.setProjection( Projections.count( "nickName" ) )
.uniqueResult();
assertEquals( 3, count.longValue() );
s.clear();
count = ( Long ) s.createQuery( "select count( distinct nickName ) from Human" ).uniqueResult();
assertEquals( 2, count.longValue() );
s.clear();
count = ( Long ) s.createCriteria( Human.class )
.setProjection( Projections.count( "nickName" ).setDistinct() )
.uniqueResult();
assertEquals( 2, count.longValue() );
s.clear();
s = openSession();
t = s.beginTransaction();
try {
count = ( Long ) s.createQuery( "select count( distinct name ) from Human" ).uniqueResult();
assertEquals( 2, count.longValue() );
}
catch ( SQLGrammarException ex ) {
// HSQLDB's cannot handle more than 1 argument in SELECT COUNT( DISTINCT ... ) )
if ( ! ( getDialect() instanceof HSQLDialect ) ) {
throw ex;
}
}
finally {
t.rollback();
s.close();
}
s = openSession();
t = s.beginTransaction();
try {
count = ( Long ) s.createCriteria( Human.class )
.setProjection( Projections.count( "name" ).setDistinct() )
.uniqueResult();
assertEquals( 2, count.longValue() );
}
catch ( SQLGrammarException ex ) {
// HSQLDB's cannot handle more than 1 argument in SELECT COUNT( DISTINCT ... ) )
if ( ! ( getDialect() instanceof HSQLDialect ) ) {
throw ex;
}
}
finally {
t.rollback();
s.close();
}
s = openSession();
t = s.beginTransaction();
count = ( Long ) s.createQuery( "select count( distinct name.first ) from Human" ).uniqueResult();
assertEquals( 1, count.longValue() );
s.clear();
count = ( Long ) s.createCriteria( Human.class )
.setProjection( Projections.count( "name.first" ).setDistinct() )
.uniqueResult();
assertEquals( 1, count.longValue() );
t.commit();
s.close();
s = openSession();
t = s.beginTransaction();
try {
count = ( Long ) s.createQuery( "select count( name ) from Human" ).uniqueResult();
fail( "should have failed due to SQLGrammarException" );
}
catch ( SQLGrammarException ex ) {
// expected
}
finally {
t.rollback();
s.close();
}
s = openSession();
t = s.beginTransaction();
try {
count = ( Long ) s.createCriteria( Human.class )
.setProjection( Projections.count( "name" ) )
.uniqueResult();
fail( "should have failed due to SQLGrammarException" );
}
catch ( SQLGrammarException ex ) {
// expected
}
finally {
t.rollback();
s.close();
}
s = openSession();
t = s.beginTransaction();
s.createQuery( "delete from Human" ).executeUpdate();
t.commit();
s.close();
}
}