HHH-892 : HQL parser does not resolve alias in ORDER BY clause

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@20673 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Gail Badner 2010-09-20 17:42:39 +00:00
parent dde16433ad
commit 13699d792b
19 changed files with 572 additions and 27 deletions

View File

@ -50,6 +50,8 @@ tokens
METHOD_NAME; // An IDENT that is a method name.
NAMED_PARAM; // A named parameter (:foo).
BOGUS; // Used for error state detection, etc.
RESULT_VARIABLE_REF; // An IDENT that refers to result variable
// (i.e, an alias for a select expression)
}
// -- Declarations --
@ -211,7 +213,14 @@ tokens
protected void lookupAlias(AST ident) throws SemanticException { }
protected void setAlias(AST selectExpr, AST ident) { }
protected void setAlias(AST selectExpr, AST ident) { }
protected boolean isOrderExpressionResultVariableRef(AST ident) throws SemanticException {
return false;
}
protected void handleResultVariableRef(AST resultVariableRef) throws SemanticException {
}
protected AST lookupProperty(AST dot,boolean root,boolean inSelect) throws SemanticException {
return dot;
@ -334,7 +343,20 @@ orderClause
;
orderExprs
: expr ( ASCENDING | DESCENDING )? (orderExprs)?
: orderExpr ( ASCENDING | DESCENDING )? (orderExprs)?
;
orderExpr
: { isOrderExpressionResultVariableRef( _t ) }? resultVariableRef
| expr
;
resultVariableRef!
: i:identifier {
// Create a RESULT_VARIABLE_REF node instead of an IDENT node.
#resultVariableRef = #([RESULT_VARIABLE_REF, i.getText()]);
handleResultVariableRef(#resultVariableRef);
}
;
groupClause
@ -358,7 +380,7 @@ selectExprList {
aliasedSelectExpr!
: #(AS se:selectExpr i:identifier) {
setAlias(#se,#i);
setAlias(#se,#i);
#aliasedSelectExpr = #se;
}
;
@ -723,4 +745,4 @@ parameter!
numericInteger
: NUM_INT
;
;

View File

@ -432,6 +432,7 @@ addrExpr
: #(r:DOT . .) { out(r); }
| i:ALIAS_REF { out(i); }
| j:INDEX_OP { out(j); }
| v:RESULT_VARIABLE_REF { out(v); }
;
sqlToken

View File

@ -1723,6 +1723,20 @@ public abstract class Dialect {
return true;
}
/**
* Does this dialect require that references to result variables
* (i.e, select expresssion aliases) in an ORDER BY clause be
* replaced by column positions (1-origin) as defined
* by the select clause?
* @return true if result variable references in the ORDER BY
* clause should be replaced by column positions;
* false otherwise.
*/
public boolean replaceResultVariableInOrderByClauseWithPosition() {
return false;
}
/**
* Does this dialect require that parameters appearing in the <tt>SELECT</tt> clause be wrapped in <tt>cast()</tt>
* calls to tell the db parser the expected type.

View File

@ -66,6 +66,7 @@ import org.hibernate.hql.ast.tree.ParameterNode;
import org.hibernate.hql.ast.tree.QueryNode;
import org.hibernate.hql.ast.tree.ResolvableNode;
import org.hibernate.hql.ast.tree.RestrictableStatement;
import org.hibernate.hql.ast.tree.ResultVariableRefNode;
import org.hibernate.hql.ast.tree.SelectClause;
import org.hibernate.hql.ast.tree.SelectExpression;
import org.hibernate.hql.ast.tree.UpdateStatement;
@ -132,6 +133,12 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
private FromClause currentFromClause = null;
private SelectClause selectClause;
/**
* Maps each top-level result variable to its SelectExpression;
* (excludes result variables defined in subqueries)
**/
private Map<String, SelectExpression> selectExpressionsByResultVariable = new HashMap();
private Set querySpaces = new HashSet();
private int parameterCount;
@ -991,8 +998,35 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
protected void setAlias(AST selectExpr, AST ident) {
((SelectExpression) selectExpr).setAlias(ident.getText());
// only put the alias (i.e., result variable) in selectExpressionsByResultVariable
// if is not defined in a subquery.
if ( ! isSubQuery() ) {
selectExpressionsByResultVariable.put( ident.getText(), ( SelectExpression ) selectExpr );
}
}
protected boolean isOrderExpressionResultVariableRef(AST orderExpressionNode) throws SemanticException {
// ORDER BY is not supported in a subquery
// TODO: should an exception be thrown if an ORDER BY is in a subquery?
if ( ! isSubQuery() &&
orderExpressionNode.getType() == IDENT &&
selectExpressionsByResultVariable.containsKey( orderExpressionNode.getText() ) ) {
return true;
}
return false;
}
protected void handleResultVariableRef(AST resultVariableRef) throws SemanticException {
if ( isSubQuery() ) {
throw new SemanticException(
"References to result variables in subqueries are not supported."
);
}
( ( ResultVariableRefNode ) resultVariableRef ).setSelectExpression(
selectExpressionsByResultVariable.get( resultVariableRef.getText() )
);
}
/**
* Returns the locations of all occurrences of the named parameter.
*/

View File

@ -51,6 +51,7 @@ import org.hibernate.hql.ast.tree.MethodNode;
import org.hibernate.hql.ast.tree.OrderByClause;
import org.hibernate.hql.ast.tree.ParameterNode;
import org.hibernate.hql.ast.tree.QueryNode;
import org.hibernate.hql.ast.tree.ResultVariableRefNode;
import org.hibernate.hql.ast.tree.SelectClause;
import org.hibernate.hql.ast.tree.SelectExpressionImpl;
import org.hibernate.hql.ast.tree.SqlFragment;
@ -124,6 +125,8 @@ public class SqlASTFactory extends ASTFactory implements HqlSqlTokenTypes {
case ALIAS_REF:
case IDENT:
return IdentNode.class;
case RESULT_VARIABLE_REF:
return ResultVariableRefNode.class;
case SQL_TOKEN:
return SqlFragment.class;
case METHOD_CALL:

View File

@ -36,6 +36,7 @@ import antlr.SemanticException;
public abstract class AbstractSelectExpression extends HqlSqlWalkerNode implements SelectExpression {
private String alias;
private int scalarColumnIndex = -1;
public final void setAlias(String alias) {
this.alias = alias;
@ -63,4 +64,13 @@ public abstract class AbstractSelectExpression extends HqlSqlWalkerNode implemen
Type type = getDataType();
return type != null && !type.isAssociationType(); // Moved here from SelectClause [jsd]
}
public void setScalarColumn(int i) throws SemanticException {
this.scalarColumnIndex = i;
setScalarColumnText( i );
}
public int getScalarColumnIndex() {
return scalarColumnIndex;
}
}

View File

@ -51,6 +51,7 @@ public class ConstructorNode extends SelectExpressionList implements AggregatedS
private Type[] constructorArgumentTypes;
private boolean isMap;
private boolean isList;
private int scalarColumnIndex = -1;
public ResultTransformer getResultTransformer() {
if ( constructor != null ) {
@ -92,6 +93,19 @@ public class ConstructorNode extends SelectExpressionList implements AggregatedS
return aliases;
}
public void setScalarColumn(int i) throws SemanticException {
SelectExpression[] selectExpressions = collectSelectExpressions();
// Invoke setScalarColumnText on each constructor argument.
for ( int j = 0; j < selectExpressions.length; j++ ) {
SelectExpression selectExpression = selectExpressions[j];
selectExpression.setScalarColumn( j );
}
}
public int getScalarColumnIndex() {
return scalarColumnIndex;
}
public void setScalarColumnText(int i) throws SemanticException {
SelectExpression[] selectExpressions = collectSelectExpressions();
// Invoke setScalarColumnText on each constructor argument.

View File

@ -60,6 +60,8 @@ public class MapEntryNode extends AbstractMapComponentNode implements Aggregated
}
}
private int scalarColumnIndex = -1;
protected String expressionDescription() {
return "entry(*)";
}
@ -190,6 +192,14 @@ public class MapEntryNode extends AbstractMapComponentNode implements Aggregated
super.setText( s );
}
public void setScalarColumn(int i) throws SemanticException {
this.scalarColumnIndex = i;
}
public int getScalarColumnIndex() {
return scalarColumnIndex;
}
public void setScalarColumnText(int i) throws SemanticException {
}

View File

@ -46,6 +46,7 @@ public class QueryNode extends AbstractRestrictableStatement implements SelectEx
private static final Logger log = LoggerFactory.getLogger( QueryNode.class );
private OrderByClause orderByClause;
private int scalarColumnIndex = -1;
/**
* @see Statement#getStatementType()
@ -145,6 +146,15 @@ public class QueryNode extends AbstractRestrictableStatement implements SelectEx
this.alias = alias;
}
public void setScalarColumn(int i) throws SemanticException {
scalarColumnIndex = i;
setScalarColumnText( i );
}
public int getScalarColumnIndex() {
return scalarColumnIndex;
}
public void setScalarColumnText(int i) throws SemanticException {
ColumnHelper.generateSingleScalarColumn( this, i );
}

View File

@ -0,0 +1,93 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.hql.ast.tree;
import antlr.SemanticException;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.util.StringHelper;
/**
* Represents a reference to a result_variable as defined in the JPA 2 spec.
* For example:
* <code>
* select v as value from tab1 order by value
* </code>
* <p/>
* "value" used in the order by clause is a reference to the
* result_variable, "value", defined in the select clause.
*
* @author Gail Badner
*/
public class ResultVariableRefNode extends HqlSqlWalkerNode {
private SelectExpression selectExpression;
/**
* Set the select expression that defines the result variable.
*
* @param selectExpression the select expression;
* selectExpression.getAlias() must be non-null
* @throws SemanticException if selectExpression or
* selectExpression.getAlias() is null.
*/
public void setSelectExpression(SelectExpression selectExpression) throws SemanticException {
if ( selectExpression == null || selectExpression.getAlias() == null ) {
throw new SemanticException( "A ResultVariableRefNode must refer to a non-null alias." );
}
this.selectExpression = selectExpression;
}
/**
* {@inheritDoc}
*/
public String getRenderText(SessionFactoryImplementor sessionFactory) {
int scalarColumnIndex = selectExpression.getScalarColumnIndex();
if ( scalarColumnIndex < 0 ) {
throw new IllegalStateException(
"selectExpression.getScalarColumnIndex() must be >= 0; actual = " + scalarColumnIndex
);
}
return sessionFactory.getDialect().replaceResultVariableInOrderByClauseWithPosition() ?
getColumnPositionsString( scalarColumnIndex ) :
getColumnNamesString( scalarColumnIndex );
}
private String getColumnPositionsString(int scalarColumnIndex ) {
int startPosition = getWalker().getSelectClause().getColumnNamesStartPosition( scalarColumnIndex );
StringBuffer buf = new StringBuffer();
int nColumns = getWalker().getSelectClause().getColumnNames()[ scalarColumnIndex ].length;
for ( int i = startPosition; i < startPosition + nColumns; i++ ) {
if ( i > startPosition ) {
buf.append( ", " );
}
buf.append( i );
}
return buf.toString();
}
private String getColumnNamesString(int scalarColumnIndex) {
return StringHelper.join( ", ", getWalker().getSelectClause().getColumnNames()[ scalarColumnIndex ] );
}
}

View File

@ -25,6 +25,7 @@
package org.hibernate.hql.ast.tree;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@ -54,6 +55,7 @@ public class SelectClause extends SelectExpressionList {
private String[][] columnNames;
private List collectionFromElements;
private String[] aliases;
private int[] columnNamesStartPositions;
// Currently we can only have one...
private AggregatedSelectExpression aggregatedSelectExpression;
@ -253,6 +255,16 @@ public class SelectClause extends SelectExpressionList {
// todo: we should really just collect these from the various SelectExpressions, rather than regenerating here
columnNames = getSessionFactoryHelper().generateColumnNames( queryReturnTypes );
columnNamesStartPositions = new int[ columnNames.length ];
int startPosition = 1;
for ( int i = 0 ; i < columnNames.length ; i ++ ) {
columnNamesStartPositions[ i ] = startPosition;
startPosition += columnNames[ i ].length;
}
}
public int getColumnNamesStartPosition(int i) {
return columnNamesStartPositions[ i ];
}
/**
@ -356,7 +368,7 @@ public class SelectClause extends SelectExpressionList {
if ( !currentFromClause.isSubQuery() ) {
for ( int i = 0; i < se.length; i++ ) {
SelectExpression expr = se[i];
expr.setScalarColumnText( i ); // Create SQL_TOKEN nodes for the columns.
expr.setScalarColumn( i ); // Create SQL_TOKEN nodes for the columns.
}
}
}

View File

@ -49,6 +49,21 @@ public interface SelectExpression {
*/
void setScalarColumnText(int i) throws SemanticException;
/**
* Sets the index and text for select expression in the projection list.
*
* @param i The index of the select expression in the projection list.
* @throws SemanticException
*/
void setScalarColumn(int i) throws SemanticException;
/**
* Gets index of the select expression in the projection list.
*
* @returns The index of the select expression in the projection list.
*/
int getScalarColumnIndex();
/**
* Returns the FROM element that this expression refers to.
*

View File

@ -100,6 +100,10 @@ public class ASTParserLoadingOrderByTest extends FunctionalTestCase {
private Zoo zoo4;
Set<Zoo> zoosWithSameName;
Set<Zoo> zoosWithSameAddress;
Mammal zoo1Mammal1;
Mammal zoo1Mammal2;
Human zoo2Director1;
Human zoo2Director2;
public ASTParserLoadingOrderByTest(String name) {
super( name );
@ -138,6 +142,14 @@ public class ASTParserLoadingOrderByTest extends FunctionalTestCase {
address1.setStateProvince( stateProvince );
address1.setCountry( "USA" );
zoo1.setAddress( address1 );
zoo1Mammal1 = new Mammal();
zoo1Mammal1.setDescription( "zoo1Mammal1" );
zoo1Mammal1.setZoo( zoo1 );
zoo1.getMammals().put( "type1", zoo1Mammal1);
zoo1Mammal2 = new Mammal();
zoo1Mammal2.setDescription( "zoo1Mammal2" );
zoo1Mammal2.setZoo( zoo1 );
zoo1.getMammals().put( "type1", zoo1Mammal2);
zoo2 = new Zoo();
zoo2.setName( "A Zoo" );
@ -147,7 +159,12 @@ public class ASTParserLoadingOrderByTest extends FunctionalTestCase {
address2.setStateProvince( stateProvince );
address2.setCountry( "USA" );
zoo2.setAddress( address2 );
zoo2Director1 = new Human();
zoo2Director1.setName( new Name( "Duh", 'A', "Man" ) );
zoo2Director2 = new Human();
zoo2Director2.setName( new Name( "Fat", 'A', "Cat" ) );
zoo2.getDirectors().put( "Head Honcho", zoo2Director1 );
zoo2.getDirectors().put( "Asst. Head Honcho", zoo2Director2 );
zoo3 = new Zoo();
zoo3.setName( "Zoo" );
@ -170,7 +187,11 @@ public class ASTParserLoadingOrderByTest extends FunctionalTestCase {
Session s = openSession();
Transaction t = s.beginTransaction();
s.save( stateProvince );
s.save( zoo1Mammal1 );
s.save( zoo1Mammal2 );
s.save( zoo1 );
s.save( zoo2Director1 );
s.save( zoo2Director2 );
s.save( zoo2 );
s.save( zoo3 );
s.save( zoo4 );
@ -204,6 +225,25 @@ public class ASTParserLoadingOrderByTest extends FunctionalTestCase {
s.delete( zoo4 );
zoo4 = null;
}
if ( zoo1Mammal1 != null ) {
s.delete( zoo1Mammal1 );
zoo1Mammal1 = null;
}
if ( zoo1Mammal2 != null ) {
s.delete( zoo1Mammal2 );
zoo1Mammal2 = null;
}
if ( zoo2Director1 != null ) {
s.delete( zoo2Director1 );
zoo2Director1 = null;
}
if ( zoo2Director2 != null ) {
s.delete( zoo2Director2 );
zoo2Director2 = null;
}
if ( stateProvince != null ) {
s.delete( stateProvince );
}
t.commit();
s.close();
}
@ -346,7 +386,7 @@ public class ASTParserLoadingOrderByTest extends FunctionalTestCase {
cleanupData();
}
public void testOrderBySelectAliasRefFailureExpected() {
public void testOrderBySelectAliasRef() {
createData();
Session s = openSession();
@ -492,22 +532,6 @@ public class ASTParserLoadingOrderByTest extends FunctionalTestCase {
t.commit();
s.close();
s = openSession();
t = s.beginTransaction();
try {
s.createQuery(
"select z2.name as zname, z2.address as zooAddress from Zoo z2 where z2.name in ( select name as zname from Zoo order by zname ) order by zooAddress"
).list();
fail( "Exception should have been thrown because subquery has ORDER BY" );
}
catch ( QuerySyntaxException ex ) {
// expected
}
finally {
t.rollback();
s.close();
}
cleanupData();
}
@ -536,6 +560,143 @@ public class ASTParserLoadingOrderByTest extends FunctionalTestCase {
cleanupData();
}
public void testOrderByEntityWithFetchJoinedCollection() {
createData();
Session s = openSession();
Transaction t = s.beginTransaction();
// ordered by address desc, name desc:
// zoo3 Zoo 1312 Mockingbird Lane, Anywhere, IL USA
// zoo4 Duh Zoo 1312 Mockingbird Lane, Nowhere, IL USA
// zoo2 A Zoo 1313 Mockingbird Lane, Anywhere, IL USA
// zoo1 Zoo 1313 Mockingbird Lane, Anywhere, IL USA
// using DESC
List list = s.createQuery( "from Zoo z join fetch z.mammals" ).list();
t.commit();
s.close();
cleanupData();
}
public void testOrderBySelectNewArgAliasRef() {
createData();
Session s = openSession();
Transaction t = s.beginTransaction();
// ordered by name, address:
// zoo2 A Zoo 1313 Mockingbird Lane, Anywhere, IL USA
// zoo4 Duh Zoo 1312 Mockingbird Lane, Nowhere, IL USA
// zoo3 Zoo 1312 Mockingbird Lane, Anywhere, IL USA
// zoo1 Zoo 1313 Mockingbird Lane, Anywhere, IL USA
List list =
s.createQuery(
"select new Zoo( z.name as zname, z.address as zaddress) from Zoo z order by zname, zaddress"
).list();
assertEquals( 4, list.size() );
assertEquals( zoo2, list.get( 0 ) );
assertEquals( zoo4, list.get( 1 ) );
assertEquals( zoo3, list.get( 2 ) );
assertEquals( zoo1, list.get( 3 ) );
// ordered by address, name:
// zoo3 Zoo 1312 Mockingbird Lane, Anywhere, IL USA
// zoo4 Duh Zoo 1312 Mockingbird Lane, Nowhere, IL USA
// zoo2 A Zoo 1313 Mockingbird Lane, Anywhere, IL USA
// zoo1 Zoo 1313 Mockingbird Lane, Anywhere, IL USA
list =
s.createQuery(
"select new Zoo( z.name as zname, z.address as zaddress) from Zoo z order by zaddress, zname"
).list();
assertEquals( 4, list.size() );
assertEquals( zoo3, list.get( 0 ) );
assertEquals( zoo4, list.get( 1 ) );
assertEquals( zoo2, list.get( 2 ) );
assertEquals( zoo1, list.get( 3 ) );
t.commit();
s.close();
cleanupData();
}
public void testOrderBySelectNewMapArgAliasRef() {
createData();
Session s = openSession();
Transaction t = s.beginTransaction();
// ordered by name, address:
// zoo2 A Zoo 1313 Mockingbird Lane, Anywhere, IL USA
// zoo4 Duh Zoo 1312 Mockingbird Lane, Nowhere, IL USA
// zoo3 Zoo 1312 Mockingbird Lane, Anywhere, IL USA
// zoo1 Zoo 1313 Mockingbird Lane, Anywhere, IL USA
List list =
s.createQuery(
"select new map( z.name as zname, z.address as zaddress ) from Zoo z left join z.mammals m order by zname, zaddress"
).list();
assertEquals( 4, list.size() );
assertEquals( zoo2.getName(), ( ( Map ) list.get( 0 ) ).get( "zname" ) );
assertEquals( zoo2.getAddress(), ( ( Map ) list.get( 0 ) ).get( "zaddress" ) );
assertEquals( zoo4.getName(), ( ( Map ) list.get( 1 ) ).get( "zname" ) );
assertEquals( zoo4.getAddress(), ( ( Map ) list.get( 1 ) ).get( "zaddress" ) );
assertEquals( zoo3.getName(), ( ( Map ) list.get( 2 ) ).get( "zname" ) );
assertEquals( zoo3.getAddress(), ( ( Map ) list.get( 2 ) ).get( "zaddress" ) );
assertEquals( zoo1.getName(), ( ( Map ) list.get( 3 ) ).get( "zname" ) );
assertEquals( zoo1.getAddress(), ( ( Map ) list.get( 3 ) ).get( "zaddress" ) );
// ordered by address, name:
// zoo3 Zoo 1312 Mockingbird Lane, Anywhere, IL USA
// zoo4 Duh Zoo 1312 Mockingbird Lane, Nowhere, IL USA
// zoo2 A Zoo 1313 Mockingbird Lane, Anywhere, IL USA
// zoo1 Zoo 1313 Mockingbird Lane, Anywhere, IL USA
list =
s.createQuery(
"select new map( z.name as zname, z.address as zaddress ) from Zoo z left join z.mammals m order by zaddress, zname"
).list();
assertEquals( 4, list.size() );
assertEquals( zoo3.getName(), ( ( Map ) list.get( 0 ) ).get( "zname" ) );
assertEquals( zoo3.getAddress(), ( ( Map ) list.get( 0 ) ).get( "zaddress" ) );
assertEquals( zoo4.getName(), ( ( Map ) list.get( 1 ) ).get( "zname" ) );
assertEquals( zoo4.getAddress(), ( ( Map ) list.get( 1 ) ).get( "zaddress" ) );
assertEquals( zoo2.getName(), ( ( Map ) list.get( 2 ) ).get( "zname" ) );
assertEquals( zoo2.getAddress(), ( ( Map ) list.get( 2 ) ).get( "zaddress" ) );
assertEquals( zoo1.getName(), ( ( Map ) list.get( 3 ) ).get( "zname" ) );
assertEquals( zoo1.getAddress(), ( ( Map ) list.get( 3 ) ).get( "zaddress" ) );
t.commit();
s.close();
cleanupData();
}
public void testOrderByAggregatedArgAliasRef() {
createData();
Session s = openSession();
Transaction t = s.beginTransaction();
// ordered by name, address:
// zoo2 A Zoo 1313 Mockingbird Lane, Anywhere, IL USA
// zoo4 Duh Zoo 1312 Mockingbird Lane, Nowhere, IL USA
// zoo3 Zoo 1312 Mockingbird Lane, Anywhere, IL USA
// zoo1 Zoo 1313 Mockingbird Lane, Anywhere, IL USA
List list =
s.createQuery(
"select z.name as zname, count(*) as cnt from Zoo z group by z.name order by cnt desc, zname"
).list();
assertEquals( 3, list.size() );
assertEquals( zoo3.getName(), ( ( Object[] ) list.get( 0 ) )[ 0 ] );
assertEquals( Long.valueOf( 2 ), ( ( Object[] ) list.get( 0 ) )[ 1 ] );
assertEquals( zoo2.getName(), ( ( Object[] ) list.get( 1 ) )[ 0 ] );
assertEquals( Long.valueOf( 1 ), ( ( Object[] ) list.get( 1 ) )[ 1 ] );
assertEquals( zoo4.getName(), ( ( Object[] ) list.get( 2 ) )[ 0 ] );
assertEquals( Long.valueOf( 1 ), ( ( Object[] ) list.get( 2 ) )[ 1 ] );
cleanupData();
}
private void checkTestOrderByResults(List results,
Zoo zoo1,
Zoo zoo2,

View File

@ -2068,6 +2068,96 @@ public class ASTParserLoadingTest extends FunctionalTestCase {
destroyTestBaseData();
}
public void testJoinFetchedCollectionOfJoinedSubclass() throws Exception {
Mammal mammal = new Mammal();
mammal.setDescription( "A Zebra" );
Zoo zoo = new Zoo();
zoo.setName( "A Zoo" );
zoo.getMammals().put( "zebra", mammal );
mammal.setZoo( zoo );
Session session = openSession();
Transaction txn = session.beginTransaction();
session.save( mammal );
session.save( zoo );
txn.commit();
session = openSession();
txn = session.beginTransaction();
List results = session.createQuery( "from Zoo z join fetch z.mammals" ).list();
assertEquals( "Incorrect result size", 1, results.size() );
assertTrue( "Incorrect result return type", results.get( 0 ) instanceof Zoo );
Zoo zooRead = ( Zoo ) results.get( 0 );
assertEquals( zoo, zooRead );
assertTrue( Hibernate.isInitialized( zooRead.getMammals() ) );
Mammal mammalRead = ( Mammal ) ( ( Map ) zooRead.getMammals() ).get( "zebra" );
assertEquals( mammal, mammalRead );
session.delete( mammalRead );
session.delete( zooRead );
txn.commit();
session.close();
}
public void testJoinedCollectionOfJoinedSubclass() throws Exception {
Mammal mammal = new Mammal();
mammal.setDescription( "A Zebra" );
Zoo zoo = new Zoo();
zoo.setName( "A Zoo" );
zoo.getMammals().put( "zebra", mammal );
mammal.setZoo( zoo );
Session session = openSession();
Transaction txn = session.beginTransaction();
session.save( mammal );
session.save( zoo );
txn.commit();
session = openSession();
txn = session.beginTransaction();
List results = session.createQuery( "from Zoo z join z.mammals m" ).list();
assertEquals( "Incorrect result size", 1, results.size() );
assertTrue( "Incorrect result return type", results.get( 0 ) instanceof Object[] );
Object[] resultObjects = ( Object[] ) results.get( 0 );
Zoo zooRead = ( Zoo ) resultObjects[ 0 ];
Mammal mammalRead = ( Mammal ) resultObjects[ 1 ];
assertEquals( zoo, zooRead );
assertEquals( mammal, mammalRead );
session.delete( mammalRead );
session.delete( zooRead );
txn.commit();
session.close();
}
public void testJoinedCollectionOfJoinedSubclassProjection() throws Exception {
Mammal mammal = new Mammal();
mammal.setDescription( "A Zebra" );
Zoo zoo = new Zoo();
zoo.setName( "A Zoo" );
zoo.getMammals().put( "zebra", mammal );
mammal.setZoo( zoo );
Session session = openSession();
Transaction txn = session.beginTransaction();
session.save( mammal );
session.save( zoo );
txn.commit();
session = openSession();
txn = session.beginTransaction();
List results = session.createQuery( "select z, m from Zoo z join z.mammals m" ).list();
assertEquals( "Incorrect result size", 1, results.size() );
assertTrue( "Incorrect result return type", results.get( 0 ) instanceof Object[] );
Object[] resultObjects = ( Object[] ) results.get( 0 );
Zoo zooRead = ( Zoo ) resultObjects[ 0 ];
Mammal mammalRead = ( Mammal ) resultObjects[ 1 ];
assertEquals( zoo, zooRead );
assertEquals( mammal, mammalRead );
session.delete( mammalRead );
session.delete( zooRead );
txn.commit();
session.close();
}
public void testProjectionQueries() throws Exception {
createTestBaseData();

View File

@ -112,6 +112,11 @@
<discriminator column="zooType" type="character"/>
<property name="name" type="string"/>
<property name="classification" type="org.hibernate.test.hql.ClassificationType"/>
<map name="directors">
<key column="directorZoo_id"/>
<index type="string" column="title"/>
<many-to-many class="Human"/>
</map>
<map name="mammals">
<key column="mammalZoo_id"/>
<index type="string" column="name"/>

View File

@ -1199,7 +1199,7 @@ public class HQLTest extends QueryTranslatorTestCase {
IndexNode n = new IndexNode();
Exception ex = null;
try {
n.setScalarColumnText( 0 );
n.setScalarColumn( 0 );
}
catch ( UnsupportedOperationException e ) {
ex = e;

View File

@ -26,5 +26,32 @@ public class Mammal extends Animal {
public void setBirthdate(Date birthdate) {
this.birthdate = birthdate;
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( !( o instanceof Mammal ) ) {
return false;
}
Mammal mammal = ( Mammal ) o;
if ( pregnant != mammal.pregnant ) {
return false;
}
if ( birthdate != null ? !birthdate.equals( mammal.birthdate ) : mammal.birthdate != null ) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = ( pregnant ? 1 : 0 );
result = 31 * result + ( birthdate != null ? birthdate.hashCode() : 0 );
return result;
}
}

View File

@ -1,6 +1,7 @@
//$Id: Zoo.java 10653 2006-10-26 13:38:50Z steve.ebersole@jboss.com $
package org.hibernate.test.hql;
import java.util.HashMap;
import java.util.Map;
/**
@ -10,10 +11,18 @@ public class Zoo {
private Long id;
private String name;
private Classification classification;
private Map animals;
private Map mammals;
private Map directors = new HashMap();
private Map animals = new HashMap();
private Map mammals = new HashMap();
private Address address;
public Zoo() {
}
public Zoo(String name, Address address) {
this.name = name;
this.address = address;
}
public Long getId() {
return id;
}
@ -30,6 +39,14 @@ public class Zoo {
this.name = name;
}
public Map getDirectors() {
return directors;
}
public void setDirectors(Map directors) {
this.directors = directors;
}
public Map getMammals() {
return mammals;
}

View File

@ -52,4 +52,11 @@ public class JPAQLComplianceTest extends AbstractJPATest {
s.createQuery( "select c FROM Item c WHERE c.parts IS EMPTY" ).list();
s.close();
}
public void testOrderByAlias() {
Session s = openSession();
s.createQuery( "select c.name as myname FROM Item c ORDER BY myname" ).list();
s.createQuery( "select p.name as name, p.stockNumber as stockNo, p.unitPrice as uPrice FROM Part p ORDER BY name, abs( p.unitPrice ), stockNo" ).list();
s.close();
}
}