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:
parent
dde16433ad
commit
13699d792b
|
@ -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
|
||||
;
|
||||
;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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 ] );
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue