[hibernate-commits] Hibernate SVN: r20673 - in core/trunk: core/src/main/java/org/hibernate/dialect and 4 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Mon Sep 20 13:42:39 EDT 2010


Author: gbadner
Date: 2010-09-20 13:42:39 -0400 (Mon, 20 Sep 2010)
New Revision: 20673

Added:
   core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/ResultVariableRefNode.java
Modified:
   core/trunk/core/src/main/antlr/hql-sql.g
   core/trunk/core/src/main/antlr/sql-gen.g
   core/trunk/core/src/main/java/org/hibernate/dialect/Dialect.java
   core/trunk/core/src/main/java/org/hibernate/hql/ast/HqlSqlWalker.java
   core/trunk/core/src/main/java/org/hibernate/hql/ast/SqlASTFactory.java
   core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/AbstractSelectExpression.java
   core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/ConstructorNode.java
   core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/MapEntryNode.java
   core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/QueryNode.java
   core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/SelectClause.java
   core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/SelectExpression.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/hql/ASTParserLoadingOrderByTest.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/hql/Animal.hbm.xml
   core/trunk/testsuite/src/test/java/org/hibernate/test/hql/HQLTest.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/hql/Mammal.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/hql/Zoo.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/jpa/ql/JPAQLComplianceTest.java
Log:
HHH-892 : HQL parser does not resolve alias in ORDER BY clause

Modified: core/trunk/core/src/main/antlr/hql-sql.g
===================================================================
--- core/trunk/core/src/main/antlr/hql-sql.g	2010-09-20 15:18:39 UTC (rev 20672)
+++ core/trunk/core/src/main/antlr/hql-sql.g	2010-09-20 17:42:39 UTC (rev 20673)
@@ -50,6 +50,8 @@
 	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,8 +213,15 @@
 
 	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,9 +343,22 @@
 	;
 
 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
 	: #(GROUP { handleClauseStart( GROUP ); } (expr)+ ( #(HAVING logicalExpr) )? )
 	;
@@ -358,7 +380,7 @@
 
 aliasedSelectExpr!
 	: #(AS se:selectExpr i:identifier) {
-	    setAlias(#se,#i);
+		setAlias(#se,#i);
 		#aliasedSelectExpr = #se;
 	}
 	;
@@ -723,4 +745,4 @@
 
 numericInteger
 	: NUM_INT
-	;
\ No newline at end of file
+	;

Modified: core/trunk/core/src/main/antlr/sql-gen.g
===================================================================
--- core/trunk/core/src/main/antlr/sql-gen.g	2010-09-20 15:18:39 UTC (rev 20672)
+++ core/trunk/core/src/main/antlr/sql-gen.g	2010-09-20 17:42:39 UTC (rev 20673)
@@ -432,6 +432,7 @@
 	: #(r:DOT . .) { out(r); }
 	| i:ALIAS_REF { out(i); }
 	| j:INDEX_OP { out(j); }
+	| v:RESULT_VARIABLE_REF { out(v); }
 	;
 
 sqlToken

Modified: core/trunk/core/src/main/java/org/hibernate/dialect/Dialect.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/dialect/Dialect.java	2010-09-20 15:18:39 UTC (rev 20672)
+++ core/trunk/core/src/main/java/org/hibernate/dialect/Dialect.java	2010-09-20 17:42:39 UTC (rev 20673)
@@ -1724,6 +1724,20 @@
 	}
 
 	/**
+	 * 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.
 	 *

Modified: core/trunk/core/src/main/java/org/hibernate/hql/ast/HqlSqlWalker.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/hql/ast/HqlSqlWalker.java	2010-09-20 15:18:39 UTC (rev 20672)
+++ core/trunk/core/src/main/java/org/hibernate/hql/ast/HqlSqlWalker.java	2010-09-20 17:42:39 UTC (rev 20673)
@@ -66,6 +66,7 @@
 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 @@
 	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 @@
 
     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.
 	 */

Modified: core/trunk/core/src/main/java/org/hibernate/hql/ast/SqlASTFactory.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/hql/ast/SqlASTFactory.java	2010-09-20 15:18:39 UTC (rev 20672)
+++ core/trunk/core/src/main/java/org/hibernate/hql/ast/SqlASTFactory.java	2010-09-20 17:42:39 UTC (rev 20673)
@@ -51,6 +51,7 @@
 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 @@
 			case ALIAS_REF:
 			case IDENT:
 				return IdentNode.class;
+			case RESULT_VARIABLE_REF:
+				return ResultVariableRefNode.class;
 			case SQL_TOKEN:
 				return SqlFragment.class;
 			case METHOD_CALL:

Modified: core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/AbstractSelectExpression.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/AbstractSelectExpression.java	2010-09-20 15:18:39 UTC (rev 20672)
+++ core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/AbstractSelectExpression.java	2010-09-20 17:42:39 UTC (rev 20673)
@@ -36,6 +36,7 @@
 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 @@
 		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;
+	}
 }

Modified: core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/ConstructorNode.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/ConstructorNode.java	2010-09-20 15:18:39 UTC (rev 20672)
+++ core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/ConstructorNode.java	2010-09-20 17:42:39 UTC (rev 20673)
@@ -51,6 +51,7 @@
 	private Type[] constructorArgumentTypes;
 	private boolean isMap;
 	private boolean isList;
+	private int scalarColumnIndex = -1;
 
 	public ResultTransformer getResultTransformer() {
 		if ( constructor != null ) {
@@ -92,6 +93,19 @@
 		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.

Modified: core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/MapEntryNode.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/MapEntryNode.java	2010-09-20 15:18:39 UTC (rev 20672)
+++ core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/MapEntryNode.java	2010-09-20 17:42:39 UTC (rev 20673)
@@ -60,6 +60,8 @@
 		}
 	}
 
+	private int scalarColumnIndex = -1;
+
 	protected String expressionDescription() {
 		return "entry(*)";
 	}
@@ -190,6 +192,14 @@
 		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 {
 	}
 

Modified: core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/QueryNode.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/QueryNode.java	2010-09-20 15:18:39 UTC (rev 20672)
+++ core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/QueryNode.java	2010-09-20 17:42:39 UTC (rev 20673)
@@ -46,6 +46,7 @@
 	private static final Logger log = LoggerFactory.getLogger( QueryNode.class );
 
 	private OrderByClause orderByClause;
+	private int scalarColumnIndex = -1;
 
 	/**
 	 * @see Statement#getStatementType() 
@@ -145,6 +146,15 @@
 		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 );
 	}

Added: core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/ResultVariableRefNode.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/ResultVariableRefNode.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/ResultVariableRefNode.java	2010-09-20 17:42:39 UTC (rev 20673)
@@ -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 ] );
+	}
+}

Modified: core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/SelectClause.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/SelectClause.java	2010-09-20 15:18:39 UTC (rev 20672)
+++ core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/SelectClause.java	2010-09-20 17:42:39 UTC (rev 20673)
@@ -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 @@
 	private String[][] columnNames;
 	private List collectionFromElements;
 	private String[] aliases;
+	private int[] columnNamesStartPositions;
 
 	// Currently we can only have one...
 	private AggregatedSelectExpression aggregatedSelectExpression;
@@ -253,8 +255,18 @@
 
 		// 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 ];
+	}
+
 	/**
 	 * Prepares a derived (i.e., not explicitly defined in the query) select clause.
 	 *
@@ -356,7 +368,7 @@
 		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.
 			}
 		}
 	}

Modified: core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/SelectExpression.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/SelectExpression.java	2010-09-20 15:18:39 UTC (rev 20672)
+++ core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/SelectExpression.java	2010-09-20 17:42:39 UTC (rev 20673)
@@ -50,6 +50,21 @@
 	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.
 	 *
 	 * @return The FROM element.

Modified: core/trunk/testsuite/src/test/java/org/hibernate/test/hql/ASTParserLoadingOrderByTest.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/hql/ASTParserLoadingOrderByTest.java	2010-09-20 15:18:39 UTC (rev 20672)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/hql/ASTParserLoadingOrderByTest.java	2010-09-20 17:42:39 UTC (rev 20673)
@@ -100,6 +100,10 @@
 	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 @@
 		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,8 +159,13 @@
 		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" );
 		Address address3 = new Address();
@@ -170,7 +187,11 @@
 		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 @@
 			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 @@
 		cleanupData();
 	}
 
-	public void testOrderBySelectAliasRefFailureExpected() {
+	public void testOrderBySelectAliasRef() {
 		createData();
 
 		Session s = openSession();
@@ -492,22 +532,6 @@
 		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 @@
 		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,

Modified: core/trunk/testsuite/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java	2010-09-20 15:18:39 UTC (rev 20672)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java	2010-09-20 17:42:39 UTC (rev 20673)
@@ -2068,6 +2068,96 @@
 		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();

Modified: core/trunk/testsuite/src/test/java/org/hibernate/test/hql/Animal.hbm.xml
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/hql/Animal.hbm.xml	2010-09-20 15:18:39 UTC (rev 20672)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/hql/Animal.hbm.xml	2010-09-20 17:42:39 UTC (rev 20673)
@@ -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"/>

Modified: core/trunk/testsuite/src/test/java/org/hibernate/test/hql/HQLTest.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/hql/HQLTest.java	2010-09-20 15:18:39 UTC (rev 20672)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/hql/HQLTest.java	2010-09-20 17:42:39 UTC (rev 20673)
@@ -1199,7 +1199,7 @@
 		IndexNode n = new IndexNode();
 		Exception ex = null;
 		try {
-			n.setScalarColumnText( 0 );
+			n.setScalarColumn( 0 );
 		}
 		catch ( UnsupportedOperationException e ) {
 			ex = e;

Modified: core/trunk/testsuite/src/test/java/org/hibernate/test/hql/Mammal.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/hql/Mammal.java	2010-09-20 15:18:39 UTC (rev 20672)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/hql/Mammal.java	2010-09-20 17:42:39 UTC (rev 20673)
@@ -26,5 +26,32 @@
 	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;
+	}
 }

Modified: core/trunk/testsuite/src/test/java/org/hibernate/test/hql/Zoo.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/hql/Zoo.java	2010-09-20 15:18:39 UTC (rev 20672)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/hql/Zoo.java	2010-09-20 17:42:39 UTC (rev 20673)
@@ -1,6 +1,7 @@
 //$Id: Zoo.java 10653 2006-10-26 13:38:50Z steve.ebersole at jboss.com $
 package org.hibernate.test.hql;
 
+import java.util.HashMap;
 import java.util.Map;
 
 /**
@@ -10,10 +11,18 @@
 	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 @@
 		this.name = name;
 	}
 
+	public Map getDirectors() {
+		return directors;
+	}
+
+	public void setDirectors(Map directors) {
+		this.directors = directors;
+	}
+
 	public Map getMammals() {
 		return mammals;
 	}

Modified: core/trunk/testsuite/src/test/java/org/hibernate/test/jpa/ql/JPAQLComplianceTest.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/jpa/ql/JPAQLComplianceTest.java	2010-09-20 15:18:39 UTC (rev 20672)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/jpa/ql/JPAQLComplianceTest.java	2010-09-20 17:42:39 UTC (rev 20673)
@@ -52,4 +52,11 @@
 		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();
+	}	
 }



More information about the hibernate-commits mailing list