HHH-817 : Projection aliases should not be applied to where-clause (Milosz Tylenda)

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@20282 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Gail Badner 2010-08-31 00:18:55 +00:00
parent b4ac7275e5
commit 19e9a408c2
11 changed files with 91 additions and 13 deletions

View File

@ -50,7 +50,7 @@ public class BetweenExpression implements Criterion {
throws HibernateException {
return StringHelper.join(
" and ",
StringHelper.suffix( criteriaQuery.getColumnsUsingProjection(criteria, propertyName), " between ? and ?" )
StringHelper.suffix( criteriaQuery.findColumns(propertyName, criteria), " between ? and ?" )
);
//TODO: get SQL rendering out of this package!

View File

@ -56,6 +56,14 @@ public interface CriteriaQuery {
public String[] getColumns(String propertyPath, Criteria criteria)
throws HibernateException;
/**
* Get the names of the columns mapped by a property path; if the
* property path is not found in criteria, try the "outer" query.
* Projection aliases are ignored.
*/
public String[] findColumns(String propertyPath, Criteria criteria)
throws HibernateException;
/**
* Get the type of a property path, ignoring projection aliases
*/
@ -67,7 +75,7 @@ public interface CriteriaQuery {
*/
public String[] getColumnsUsingProjection(Criteria criteria, String propertyPath)
throws HibernateException;
/**
* Get the type of a property path
*/

View File

@ -52,7 +52,7 @@ public class IlikeExpression implements Criterion {
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
Dialect dialect = criteriaQuery.getFactory().getDialect();
String[] columns = criteriaQuery.getColumnsUsingProjection(criteria, propertyName);
String[] columns = criteriaQuery.findColumns(propertyName, criteria);
if (columns.length!=1) throw new HibernateException("ilike may only be used with single-column properties");
if ( dialect instanceof PostgreSQLDialect ) {
return columns[0] + " ilike ?";

View File

@ -49,8 +49,7 @@ public class InExpression implements Criterion {
public String toSqlString( Criteria criteria, CriteriaQuery criteriaQuery )
throws HibernateException {
String[] columns = criteriaQuery.getColumnsUsingProjection(
criteria, propertyName );
String[] columns = criteriaQuery.findColumns(propertyName, criteria);
if ( criteriaQuery.getFactory().getDialect()
.supportsRowValueConstructorSyntaxInInList() || columns.length<=1) {

View File

@ -78,7 +78,7 @@ public class LikeExpression implements Criterion {
Criteria criteria,
CriteriaQuery criteriaQuery) throws HibernateException {
Dialect dialect = criteriaQuery.getFactory().getDialect();
String[] columns = criteriaQuery.getColumnsUsingProjection( criteria, propertyName );
String[] columns = criteriaQuery.findColumns(propertyName, criteria);
if ( columns.length != 1 ) {
throw new HibernateException( "Like may only be used with single-column properties" );
}

View File

@ -46,7 +46,7 @@ public class NotNullExpression implements Criterion {
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
String[] columns = criteriaQuery.getColumnsUsingProjection(criteria, propertyName);
String[] columns = criteriaQuery.findColumns(propertyName, criteria);
String result = StringHelper.join(
" or ",
StringHelper.suffix( columns, " is not null" )

View File

@ -46,7 +46,7 @@ public class NullExpression implements Criterion {
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
String[] columns = criteriaQuery.getColumnsUsingProjection(criteria, propertyName);
String[] columns = criteriaQuery.findColumns(propertyName, criteria);
String result = StringHelper.join(
" and ",
StringHelper.suffix( columns, " is null" )

View File

@ -49,8 +49,8 @@ public class PropertyExpression implements Criterion {
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
String[] xcols = criteriaQuery.getColumnsUsingProjection(criteria, propertyName);
String[] ycols = criteriaQuery.getColumnsUsingProjection(criteria, otherPropertyName);
String[] xcols = criteriaQuery.findColumns(propertyName, criteria);
String[] ycols = criteriaQuery.findColumns(otherPropertyName, criteria);
String result = StringHelper.join(
" and ",
StringHelper.add(xcols, getOp(), ycols)

View File

@ -65,7 +65,7 @@ public class SimpleExpression implements Criterion {
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
String[] columns = criteriaQuery.getColumnsUsingProjection(criteria, propertyName);
String[] columns = criteriaQuery.findColumns(propertyName, criteria);
Type type = criteriaQuery.getTypeUsingProjection(criteria, propertyName);
StringBuffer fragment = new StringBuffer();
if (columns.length>1) fragment.append('(');

View File

@ -487,6 +487,27 @@ public class CriteriaQueryTranslator implements CriteriaQuery {
);
}
/**
* Get the names of the columns mapped by a property path; if the
* property path is not found in subcriteria, try the "outer" query.
* Projection aliases are ignored.
*/
public String[] findColumns(String propertyName, Criteria subcriteria )
throws HibernateException {
try {
return getColumns( propertyName, subcriteria );
}
catch ( HibernateException he ) {
//not found in inner query, try the outer query
if ( outerQueryTranslator != null ) {
return outerQueryTranslator.findColumns( propertyName, subcriteria );
}
else {
throw he;
}
}
}
public Type getTypeUsingProjection(Criteria subcriteria, String propertyName)
throws HibernateException {

View File

@ -182,6 +182,17 @@ public class CriteriaQueryTest extends FunctionalTestCase {
.add( Subqueries.eq("Gavin King", dc3) )
.list();
DetachedCriteria dc4 = DetachedCriteria.forClass(Student.class, "st")
.setProjection( Property.forName("name").as( "stname" ) );
dc4.getExecutableCriteria( session ).list();
dc4.getExecutableCriteria( session ).addOrder( Order.asc( "stname" ) ).list();
session.createCriteria(Enrolment.class, "e")
.add( Subqueries.eq("Gavin King", dc4) )
.list();
session.delete(enrolment2);
session.delete(gavin);
session.delete(course);
@ -539,7 +550,7 @@ public class CriteriaQueryTest extends FunctionalTestCase {
assertEquals(new Long(667),result[1]);
assertEquals(new Long(101),result[2]);
assertEquals( 384.0, ( (Double) result[3] ).doubleValue(), 0.01 );
List resultWithMaps = s.createCriteria(Enrolment.class)
.setProjection( Projections.distinct( Projections.projectionList()
@ -740,6 +751,17 @@ public class CriteriaQueryTest extends FunctionalTestCase {
}
}
resultList = s.createCriteria(Student.class)
.add(Restrictions.eq("name", "Gavin King"))
.setProjection( Projections.projectionList()
.add( Projections.id().as( "studentNumber" ))
.add( Property.forName( "name" ), "name" )
.add( Property.forName( "cityState" ), "cityState" )
.add( Property.forName("preferredCourse"), "preferredCourse" )
)
.list();
assertEquals( 1, resultList.size() );
Object[] aResult = ( Object[] ) s.createCriteria(Student.class)
.add( Restrictions.idEq( new Long( 667 ) ) )
.setProjection( Projections.projectionList()
@ -895,9 +917,37 @@ public class CriteriaQueryTest extends FunctionalTestCase {
.add( Property.forName("year").group() )
)
.list();
assertEquals( list.size(), 2 );
list = s.createCriteria(Enrolment.class)
.createAlias("student", "st")
.createAlias("course", "co")
.setProjection( Projections.projectionList()
.add( Property.forName("co.courseCode").group().as( "courseCode" ))
.add( Property.forName("st.studentNumber").count().setDistinct().as( "studentNumber" ))
.add( Property.forName("year").group())
)
.addOrder( Order.asc( "courseCode" ) )
.addOrder( Order.asc( "studentNumber" ) )
.list();
assertEquals( list.size(), 2 );
list = s.createCriteria(Enrolment.class)
.createAlias("student", "st")
.createAlias("course", "co")
.setProjection( Projections.projectionList()
.add( Property.forName("co.courseCode").group().as( "cCode" ))
.add( Property.forName("st.studentNumber").count().setDistinct().as( "stNumber" ))
.add( Property.forName("year").group())
)
.addOrder( Order.asc( "cCode" ) )
.addOrder( Order.asc( "stNumber" ) )
.list();
assertEquals( list.size(), 2 );
s.delete(gavin);
s.delete(xam);
s.delete(course);