This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch STABLE-4.2
in repository https://gitbox.apache.org/repos/asf/cayenne.git


The following commit(s) were added to refs/heads/STABLE-4.2 by this push:
     new 016406675 CAY-2988 Nested iterated queries transaction handling
016406675 is described below

commit 0164066751f0b287929d4187a21718ecc0380ea7
Author: Andrus Adamchik <[email protected]>
AuthorDate: Mon Aug 17 12:54:56 2026 -0400

    CAY-2988 Nested iterated queries transaction handling
    
    a test from 5.x... should not fail on 4.2
---
 .../cayenne/access/DataContextIteratedQueryIT.java | 58 ++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextIteratedQueryIT.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextIteratedQueryIT.java
index 8853c8c0d..b50f12d07 100644
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextIteratedQueryIT.java
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextIteratedQueryIT.java
@@ -27,7 +27,9 @@ import org.apache.cayenne.test.jdbc.DBHelper;
 import org.apache.cayenne.test.jdbc.TableHelper;
 import org.apache.cayenne.testdo.testmap.Artist;
 import org.apache.cayenne.testdo.testmap.Painting;
+import org.apache.cayenne.configuration.server.ServerRuntime;
 import org.apache.cayenne.tx.BaseTransaction;
+import org.apache.cayenne.tx.TransactionManager;
 import org.apache.cayenne.unit.di.server.CayenneProjects;
 import org.apache.cayenne.unit.di.server.ServerCase;
 import org.apache.cayenne.unit.di.server.UseServerRuntime;
@@ -39,6 +41,7 @@ import java.util.List;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 @UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
 public class DataContextIteratedQueryIT extends ServerCase {
@@ -46,6 +49,8 @@ public class DataContextIteratedQueryIT extends ServerCase {
     @Inject
     protected DBHelper dbHelper;
     @Inject
+    private ServerRuntime runtime;
+    @Inject
     private DataContext context;
     private TableHelper tArtist;
     private TableHelper tExhibit;
@@ -217,4 +222,57 @@ public class DataContextIteratedQueryIT extends ServerCase 
{
 
         // TODO: how do we test that transaction unbound from the thread is 
closed/committed at the end?
     }
+
+    @Test
+    public void testIterator_CallerTransaction() throws Exception {
+        createArtistsDataSet();
+
+        TransactionManager txManager = 
runtime.getInjector().getInstance(TransactionManager.class);
+
+        int count = txManager.performInTransaction(() -> {
+            int c = 0;
+            try (ResultIterator<Artist> it = 
ObjectSelect.query(Artist.class).iterator(context)) {
+                while (it.hasNextRow()) {
+                    it.nextRow();
+                    c++;
+                }
+            }
+
+            // The caller transaction must survive the iterator, as the 
iterator doesn't own it. A committed
+            // transaction would refuse to open a connection for the query 
below.
+            assertNotNull("Caller transaction was unbound by the iterator", 
BaseTransaction.getThreadTransaction());
+            assertEquals(7, 
ObjectSelect.query(Artist.class).select(context).size());
+            return c;
+        });
+
+        assertEquals(7, count);
+    }
+
+    @Test
+    public void testIterator_NestedIteratorInCallerTransaction() throws 
Exception {
+        createArtistsAndPaintingsDataSet();
+
+        TransactionManager txManager = 
runtime.getInjector().getInstance(TransactionManager.class);
+
+        int count = txManager.performInTransaction(() -> {
+            int c = 0;
+            try (ResultIterator<Artist> outer = 
ObjectSelect.query(Artist.class).iterator(context)) {
+
+                // open and close a nested iterator over another entity while 
"outer" is still open. Closing it
+                // must not commit the caller transaction, as that would close 
the "outer" ResultSet as well
+                assertTrue(outer.hasNextRow());
+                try (ResultIterator<Painting> inner = 
ObjectSelect.query(Painting.class).iterator(context)) {
+                    assertEquals(7, inner.allRows().size());
+                }
+
+                while (outer.hasNextRow()) {
+                    outer.nextRow();
+                    c++;
+                }
+            }
+            return c;
+        });
+
+        assertEquals(7, count);
+    }
 }

Reply via email to