diff --git a/src/main/java/io/ebeaninternal/server/query/CQuery.java b/src/main/java/io/ebeaninternal/server/query/CQuery.java index eca6e71ec..98ace2aa5 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQuery.java +++ b/src/main/java/io/ebeaninternal/server/query/CQuery.java @@ -36,6 +36,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; /** * An object that represents a SqlSelect statement. @@ -421,6 +422,7 @@ public class CQuery implements DbReadContext, CancelableQuery { if (!moveToNextRow()) { if (currentBean == null) { + nextBean = null; return false; } else { // the last bean @@ -508,6 +510,9 @@ public class CQuery implements DbReadContext, CancelableQuery { auditIterateNextBean(); } hasNextCache = false; + if (nextBean == null) { + throw new NoSuchElementException(); + } return nextBean; } diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryIteratorSimple.java b/src/main/java/io/ebeaninternal/server/query/CQueryIteratorSimple.java index a113cf760..fb434a6de 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQueryIteratorSimple.java +++ b/src/main/java/io/ebeaninternal/server/query/CQueryIteratorSimple.java @@ -14,6 +14,8 @@ class CQueryIteratorSimple implements QueryIterator { private final CQuery cquery; private final OrmQueryRequest request; + + private boolean closed; CQueryIteratorSimple(CQuery cquery, OrmQueryRequest request) { this.cquery = cquery; @@ -22,11 +24,17 @@ class CQueryIteratorSimple implements QueryIterator { @Override public boolean hasNext() { + boolean ret = false; try { request.flushPersistenceContextOnIterate(); - return cquery.hasNext(); + ret = cquery.hasNext(); + return ret; } catch (SQLException e) { throw cquery.createPersistenceException(e); + } finally { + if (!ret) { + close(); + } } } @@ -38,9 +46,12 @@ class CQueryIteratorSimple implements QueryIterator { @Override public void close() { - cquery.updateExecutionStatisticsIterator(); - cquery.close(); - request.endTransIfRequired(); + if (!closed) { + closed = true; + cquery.updateExecutionStatisticsIterator(); + cquery.close(); + request.endTransIfRequired(); + } } @Override diff --git a/src/test/java/org/tests/query/TestQueryFindIterate.java b/src/test/java/org/tests/query/TestQueryFindIterate.java index 6d17d5599..6600315e3 100644 --- a/src/test/java/org/tests/query/TestQueryFindIterate.java +++ b/src/test/java/org/tests/query/TestQueryFindIterate.java @@ -9,16 +9,17 @@ import org.tests.model.basic.Customer; import org.tests.model.basic.Order; import org.tests.model.basic.OrderShipment; import org.tests.model.basic.ResetBasicData; +import org.avaje.datasource.DataSourcePool; import org.ebeantest.LoggedSqlCollector; import org.junit.Test; import javax.persistence.PersistenceException; import java.util.List; +import java.util.NoSuchElementException; import java.util.concurrent.atomic.AtomicInteger; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; public class TestQueryFindIterate extends BaseTestCase { @@ -224,4 +225,39 @@ public class TestQueryFindIterate extends BaseTestCase { } }); } + + @Test + public void testCloseConnection() throws Exception { + ResetBasicData.reset(); + DataSourcePool dsPool = (DataSourcePool) server().getPluginApi().getDataSource(); + int startConns = dsPool.getStatus(false).getBusy(); + QueryIterator queryIterator = server().find(Customer.class) + .where() + .isNotNull("name") + .setMaxRows(3) + .order().asc("id") + .findIterate(); + + assertThat(dsPool.getStatus(false).getBusy()).isEqualTo(startConns + 1); + + assertTrue(queryIterator.hasNext()); + assertThat(queryIterator.next()).isNotNull(); + assertThat(dsPool.getStatus(false).getBusy()).isEqualTo(startConns + 1); + + assertTrue(queryIterator.hasNext()); + assertThat(queryIterator.next()).isNotNull(); + assertThat(dsPool.getStatus(false).getBusy()).isEqualTo(startConns + 1); + + assertTrue(queryIterator.hasNext()); + assertThat(queryIterator.next()).isNotNull(); + assertThat(dsPool.getStatus(false).getBusy()).isEqualTo(startConns + 1); + + assertFalse(queryIterator.hasNext()); + assertThat(dsPool.getStatus(false).getBusy()).isEqualTo(startConns); + try { + queryIterator.next(); + fail("noSuchElementException expected"); + } catch (NoSuchElementException e) {} + + } }