diff --git a/testsuite/src/test/java/org/hibernate/test/hql/ASTParserLoadingOrderByTest.java b/testsuite/src/test/java/org/hibernate/test/hql/ASTParserLoadingOrderByTest.java new file mode 100644 index 0000000000..4e0b3dd14f --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/hql/ASTParserLoadingOrderByTest.java @@ -0,0 +1,574 @@ +/* + * 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.test.hql; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Date; +import java.sql.Time; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import junit.framework.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.hibernate.Hibernate; +import org.hibernate.HibernateException; +import org.hibernate.Query; +import org.hibernate.QueryException; +import org.hibernate.ScrollableResults; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.TypeMismatchException; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.dialect.DB2Dialect; +import org.hibernate.dialect.HSQLDialect; +import org.hibernate.dialect.IngresDialect; +import org.hibernate.dialect.MySQLDialect; +import org.hibernate.dialect.Oracle8iDialect; +import org.hibernate.dialect.PostgreSQLDialect; +import org.hibernate.dialect.SQLServerDialect; +import org.hibernate.dialect.Sybase11Dialect; +import org.hibernate.dialect.SybaseASE15Dialect; +import org.hibernate.dialect.SybaseAnywhereDialect; +import org.hibernate.dialect.SybaseDialect; +import org.hibernate.hql.ast.ASTQueryTranslatorFactory; +import org.hibernate.hql.ast.QuerySyntaxException; +import org.hibernate.persister.entity.DiscriminatorType; +import org.hibernate.stat.QueryStatistics; +import org.hibernate.test.any.IntegerPropertyValue; +import org.hibernate.test.any.PropertySet; +import org.hibernate.test.any.PropertyValue; +import org.hibernate.test.any.StringPropertyValue; +import org.hibernate.test.cid.Customer; +import org.hibernate.test.cid.LineItem; +import org.hibernate.test.cid.LineItem.Id; +import org.hibernate.test.cid.Order; +import org.hibernate.test.cid.Product; +import org.hibernate.testing.junit.functional.FunctionalTestCase; +import org.hibernate.testing.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.transform.DistinctRootEntityResultTransformer; +import org.hibernate.transform.Transformers; +import org.hibernate.type.ComponentType; +import org.hibernate.type.ManyToOneType; +import org.hibernate.type.Type; +import org.hibernate.util.StringHelper; + +/** + * Tests AST parser processing of ORDER BY clauses. + * + * @author Gail Badner + */ +public class ASTParserLoadingOrderByTest extends FunctionalTestCase { + + private static final Logger log = LoggerFactory.getLogger( ASTParserLoadingOrderByTest.class ); + + StateProvince stateProvince; + private Zoo zoo1; + private Zoo zoo2; + private Zoo zoo3; + private Zoo zoo4; + Set zoosWithSameName; + Set zoosWithSameAddress; + + public ASTParserLoadingOrderByTest(String name) { + super( name ); + } + + public String[] getMappings() { + return new String[] { + "hql/Animal.hbm.xml", + }; + } + + public void configure(Configuration cfg) { + super.configure( cfg ); + cfg.setProperty( Environment.USE_QUERY_CACHE, "false" ); + cfg.setProperty( Environment.GENERATE_STATISTICS, "true" ); + cfg.setProperty( Environment.QUERY_TRANSLATOR, ASTQueryTranslatorFactory.class.getName() ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( ASTParserLoadingOrderByTest.class ); + } + + protected void prepareTest() { + cleanupData(); + } + + protected void createData() { + stateProvince = new StateProvince(); + stateProvince.setName( "IL" ); + + zoo1 = new Zoo(); + zoo1.setName( "Zoo" ); + Address address1 = new Address(); + address1.setStreet( "1313 Mockingbird Lane" ); + address1.setCity( "Anywhere" ); + address1.setStateProvince( stateProvince ); + address1.setCountry( "USA" ); + zoo1.setAddress( address1 ); + + zoo2 = new Zoo(); + zoo2.setName( "A Zoo" ); + Address address2 = new Address(); + address2.setStreet( "1313 Mockingbird Lane" ); + address2.setCity( "Anywhere" ); + address2.setStateProvince( stateProvince ); + address2.setCountry( "USA" ); + zoo2.setAddress( address2 ); + + + zoo3 = new Zoo(); + zoo3.setName( "Zoo" ); + Address address3 = new Address(); + address3.setStreet( "1312 Mockingbird Lane" ); + address3.setCity( "Anywhere" ); + address3.setStateProvince( stateProvince ); + address3.setCountry( "USA" ); + zoo3.setAddress( address3 ); + + zoo4 = new Zoo(); + zoo4.setName( "Duh Zoo" ); + Address address4 = new Address(); + address4.setStreet( "1312 Mockingbird Lane" ); + address4.setCity( "Nowhere" ); + address4.setStateProvince( stateProvince ); + address4.setCountry( "USA" ); + zoo4.setAddress( address4 ); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.save( stateProvince ); + s.save( zoo1 ); + s.save( zoo2 ); + s.save( zoo3 ); + s.save( zoo4 ); + t.commit(); + s.close(); + + zoosWithSameName = new HashSet( 2 ); + zoosWithSameName.add( zoo1 ); + zoosWithSameName.add( zoo3 ); + zoosWithSameAddress = new HashSet( 2 ); + zoosWithSameAddress.add( zoo1 ); + zoosWithSameAddress.add( zoo2 ); + } + + protected void cleanupData() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + if ( zoo1 != null ) { + s.delete( zoo1 ); + zoo1 = null; + } + if ( zoo2 != null ) { + s.delete( zoo2 ); + zoo2 = null; + } + if ( zoo3 != null ) { + s.delete( zoo3 ); + zoo3 = null; + } + if ( zoo4 != null ) { + s.delete( zoo4 ); + zoo4 = null; + } + t.commit(); + s.close(); + } + + public void testOrderByNoSelectAliasRef() { + 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 + checkTestOrderByResults( + s.createQuery( + "select name, address from Zoo order by name, address" + ).list(), + zoo2, zoo4, zoo3, zoo1, null + ); + checkTestOrderByResults( + s.createQuery( + "select z.name, z.address from Zoo z order by z.name, z.address" + ).list(), + zoo2, zoo4, zoo3, zoo1, null + ); + checkTestOrderByResults( + s.createQuery( + "select z2.name, z2.address from Zoo z2 where z2.name in ( select name from Zoo ) order by z2.name, z2.address" + ).list(), + zoo2, zoo4, zoo3, zoo1, null + ); + // using ASC + checkTestOrderByResults( + s.createQuery( + "select name, address from Zoo order by name ASC, address ASC" + ).list(), + zoo2, zoo4, zoo3, zoo1, null + ); + checkTestOrderByResults( + s.createQuery( + "select z.name, z.address from Zoo z order by z.name ASC, z.address ASC" + ).list(), + zoo2, zoo4, zoo3, zoo1, null + ); + checkTestOrderByResults( + s.createQuery( + "select z2.name, z2.address from Zoo z2 where z2.name in ( select name from Zoo ) order by z2.name ASC, z2.address ASC" + ).list(), + zoo2, zoo4, zoo3, zoo1, null + ); + + // 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 + checkTestOrderByResults( + s.createQuery( + "select z.name, z.address from Zoo z order by z.address, z.name" + ).list(), + zoo3, zoo4, zoo2, zoo1, null + ); + checkTestOrderByResults( + s.createQuery( + "select name, address from Zoo order by address, name" + ).list(), + zoo3, zoo4, zoo2, zoo1, null + ); + + // ordered by address: + // zoo3 Zoo 1312 Mockingbird Lane, Anywhere, IL USA + // zoo4 Duh Zoo 1312 Mockingbird Lane, Nowhere, IL USA + // unordered: + // zoo2 A Zoo 1313 Mockingbird Lane, Anywhere, IL USA + // zoo1 Zoo 1313 Mockingbird Lane, Anywhere, IL USA + checkTestOrderByResults( + s.createQuery( + "select z.name, z.address from Zoo z order by z.address" + ).list(), + zoo3, zoo4, null, null, zoosWithSameAddress + ); + checkTestOrderByResults( + s.createQuery( + "select name, address from Zoo order by address" + ).list(), + zoo3, zoo4, null, null, zoosWithSameAddress + ); + + // ordered by name: + // zoo2 A Zoo 1313 Mockingbird Lane, Anywhere, IL USA + // zoo4 Duh Zoo 1312 Mockingbird Lane, Nowhere, IL USA + // unordered: + // zoo1 Zoo 1313 Mockingbird Lane, Anywhere, IL USA + // zoo3 Zoo 1312 Mockingbird Lane, Anywhere, IL USA + checkTestOrderByResults( + s.createQuery( + "select z.name, z.address from Zoo z order by z.name" + ).list(), + zoo2, zoo4, null, null, zoosWithSameName + ); + checkTestOrderByResults( + s.createQuery( + "select name, address from Zoo order by name" + ).list(), + zoo2, zoo4, null, null, zoosWithSameName + ); + t.commit(); + s.close(); + + cleanupData(); + } + + public void testOrderByComponentDescNoSelectAliasRefFailureExpected() { + 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 + checkTestOrderByResults( + s.createQuery( + "select z.name, z.address from Zoo z order by z.address DESC, z.name DESC" + ).list(), + zoo1, zoo2, zoo4, zoo3, null + ); + checkTestOrderByResults( + s.createQuery( + "select name, address from Zoo order by address DESC, name DESC" + ).list(), + zoo1, zoo2, zoo4, zoo3, null + ); + t.commit(); + s.close(); + cleanupData(); + } + + public void testOrderBySelectAliasRefFailureExpected() { + 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 + checkTestOrderByResults( + s.createQuery( + "select z2.name as zname, z2.address as zooAddress from Zoo z2 where z2.name in ( select name from Zoo ) order by zname, zooAddress" + ).list(), + zoo2, zoo4, zoo3, zoo1, null + ); + checkTestOrderByResults( + s.createQuery( + "select z.name as name, z.address as address from Zoo z order by name, address" + ).list(), + zoo2, zoo4, zoo3, zoo1, null + ); + checkTestOrderByResults( + s.createQuery( + "select z.name as zooName, z.address as zooAddress from Zoo z order by zooName, zooAddress" + ).list(), + zoo2, zoo4, zoo3, zoo1, null + ); + checkTestOrderByResults( + s.createQuery( + "select z.name, z.address as name from Zoo z order by z.name, name" + ).list(), + zoo2, zoo4, zoo3, zoo1, null + ); + checkTestOrderByResults( + s.createQuery( + "select z.name, z.address as name from Zoo z order by z.name, name" + ).list(), + zoo2, zoo4, zoo3, zoo1, null + ); + // using ASC + checkTestOrderByResults( + s.createQuery( + "select z2.name as zname, z2.address as zooAddress from Zoo z2 where z2.name in ( select name from Zoo ) order by zname ASC, zooAddress ASC" + ).list(), + zoo2, zoo4, zoo3, zoo1, null + ); + checkTestOrderByResults( + s.createQuery( + "select z.name as name, z.address as address from Zoo z order by name ASC, address ASC" + ).list(), + zoo2, zoo4, zoo3, zoo1, null + ); + checkTestOrderByResults( + s.createQuery( + "select z.name as zooName, z.address as zooAddress from Zoo z order by zooName ASC, zooAddress ASC" + ).list(), + zoo2, zoo4, zoo3, zoo1, null + ); + checkTestOrderByResults( + s.createQuery( + "select z.name, z.address as name from Zoo z order by z.name ASC, name ASC" + ).list(), + zoo2, zoo4, zoo3, zoo1, null + ); + checkTestOrderByResults( + s.createQuery( + "select z.name, z.address as name from Zoo z order by z.name ASC, name ASC" + ).list(), + zoo2, zoo4, zoo3, zoo1, null + ); + + // 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 + checkTestOrderByResults( + s.createQuery( + "select z.name as address, z.address as name from Zoo z order by name, address" + ).list(), + zoo3, zoo4, zoo2, zoo1, null + ); + checkTestOrderByResults( + s.createQuery( + "select z.name, z.address as name from Zoo z order by name, z.name" + ).list(), + zoo3, zoo4, zoo2, zoo1, null + ); + // using ASC + checkTestOrderByResults( + s.createQuery( + "select z.name as address, z.address as name from Zoo z order by name ASC, address ASC" + ).list(), + zoo3, zoo4, zoo2, zoo1, null + ); + checkTestOrderByResults( + s.createQuery( + "select z.name, z.address as name from Zoo z order by name ASC, z.name ASC" + ).list(), + zoo3, zoo4, zoo2, zoo1, null + ); + + // ordered by address: + // zoo3 Zoo 1312 Mockingbird Lane, Anywhere, IL USA + // zoo4 Duh Zoo 1312 Mockingbird Lane, Nowhere, IL USA + // unordered: + // zoo2 A Zoo 1313 Mockingbird Lane, Anywhere, IL USA + // zoo1 Zoo 1313 Mockingbird Lane, Anywhere, IL USA + checkTestOrderByResults( + s.createQuery( + "select z.name as zooName, z.address as zooAddress from Zoo z order by zooAddress" + ).list(), + zoo3, zoo4, null, null, zoosWithSameAddress + ); + + checkTestOrderByResults( + s.createQuery( + "select z.name as zooName, z.address as name from Zoo z order by name" + ).list(), + zoo3, zoo4, null, null, zoosWithSameAddress + ); + + // ordered by name: + // zoo2 A Zoo 1313 Mockingbird Lane, Anywhere, IL USA + // zoo4 Duh Zoo 1312 Mockingbird Lane, Nowhere, IL USA + // unordered: + // zoo1 Zoo 1313 Mockingbird Lane, Anywhere, IL USA + // zoo3 Zoo 1312 Mockingbird Lane, Anywhere, IL USA + checkTestOrderByResults( + s.createQuery( + "select z.name as zooName, z.address as zooAddress from Zoo z order by zooName" + ).list(), + zoo2, zoo4, null, null, zoosWithSameName + ); + + checkTestOrderByResults( + s.createQuery( + "select z.name as address, z.address as name from Zoo z order by address" + ).list(), + zoo2, zoo4, null, null, zoosWithSameName + ); + 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(); + } + + public void testOrderByComponentDescSelectAliasRefFailureExpected() { + 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 + checkTestOrderByResults( + s.createQuery( + "select z.name as zooName, z.address as zooAddress from Zoo z order by zooAddress DESC, zooName DESC" + ).list(), + zoo1, zoo2, zoo4, zoo3, null + ); + + t.commit(); + s.close(); + + cleanupData(); + } + + private void checkTestOrderByResults(List results, + Zoo zoo1, + Zoo zoo2, + Zoo zoo3, + Zoo zoo4, + Set zoosUnordered) { + assertEquals( 4, results.size() ); + Set zoosUnorderedCopy = ( zoosUnordered == null ? null : new HashSet( zoosUnordered ) ); + checkTestOrderByResult( results.get( 0 ), zoo1, zoosUnorderedCopy ); + checkTestOrderByResult( results.get( 1 ), zoo2, zoosUnorderedCopy ); + checkTestOrderByResult( results.get( 2 ), zoo3, zoosUnorderedCopy ); + checkTestOrderByResult( results.get( 3 ), zoo4, zoosUnorderedCopy ); + if ( zoosUnorderedCopy != null ) { + assertTrue( zoosUnorderedCopy.isEmpty() ); + } + } + + private void checkTestOrderByResult(Object result, + Zoo zooExpected, + Set zoosUnordered) { + assertTrue( result instanceof Object[] ); + Object[] resultArray = ( Object[] ) result; + assertEquals( 2, resultArray.length ); + Hibernate.initialize( ( ( Address ) resultArray[ 1 ] ).getStateProvince() ); + if ( zooExpected == null ) { + Zoo zooResult = new Zoo(); + zooResult.setName( ( String ) resultArray[ 0 ] ); + zooResult.setAddress( ( Address ) resultArray[ 1 ] ); + assertTrue( zoosUnordered.remove( zooResult ) ); + } + else { + assertEquals( zooExpected.getName(), ( ( Object[] ) result )[ 0 ] ); + assertEquals( zooExpected.getAddress(), ( ( Object[] ) result )[ 1 ] ); + } + } +} \ No newline at end of file diff --git a/testsuite/src/test/java/org/hibernate/test/hql/Address.java b/testsuite/src/test/java/org/hibernate/test/hql/Address.java index a947217ff8..6584d5aeb4 100644 --- a/testsuite/src/test/java/org/hibernate/test/hql/Address.java +++ b/testsuite/src/test/java/org/hibernate/test/hql/Address.java @@ -52,4 +52,44 @@ public class Address { public void setStateProvince(StateProvince stateProvince) { this.stateProvince = stateProvince; } + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + + Address address = ( Address ) o; + + if ( city != null ? !city.equals( address.city ) : address.city != null ) { + return false; + } + if ( country != null ? !country.equals( address.country ) : address.country != null ) { + return false; + } + if ( postalCode != null ? !postalCode.equals( address.postalCode ) : address.postalCode != null ) { + return false; + } + if ( stateProvince != null ? !stateProvince.equals( address.stateProvince ) : address.stateProvince != null ) { + return false; + } + if ( street != null ? !street.equals( address.street ) : address.street != null ) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = street != null ? street.hashCode() : 0; + result = 31 * result + ( city != null ? city.hashCode() : 0 ); + result = 31 * result + ( postalCode != null ? postalCode.hashCode() : 0 ); + result = 31 * result + ( country != null ? country.hashCode() : 0 ); + result = 31 * result + ( stateProvince != null ? stateProvince.hashCode() : 0 ); + return result; + } } diff --git a/testsuite/src/test/java/org/hibernate/test/hql/StateProvince.java b/testsuite/src/test/java/org/hibernate/test/hql/StateProvince.java index 0874df94c8..1574894a43 100644 --- a/testsuite/src/test/java/org/hibernate/test/hql/StateProvince.java +++ b/testsuite/src/test/java/org/hibernate/test/hql/StateProvince.java @@ -34,4 +34,32 @@ public class StateProvince { public void setIsoCode(String isoCode) { this.isoCode = isoCode; } + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( !( o instanceof StateProvince ) ) { + return false; + } + + StateProvince that = ( StateProvince ) o; + + if ( isoCode != null ? !isoCode.equals( that.getIsoCode() ) : that.getIsoCode() != null ) { + return false; + } + if ( name != null ? !name.equals( that.getName() ) : that.getName() != null ) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = name != null ? name.hashCode() : 0; + result = 31 * result + ( isoCode != null ? isoCode.hashCode() : 0 ); + return result; + } } diff --git a/testsuite/src/test/java/org/hibernate/test/hql/Zoo.java b/testsuite/src/test/java/org/hibernate/test/hql/Zoo.java index ea36a546a8..a04af15a1b 100644 --- a/testsuite/src/test/java/org/hibernate/test/hql/Zoo.java +++ b/testsuite/src/test/java/org/hibernate/test/hql/Zoo.java @@ -61,4 +61,32 @@ public class Zoo { public void setClassification(Classification classification) { this.classification = classification; } + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( !( o instanceof Zoo ) ) { + return false; + } + + Zoo zoo = ( Zoo ) o; + + if ( address != null ? !address.equals( zoo.address ) : zoo.address != null ) { + return false; + } + if ( name != null ? !name.equals( zoo.name ) : zoo.name != null ) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = name != null ? name.hashCode() : 0; + result = 31 * result + ( address != null ? address.hashCode() : 0 ); + return result; + } }