From 0facaf563231987ddb48be11b37d832a6319e66b Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Wed, 27 Oct 2021 20:54:54 +0200 Subject: [PATCH] Re-enable additional scrollable fetch test --- .../query/sqm/InterpretationException.java | 7 +- .../hql/ScrollableCollectionFetchingTest.java | 425 +++++++++++++++++ .../hql/ScrollableCollectionFetchingTest.java | 427 ------------------ 3 files changed, 429 insertions(+), 430 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/hql/ScrollableCollectionFetchingTest.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/hql/ScrollableCollectionFetchingTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/InterpretationException.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/InterpretationException.java index 094be0bc03..9a4469983a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/InterpretationException.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/InterpretationException.java @@ -6,7 +6,7 @@ */ package org.hibernate.query.sqm; -import org.hibernate.HibernateException; +import org.hibernate.QueryException; /** * Represents a general uncaught problem performing the interpretation. This might indicate @@ -14,14 +14,15 @@ import org.hibernate.HibernateException; * * @author Steve Ebersole */ -public class InterpretationException extends HibernateException { +public class InterpretationException extends QueryException { public InterpretationException(String query) { this( query, null ); } - public InterpretationException(String query, Throwable cause) { + public InterpretationException(String query, Exception cause) { super( "Error interpreting query [" + query + "]; this may indicate a semantic (user query) problem or a bug in the parser", + query, cause ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/ScrollableCollectionFetchingTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/ScrollableCollectionFetchingTest.java new file mode 100644 index 0000000000..db84cfe4bc --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/ScrollableCollectionFetchingTest.java @@ -0,0 +1,425 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.orm.test.hql; + +import org.hibernate.HibernateException; +import org.hibernate.QueryException; +import org.hibernate.ScrollMode; +import org.hibernate.ScrollableResults; +import org.hibernate.dialect.AbstractHANADialect; +import org.hibernate.dialect.SybaseASEDialect; +import org.hibernate.query.sqm.InterpretationException; + +import org.hibernate.testing.orm.junit.DialectFeatureChecks; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.RequiresDialectFeature; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.SkipForDialect; +import org.hibernate.test.hql.Animal; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import static org.hibernate.testing.orm.junit.ExtraAssertions.assertTyping; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + + +/** + * Tests the new functionality of allowing scrolling of results which + * contain collection fetches. + * + * @author Steve Ebersole + */ +@DomainModel( + xmlMappings = "org/hibernate/test/hql/Animal.hbm.xml" +) +@SessionFactory +public class ScrollableCollectionFetchingTest { + + @Test + public void testTupleReturnFails(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + try { + session.createQuery( "select a, a.weight from Animal a inner join fetch a.offspring" ).scroll(); + fail( "scroll allowed with collection fetch and reurning tuples" ); + } + catch (IllegalArgumentException e) { + assertTyping( QueryException.class, e.getCause() ); + } + catch (HibernateException e) { + // expected result... + } + } + ); + + } + + @Test + @SkipForDialect(dialectClass = SybaseASEDialect.class, version = 1500, matchSubTypes = true, reason = "HHH-5229") + @SkipForDialect(dialectClass = AbstractHANADialect.class, reason = "HANA only supports forward-only cursors.") + public void testScrollingJoinFetchesEmptyResultSet(SessionFactoryScope scope) { + scope.inTransaction( + s -> { + final String query = "from Animal a left join fetch a.offspring where a.description like :desc order by a.id"; + + // first, as a control, make sure there are no results + int size = s.createQuery( query ).setParameter( "desc", "root%" ).list().size(); + assertEquals( 0, size ); + + // now get the scrollable results + ScrollableResults results = s.createQuery( query ).setParameter( "desc", "root%" ).scroll(); + + assertFalse( results.isFirst() ); + assertFalse( results.isLast() ); + + assertFalse( results.next() ); + assertFalse( results.isFirst() ); + assertFalse( results.isLast() ); + + assertFalse( results.previous() ); + assertFalse( results.isFirst() ); + assertFalse( results.isLast() ); + + results.beforeFirst(); + assertFalse( results.isFirst() ); + assertFalse( results.isLast() ); + assertFalse( results.next() ); + + assertFalse( results.first() ); + assertFalse( results.isFirst() ); + assertFalse( results.isLast() ); + assertFalse( results.next() ); + + results.afterLast(); + assertFalse( results.isFirst() ); + assertFalse( results.isLast() ); + assertFalse( results.next() ); + + assertFalse( results.last() ); + assertFalse( results.isFirst() ); + assertFalse( results.isLast() ); + assertFalse( results.next() ); + + for ( int i = 1; i < 3; i++ ) { + assertFalse( results.scroll( i ) ); + assertFalse( results.isFirst() ); + assertFalse( results.isLast() ); + + assertFalse( results.scroll( -i ) ); + assertFalse( results.isFirst() ); + assertFalse( results.isLast() ); + + assertFalse( results.setRowNumber( i ) ); + assertFalse( results.isFirst() ); + assertFalse( results.isLast() ); + + assertFalse( results.setRowNumber( -i ) ); + assertFalse( results.isFirst() ); + assertFalse( results.isLast() ); + } + } + ); + } + + @Test + @RequiresDialectFeature(feature = DialectFeatureChecks.SupportsTemporaryTable.class) + @SkipForDialect(dialectClass = AbstractHANADialect.class, reason = "HANA only supports forward-only cursors") + public void testScrollingJoinFetchesSingleRowResultSet(SessionFactoryScope scope) { + + scope.inTransaction( + session -> { + Animal mother = new Animal(); + mother.setDescription( "root-1" ); + + Animal daughter = new Animal(); + daughter.setDescription( "daughter" ); + + daughter.setMother( mother ); + mother.addOffspring( daughter ); + + session.save( mother ); + session.save( daughter ); + } + ); + + + scope.inTransaction( + session -> { + assertNotNull( + session + .createQuery( + "from Animal a left join fetch a.offspring where a.description like :desc order by a.id" ) + .setParameter( "desc", "root%" ) + .uniqueResult() ); + + ScrollableResults results = session + .createQuery( + "from Animal a left join fetch a.offspring where a.description like :desc order by a.id" ) + .setParameter( "desc", "root%" ).scroll(); + + assertFalse( results.isFirst() ); + assertFalse( results.isLast() ); + assertFalse( results.previous() ); + + assertTrue( results.next() ); + assertTrue( results.isFirst() ); + assertTrue( results.isLast() ); + + assertFalse( results.next() ); + assertFalse( results.isFirst() ); + assertFalse( results.isLast() ); + + assertTrue( results.previous() ); + assertTrue( results.isFirst() ); + assertTrue( results.isLast() ); + + assertFalse( results.previous() ); + assertFalse( results.isFirst() ); + assertFalse( results.isLast() ); + + assertTrue( results.next() ); + assertTrue( results.isFirst() ); + assertTrue( results.isLast() ); + + results.beforeFirst(); + assertFalse( results.isFirst() ); + assertFalse( results.isLast() ); + assertFalse( results.previous() ); + + assertTrue( results.first() ); + assertTrue( results.isFirst() ); + assertTrue( results.isLast() ); + assertFalse( results.next() ); + + results.afterLast(); + assertFalse( results.isFirst() ); + assertFalse( results.isLast() ); + assertFalse( results.next() ); + + assertTrue( results.last() ); + assertTrue( results.isFirst() ); + assertTrue( results.isLast() ); + assertFalse( results.next() ); + + assertTrue( results.first() ); + assertTrue( results.isFirst() ); + assertTrue( results.isLast() ); + + for ( int i = 1; i < 3; i++ ) { + assertTrue( results.setRowNumber( 1 ) ); + assertTrue( results.isFirst() ); + assertTrue( results.isLast() ); + + assertFalse( results.scroll( i ) ); + assertFalse( results.isFirst() ); + assertFalse( results.isLast() ); + + assertTrue( results.setRowNumber( 1 ) ); + assertTrue( results.isFirst() ); + assertTrue( results.isLast() ); + + assertFalse( results.scroll( -i ) ); + assertFalse( results.isFirst() ); + assertFalse( results.isLast() ); + + if ( i != 1 ) { + assertFalse( results.setRowNumber( i ) ); + assertFalse( results.isFirst() ); + assertFalse( results.isLast() ); + + assertFalse( results.setRowNumber( -i ) ); + assertFalse( results.isFirst() ); + assertFalse( results.isLast() ); + } + } + } + ); + + scope.inTransaction( + session -> { + session.createQuery( "delete Animal where not description like 'root%'" ).executeUpdate(); + session.createQuery( "delete Animal" ).executeUpdate(); + } + ); + } + + @Test + @RequiresDialectFeature( + feature = DialectFeatureChecks.SupportsResultSetPositioningOnForwardOnlyCursorCheck.class, + comment = "Driver does not support result set positioning methods on forward-only cursors" + ) + public void testScrollingJoinFetchesForward(SessionFactoryScope scope) { + TestData data = new TestData(); + data.prepare(scope); + + scope.inTransaction( + s -> { + ScrollableResults results = s + .createQuery( + "from Animal a left join fetch a.offspring where a.description like :desc order by a.id" ) + .setParameter( "desc", "root%" ) + .scroll( ScrollMode.FORWARD_ONLY ); + + int counter = 0; + while ( results.next() ) { + counter++; + Animal animal = (Animal) results.get(); + checkResult( animal ); + } + assertEquals( 2, counter, "unexpected result count" ); + + } + ); + } + + @Test + @RequiresDialectFeature(feature = DialectFeatureChecks.SupportsTemporaryTable.class) + @SkipForDialect(dialectClass = AbstractHANADialect.class, reason = "HANA only supports forward-only cursors.") + public void testScrollingJoinFetchesReverse(SessionFactoryScope scope) { + TestData data = new TestData(); + data.prepare(scope); + + scope.inTransaction( + s -> { + ScrollableResults results = s + .createQuery( + "from Animal a left join fetch a.offspring where a.description like :desc order by a.id" ) + .setParameter( "desc", "root%" ).scroll(); + + results.afterLast(); + + int counter = 0; + while ( results.previous() ) { + counter++; + Animal animal = (Animal) results.get(); + checkResult( animal ); + } + assertEquals( 2, counter, "unexpected result count" ); + + } + ); + } + + @Test + @RequiresDialectFeature(feature = DialectFeatureChecks.SupportsTemporaryTable.class) + @SkipForDialect(dialectClass = AbstractHANADialect.class, reason = "HANA only supports forward-only cursors.") + public void testScrollingJoinFetchesPositioning(SessionFactoryScope scope) { + TestData data = new TestData(); + data.prepare( scope ); + + scope.inTransaction( + session -> { + ScrollableResults results = session + .createQuery( + "from Animal a left join fetch a.offspring where a.description like :desc order by a.id" ) + .setParameter( "desc", "root%" ) + .scroll(); + + results.first(); + Animal animal = (Animal) results.get(); + assertEquals( data.root1Id, animal.getId(), "first() did not return expected row" ); + + results.scroll( 1 ); + animal = (Animal) results.get(); + assertEquals( data.root2Id, animal.getId(), "scroll(1) did not return expected row" ); + + results.scroll( -1 ); + animal = (Animal) results.get(); + assertEquals( data.root1Id, animal.getId(), "scroll(-1) did not return expected row" ); + + results.setRowNumber( 1 ); + animal = (Animal) results.get(); + assertEquals( data.root1Id, animal.getId(), "setRowNumber(1) did not return expected row" ); + + results.setRowNumber( 2 ); + animal = (Animal) results.get(); + assertEquals( data.root2Id, animal.getId(), "setRowNumber(2) did not return expected row" ); + } + ); + } + + @AfterEach + public void tearDown(SessionFactoryScope scope) { + TestData.cleanup( scope ); + } + + private void checkResult(Animal animal) { + if ( "root-1".equals( animal.getDescription() ) ) { + assertEquals( 2, animal.getOffspring().size(), "root-1 did not contain both children" ); + } + else if ( "root-2".equals( animal.getDescription() ) ) { + assertEquals( 0, animal.getOffspring().size(), "root-2 did not contain zero children" ); + } + } + + private static class TestData { + + private Long root1Id; + private Long root2Id; + + private void prepare(SessionFactoryScope scope) { + Animal mother = new Animal(); + Animal another = new Animal(); + scope.inTransaction( + session -> { + mother.setDescription( "root-1" ); + + another.setDescription( "root-2" ); + + Animal son = new Animal(); + son.setDescription( "son" ); + + Animal daughter = new Animal(); + daughter.setDescription( "daughter" ); + + Animal grandson = new Animal(); + grandson.setDescription( "grandson" ); + + Animal grandDaughter = new Animal(); + grandDaughter.setDescription( "granddaughter" ); + + son.setMother( mother ); + mother.addOffspring( son ); + + daughter.setMother( mother ); + mother.addOffspring( daughter ); + + grandson.setMother( daughter ); + daughter.addOffspring( grandson ); + + grandDaughter.setMother( daughter ); + daughter.addOffspring( grandDaughter ); + + session.save( mother ); + session.save( another ); + session.save( son ); + session.save( daughter ); + session.save( grandson ); + session.save( grandDaughter ); + } + ); + + root1Id = mother.getId(); + root2Id = another.getId(); + } + + public static void cleanup(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + session.createQuery( "delete Animal where description like 'grand%'" ).executeUpdate(); + session.createQuery( "delete Animal where not description like 'root%'" ).executeUpdate(); + session.createQuery( "delete Animal" ).executeUpdate(); + } + ); + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/ScrollableCollectionFetchingTest.java b/hibernate-core/src/test/java/org/hibernate/test/hql/ScrollableCollectionFetchingTest.java deleted file mode 100644 index cfcd20aab4..0000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/hql/ScrollableCollectionFetchingTest.java +++ /dev/null @@ -1,427 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.hql; - -import org.hibernate.HibernateException; -import org.hibernate.QueryException; -import org.hibernate.ScrollMode; -import org.hibernate.ScrollableResults; -import org.hibernate.Session; -import org.hibernate.Transaction; -import org.hibernate.dialect.AbstractHANADialect; -import org.hibernate.dialect.SybaseASE15Dialect; - -import org.hibernate.testing.DialectChecks; -import org.hibernate.testing.RequiresDialectFeature; -import org.hibernate.testing.SkipForDialect; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.junit.Test; - -import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -/** - * Tests the new functionality of allowing scrolling of results which - * contain collection fetches. - * - * @author Steve Ebersole - */ -public class ScrollableCollectionFetchingTest extends BaseCoreFunctionalTestCase { - public String[] getMappings() { - return new String[] { "hql/Animal.hbm.xml" }; - } - - @Test - public void testTupleReturnFails() { - Session s = openSession(); - Transaction txn = s.beginTransaction(); - - try { - s.createQuery( "select a, a.weight from Animal a inner join fetch a.offspring" ).scroll(); - fail( "scroll allowed with collection fetch and reurning tuples" ); - } - catch (IllegalArgumentException e) { - assertTyping( QueryException.class, e.getCause() ); - } - catch( HibernateException e ) { - // expected result... - } - - txn.commit(); - s.close(); - } - - @Test - @SkipForDialect(value = SybaseASE15Dialect.class , jiraKey = "HHH-5229") - @SkipForDialect(value = { AbstractHANADialect.class }, comment = "HANA only supports forward-only cursors.") - public void testScrollingJoinFetchesEmptyResultSet() { - inTransaction( - s -> { - final String query = "from Animal a left join fetch a.offspring where a.description like :desc order by a.id"; - - // first, as a control, make sure there are no results - int size = s.createQuery( query ).setParameter( "desc", "root%" ).list().size(); - assertEquals( 0, size ); - - // now get the scrollable results - ScrollableResults results = s.createQuery( query ).setParameter( "desc", "root%" ).scroll(); - - assertFalse( results.isFirst() ); - assertFalse( results.isLast() ); - - assertFalse( results.next() ); - assertFalse( results.isFirst() ); - assertFalse( results.isLast() ); - - assertFalse( results.previous() ); - assertFalse( results.isFirst() ); - assertFalse( results.isLast() ); - - results.beforeFirst(); - assertFalse( results.isFirst() ); - assertFalse( results.isLast() ); - assertFalse( results.next() ); - - assertFalse( results.first() ); - assertFalse( results.isFirst() ); - assertFalse( results.isLast() ); - assertFalse( results.next() ); - - results.afterLast(); - assertFalse( results.isFirst() ); - assertFalse( results.isLast() ); - assertFalse( results.next() ); - - assertFalse( results.last() ); - assertFalse( results.isFirst() ); - assertFalse( results.isLast() ); - assertFalse( results.next() ); - - for ( int i=1; i<3; i++ ) { - assertFalse( results.scroll( i ) ); - assertFalse( results.isFirst() ); - assertFalse( results.isLast() ); - - assertFalse( results.scroll( - i ) ); - assertFalse( results.isFirst() ); - assertFalse( results.isLast() ); - - assertFalse( results.setRowNumber( i ) ); - assertFalse( results.isFirst() ); - assertFalse( results.isLast() ); - - assertFalse( results.setRowNumber( - i ) ); - assertFalse( results.isFirst() ); - assertFalse( results.isLast() ); - } - } - ); - } - - @Test - @RequiresDialectFeature(DialectChecks.SupportsTemporaryTable.class) - @SkipForDialect(value = AbstractHANADialect.class, comment = "HANA only supports forward-only cursors") - public void testScrollingJoinFetchesSingleRowResultSet() { - Session s = openSession(); - Transaction txn = s.beginTransaction(); - - Animal mother = new Animal(); - mother.setDescription( "root-1" ); - - Animal daughter = new Animal(); - daughter.setDescription( "daughter" ); - - daughter.setMother( mother ); - mother.addOffspring( daughter ); - - s.save( mother ); - s.save( daughter ); - - txn.commit(); - s.close(); - - s = openSession(); - txn = s.beginTransaction(); - - assertNotNull(s - .createQuery( "from Animal a left join fetch a.offspring where a.description like :desc order by a.id" ) - .setParameter( "desc", "root%" ) - .uniqueResult() ); - - ScrollableResults results = s - .createQuery( "from Animal a left join fetch a.offspring where a.description like :desc order by a.id" ) - .setParameter( "desc", "root%" ).scroll(); - - assertFalse( results.isFirst() ); - assertFalse( results.isLast() ); - assertFalse( results.previous() ); - - assertTrue( results.next() ); - assertTrue( results.isFirst() ); - assertTrue( results.isLast() ); - - assertFalse( results.next() ); - assertFalse( results.isFirst() ); - assertFalse( results.isLast() ); - - assertTrue( results.previous() ); - assertTrue( results.isFirst() ); - assertTrue( results.isLast() ); - - assertFalse( results.previous() ); - assertFalse( results.isFirst() ); - assertFalse( results.isLast() ); - - assertTrue( results.next() ); - assertTrue( results.isFirst() ); - assertTrue( results.isLast() ); - - results.beforeFirst(); - assertFalse( results.isFirst() ); - assertFalse( results.isLast() ); - assertFalse( results.previous() ); - - assertTrue( results.first() ); - assertTrue( results.isFirst() ); - assertTrue( results.isLast() ); - assertFalse( results.next() ); - - results.afterLast(); - assertFalse( results.isFirst() ); - assertFalse( results.isLast() ); - assertFalse( results.next() ); - - assertTrue( results.last() ); - assertTrue( results.isFirst() ); - assertTrue( results.isLast() ); - assertFalse( results.next() ); - - assertTrue( results.first() ); - assertTrue( results.isFirst() ); - assertTrue( results.isLast() ); - - for ( int i=1; i<3; i++ ) { - assertTrue( results.setRowNumber( 1 ) ); - assertTrue( results.isFirst() ); - assertTrue( results.isLast() ); - - assertFalse( results.scroll( i ) ); - assertFalse( results.isFirst() ); - assertFalse( results.isLast() ); - - assertTrue( results.setRowNumber( 1 ) ); - assertTrue( results.isFirst() ); - assertTrue( results.isLast() ); - - assertFalse( results.scroll( - i ) ); - assertFalse( results.isFirst() ); - assertFalse( results.isLast() ); - - if ( i != 1 ) { - assertFalse( results.setRowNumber( i ) ); - assertFalse( results.isFirst() ); - assertFalse( results.isLast() ); - - assertFalse( results.setRowNumber( - i ) ); - assertFalse( results.isFirst() ); - assertFalse( results.isLast() ); - } - } - - txn.commit(); - s.close(); - - s = openSession(); - txn = s.beginTransaction(); - - s.createQuery( "delete Animal where not description like 'root%'" ).executeUpdate(); - s.createQuery( "delete Animal" ).executeUpdate(); - - txn.commit(); - s.close(); - } - - @Test - @RequiresDialectFeature( - value = DialectChecks.SupportsResultSetPositioningOnForwardOnlyCursorCheck.class, - comment = "Driver does not support result set positioning methods on forward-only cursors" - ) - public void testScrollingJoinFetchesForward() { - TestData data = new TestData(); - data.prepare(); - - inTransaction( - s -> { - ScrollableResults results = s - .createQuery( "from Animal a left join fetch a.offspring where a.description like :desc order by a.id" ) - .setParameter( "desc", "root%" ) - .scroll( ScrollMode.FORWARD_ONLY ); - - int counter = 0; - while ( results.next() ) { - counter++; - Animal animal = ( Animal ) results.get(); - checkResult( animal ); - } - assertEquals( "unexpected result count", 2, counter ); - - } - ); - - data.cleanup(); - } - - @Test - @RequiresDialectFeature(DialectChecks.SupportsTemporaryTable.class) - @SkipForDialect(value = AbstractHANADialect.class, comment = "HANA only supports forward-only cursors.") - public void testScrollingJoinFetchesReverse() { - TestData data = new TestData(); - data.prepare(); - - inTransaction( - s -> { - ScrollableResults results = s - .createQuery( - "from Animal a left join fetch a.offspring where a.description like :desc order by a.id" ) - .setParameter( "desc", "root%" ).scroll(); - - results.afterLast(); - - int counter = 0; - while ( results.previous() ) { - counter++; - Animal animal = ( Animal ) results.get( ); - checkResult( animal ); - } - assertEquals( "unexpected result count", 2, counter ); - - } - ); - - data.cleanup(); - } - - @Test - @RequiresDialectFeature(DialectChecks.SupportsTemporaryTable.class) - @SkipForDialect(value = AbstractHANADialect.class, comment = "HANA only supports forward-only cursors.") - public void testScrollingJoinFetchesPositioning() { - TestData data = new TestData(); - data.prepare(); - - Session s = openSession(); - Transaction txn = s.beginTransaction(); - - ScrollableResults results = s - .createQuery( "from Animal a left join fetch a.offspring where a.description like :desc order by a.id" ) - .setParameter( "desc", "root%" ) - .scroll(); - - results.first(); - Animal animal = ( Animal ) results.get( ); - assertEquals( "first() did not return expected row", data.root1Id, animal.getId() ); - - results.scroll( 1 ); - animal = ( Animal ) results.get( ); - assertEquals( "scroll(1) did not return expected row", data.root2Id, animal.getId() ); - - results.scroll( -1 ); - animal = ( Animal ) results.get( ); - assertEquals( "scroll(-1) did not return expected row", data.root1Id, animal.getId() ); - - results.setRowNumber( 1 ); - animal = ( Animal ) results.get(); - assertEquals( "setRowNumber(1) did not return expected row", data.root1Id, animal.getId() ); - - results.setRowNumber( 2 ); - animal = ( Animal ) results.get(); - assertEquals( "setRowNumber(2) did not return expected row", data.root2Id, animal.getId() ); - - txn.commit(); - s.close(); - - data.cleanup(); - } - - private void checkResult(Animal animal) { - if ( "root-1".equals( animal.getDescription() ) ) { - assertEquals( "root-1 did not contain both children", 2, animal.getOffspring().size() ); - } - else if ( "root-2".equals( animal.getDescription() ) ) { - assertEquals( "root-2 did not contain zero children", 0, animal.getOffspring().size() ); - } - } - - private class TestData { - - private Long root1Id; - private Long root2Id; - - private void prepare() { - Session s = openSession(); - Transaction txn = s.beginTransaction(); - - Animal mother = new Animal(); - mother.setDescription( "root-1" ); - - Animal another = new Animal(); - another.setDescription( "root-2" ); - - Animal son = new Animal(); - son.setDescription( "son"); - - Animal daughter = new Animal(); - daughter.setDescription( "daughter" ); - - Animal grandson = new Animal(); - grandson.setDescription( "grandson" ); - - Animal grandDaughter = new Animal(); - grandDaughter.setDescription( "granddaughter" ); - - son.setMother( mother ); - mother.addOffspring( son ); - - daughter.setMother( mother ); - mother.addOffspring( daughter ); - - grandson.setMother( daughter ); - daughter.addOffspring( grandson ); - - grandDaughter.setMother( daughter ); - daughter.addOffspring( grandDaughter ); - - s.save( mother ); - s.save( another ); - s.save( son ); - s.save( daughter ); - s.save( grandson ); - s.save( grandDaughter ); - - txn.commit(); - s.close(); - - root1Id = mother.getId(); - root2Id = another.getId(); - } - - private void cleanup() { - Session s = openSession(); - Transaction txn = s.beginTransaction(); - - s.createQuery( "delete Animal where description like 'grand%'" ).executeUpdate(); - s.createQuery( "delete Animal where not description like 'root%'" ).executeUpdate(); - s.createQuery( "delete Animal" ).executeUpdate(); - - txn.commit(); - s.close(); - } - } -}