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(a)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();
+ }
}