Index: modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2ResultSetIterator.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2ResultSetIterator.java (date 1534181983000) +++ modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2ResultSetIterator.java (date 1534248021992) @@ -22,6 +22,7 @@ import java.sql.SQLException; import java.util.NoSuchElementException; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.IgniteException; import org.apache.ignite.internal.processors.query.IgniteSQLException; import org.apache.ignite.internal.processors.query.h2.opt.GridH2ValueCacheObject; import org.apache.ignite.internal.util.GridCloseableIteratorAdapter; @@ -56,10 +57,10 @@ private static final long serialVersionUID = 0L; /** */ - private final ResultInterface res; + private ResultInterface res; /** */ - private final ResultSet data; + private ResultSet data; /** */ protected final Object[] row; @@ -107,8 +108,10 @@ return false; try { - if (!data.next()) + if (!data.next()){ + onClose(); return false; + } if (res != null) { Value[] values = res.currentRow(); @@ -135,6 +138,9 @@ catch (SQLException e) { throw new IgniteSQLException(e); } + catch (IgniteCheckedException e) { + throw new IgniteException(e); + } } /** {@inheritDoc} */ @@ -179,6 +185,8 @@ } U.closeQuiet(data); + res = null; + data = null; } /** {@inheritDoc} */ Index: modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/H2ResultSetIteratorNullifyOnEnd.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/H2ResultSetIteratorNullifyOnEnd.java (date 1534248021999) +++ modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/H2ResultSetIteratorNullifyOnEnd.java (date 1534248021999) @@ -0,0 +1,155 @@ +package org.apache.ignite.internal.processors.query.h2; + +import java.util.Collections; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteCache; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.cache.query.annotations.QuerySqlField; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.internal.processors.query.GridQueryProcessor; +import org.apache.ignite.internal.util.lang.GridCloseableIterator; +import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; + +/** + * Test for iterator data link erasure after closing or completing + */ +public class H2ResultSetIteratorNullifyOnEnd extends GridCommonAbstractTest { + /** */ + private static final int NODES_COUNT = 2; + /** */ + private static final int PERSON_COUNT = 20; + /** */ + private static final String SELECT_ALL_SQL = "select * from Person"; + /** */ + private IgniteCache personCache; + /** */ + private IgniteH2Indexing h2Idx; + + /** + * on close should remove links to data + */ + public void testOnClose() { + try { + GridCloseableIterator it = h2Idx.queryLocalSql( + h2Idx.schema(personCache.getName()), + personCache.getName(), + SELECT_ALL_SQL, + null, + Collections.emptySet(), + "Person", + null, + null); + if(H2ResultSetIterator.class.isAssignableFrom(it.getClass())){ + H2ResultSetIterator h2it = (H2ResultSetIterator)it; + try { + h2it.onClose(); + } + catch (IgniteCheckedException e) { + fail(e.getMessage()); + } + assertNull(GridTestUtils.getFieldValue(h2it, H2ResultSetIterator.class, "data")); + }else + fail(); + } + catch (IgniteCheckedException e) { + fail(e.getMessage()); + } + } + /** + * complete iterate should remove links to data + */ + public void testOnComplete() { + try { + GridCloseableIterator it = h2Idx.queryLocalSql( + h2Idx.schema(personCache.getName()), + personCache.getName(), + SELECT_ALL_SQL, + null, + Collections.emptySet(), + "Person", + null, + null); + if(H2ResultSetIterator.class.isAssignableFrom(it.getClass())){ + H2ResultSetIterator h2it = (H2ResultSetIterator)it; + while( h2it.onHasNext()) + h2it.onNext(); + assertNull(GridTestUtils.getFieldValue(h2it, H2ResultSetIterator.class, "data")); + }else + fail(); + } + catch (IgniteCheckedException e) { + fail(e.getMessage()); + } + } + /** {@inheritDoc} */ + @Override protected void beforeTest() throws Exception { + final Ignite ignite = startGridsMultiThreaded(NODES_COUNT, false); + final GridQueryProcessor qryProc = grid(ignite.name()).context().query(); + h2Idx = GridTestUtils.getFieldValue(qryProc, GridQueryProcessor.class, "idx"); + + personCache = ignite(0).getOrCreateCache(new CacheConfiguration("pers") + .setIndexedTypes(String.class, Person.class)); + + awaitPartitionMapExchange(); + + populateDataIntoPerson(personCache); + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + stopAllGrids(); + } + + /** + * Populate person cache with test data + * @param cache @{IgniteCache} + */ + private void populateDataIntoPerson(IgniteCache cache) { + int personId = 0; + for (int j = 0; j < PERSON_COUNT; j++) { + Person prsn = new Person(); + prsn.setId("pers" + personId); + prsn.setName("Person name #" + personId); + cache.put(prsn.getId(), prsn); + personId++; + } + } + + /** + * + */ + private static class Person { + /** */ + @QuerySqlField(index = true) + private String id; + + /** */ + @QuerySqlField(index = true) + private String name; + + /** */ + public String getId() { + + return id; + } + + /** */ + public void setId(String id) { + + this.id = id; + } + + /** */ + public String getName() { + + return name; + } + + /** */ + public void setName(String name) { + + this.name = name; + } + } +}