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:
parent
95de10caf0
commit
1286804335
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue