From 19e9a408c286e4872329273974cf9052aae767fe Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Tue, 31 Aug 2010 00:18:55 +0000 Subject: [PATCH] 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 --- .../criterion/BetweenExpression.java | 2 +- .../hibernate/criterion/CriteriaQuery.java | 10 +++- .../hibernate/criterion/IlikeExpression.java | 2 +- .../org/hibernate/criterion/InExpression.java | 3 +- .../hibernate/criterion/LikeExpression.java | 2 +- .../criterion/NotNullExpression.java | 2 +- .../hibernate/criterion/NullExpression.java | 2 +- .../criterion/PropertyExpression.java | 4 +- .../hibernate/criterion/SimpleExpression.java | 2 +- .../criteria/CriteriaQueryTranslator.java | 21 ++++++++ .../test/criteria/CriteriaQueryTest.java | 54 ++++++++++++++++++- 11 files changed, 91 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/org/hibernate/criterion/BetweenExpression.java b/core/src/main/java/org/hibernate/criterion/BetweenExpression.java index ac2028b485..337bdc0bc4 100644 --- a/core/src/main/java/org/hibernate/criterion/BetweenExpression.java +++ b/core/src/main/java/org/hibernate/criterion/BetweenExpression.java @@ -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! diff --git a/core/src/main/java/org/hibernate/criterion/CriteriaQuery.java b/core/src/main/java/org/hibernate/criterion/CriteriaQuery.java index 7d8043d45d..9482688e88 100755 --- a/core/src/main/java/org/hibernate/criterion/CriteriaQuery.java +++ b/core/src/main/java/org/hibernate/criterion/CriteriaQuery.java @@ -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 */ diff --git a/core/src/main/java/org/hibernate/criterion/IlikeExpression.java b/core/src/main/java/org/hibernate/criterion/IlikeExpression.java index 1b1b21aae9..72df93ac4b 100644 --- a/core/src/main/java/org/hibernate/criterion/IlikeExpression.java +++ b/core/src/main/java/org/hibernate/criterion/IlikeExpression.java @@ -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 ?"; diff --git a/core/src/main/java/org/hibernate/criterion/InExpression.java b/core/src/main/java/org/hibernate/criterion/InExpression.java index 04ad9cce2e..492b3a788a 100644 --- a/core/src/main/java/org/hibernate/criterion/InExpression.java +++ b/core/src/main/java/org/hibernate/criterion/InExpression.java @@ -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) { diff --git a/core/src/main/java/org/hibernate/criterion/LikeExpression.java b/core/src/main/java/org/hibernate/criterion/LikeExpression.java index 1af7339b2e..2450e02cea 100644 --- a/core/src/main/java/org/hibernate/criterion/LikeExpression.java +++ b/core/src/main/java/org/hibernate/criterion/LikeExpression.java @@ -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" ); } diff --git a/core/src/main/java/org/hibernate/criterion/NotNullExpression.java b/core/src/main/java/org/hibernate/criterion/NotNullExpression.java index c23b5e6aa9..9f006d1451 100644 --- a/core/src/main/java/org/hibernate/criterion/NotNullExpression.java +++ b/core/src/main/java/org/hibernate/criterion/NotNullExpression.java @@ -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" ) diff --git a/core/src/main/java/org/hibernate/criterion/NullExpression.java b/core/src/main/java/org/hibernate/criterion/NullExpression.java index ffa472d1af..a26317ea7d 100644 --- a/core/src/main/java/org/hibernate/criterion/NullExpression.java +++ b/core/src/main/java/org/hibernate/criterion/NullExpression.java @@ -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" ) diff --git a/core/src/main/java/org/hibernate/criterion/PropertyExpression.java b/core/src/main/java/org/hibernate/criterion/PropertyExpression.java index d9de98f308..40f4b05459 100644 --- a/core/src/main/java/org/hibernate/criterion/PropertyExpression.java +++ b/core/src/main/java/org/hibernate/criterion/PropertyExpression.java @@ -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) diff --git a/core/src/main/java/org/hibernate/criterion/SimpleExpression.java b/core/src/main/java/org/hibernate/criterion/SimpleExpression.java index 2d72330f58..7d8950a78a 100644 --- a/core/src/main/java/org/hibernate/criterion/SimpleExpression.java +++ b/core/src/main/java/org/hibernate/criterion/SimpleExpression.java @@ -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('('); diff --git a/core/src/main/java/org/hibernate/loader/criteria/CriteriaQueryTranslator.java b/core/src/main/java/org/hibernate/loader/criteria/CriteriaQueryTranslator.java index 9dbfc7b336..bdcaad0d9a 100755 --- a/core/src/main/java/org/hibernate/loader/criteria/CriteriaQueryTranslator.java +++ b/core/src/main/java/org/hibernate/loader/criteria/CriteriaQueryTranslator.java @@ -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 { diff --git a/testsuite/src/test/java/org/hibernate/test/criteria/CriteriaQueryTest.java b/testsuite/src/test/java/org/hibernate/test/criteria/CriteriaQueryTest.java index 44eaee3c3e..3c37ea6bb8 100755 --- a/testsuite/src/test/java/org/hibernate/test/criteria/CriteriaQueryTest.java +++ b/testsuite/src/test/java/org/hibernate/test/criteria/CriteriaQueryTest.java @@ -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);