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:
parent
b4ac7275e5
commit
19e9a408c2
|
@ -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!
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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 ?";
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
|
|
@ -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" );
|
||||
}
|
||||
|
|
|
@ -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" )
|
||||
|
|
|
@ -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" )
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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('(');
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue