You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2023/11/09 14:08:04 UTC

(cayenne) 02/02: CAY-2819 `DataContext.performIteratedQuery()` method should be unified with `iterator()` method

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

ntimofeev pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git

commit b72b1f4f8be3ee22e09ae4300ff696af6081adf6
Author: stariy95 <st...@gmail.com>
AuthorDate: Thu Nov 9 18:07:33 2023 +0400

    CAY-2819 `DataContext.performIteratedQuery()` method should be unified with `iterator()` method
---
 RELEASE-NOTES.txt                                  |  1 +
 .../org/apache/cayenne/access/DataContext.java     | 95 +++++++---------------
 .../cayenne/access/DataDomainQueryAction.java      |  1 +
 .../cayenne/query/IteratedQueryDecorator.java      | 17 +++-
 4 files changed, 44 insertions(+), 70 deletions(-)

diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index e1ef21051..8d74cc967 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -41,6 +41,7 @@ CAY-2802 Upgrade Gradle to 7.6.1
 CAY-2803 Test infrastructure: declarative custom DI modules in ServerCase
 CAY-2805 Stop calling exp parser internally
 CAY-2817 Pagination flow refactoring
+CAY-2819 DataContext.performIteratedQuery() method should be unified with iterator() method
 
 Bug Fixes:
 
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataContext.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataContext.java
index ec930c81a..4206edfd5 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataContext.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/DataContext.java
@@ -792,84 +792,45 @@ public class DataContext extends BaseContext {
 
     }
 
-    @SuppressWarnings("unchecked")
+    /**
+     * Performs a single database select query returning result as a {@link ResultIterator}.
+     * <p>
+     * It is caller's responsibility to explicitly close the {@link ResultIterator}.
+     * A failure to do so will result in a <b>database connection not being released</b>.
+     * Another side effect of an open {@link ResultIterator} is that an internal Cayenne transaction
+     * that originated in this method stays open until the iterator is closed.
+     * So users should normally close the iterator within the same thread that opened it.
+     * <p>
+     */
     @Override
     public <T> ResultIterator<T> iterator(final Select<T> query) {
-        IteratedQueryDecorator queryDecorator = new IteratedQueryDecorator(query);
-        Query queryToRun = nonNullDelegate().willPerformQuery(this, queryDecorator);
-        QueryResponse queryResponse = onQuery(this, queryToRun);
-        return (ResultIterator<T>) queryResponse.firstIterator();
+        return performIteratedQueryInternal(query, false);
     }
 
     /**
-     * Performs a single database select query returning result as a
-     * ResultIterator. It is caller's responsibility to explicitly close the
-     * ResultIterator. A failure to do so will result in a database connection
-     * not being released. Another side effect of an open ResultIterator is that
-     * an internal Cayenne transaction that originated in this method stays open
-     * until the iterator is closed. So users should normally close the iterator
-     * within the same thread that opened it.
+     * Performs a single database select query returning result as a {@link ResultIterator}.
+     * <p>
+     * It is caller's responsibility to explicitly close the {@link ResultIterator}.
+     * A failure to do so will result in a <b>database connection not being released</b>.
+     * Another side effect of an open {@link ResultIterator} is that an internal Cayenne transaction
+     * that originated in this method stays open until the iterator is closed.
+     * So users should normally close the iterator within the same thread that opened it.
      * <p>
-     * Note that 'performIteratedQuery' always returns ResultIterator over
-     * DataRows. Use
-     * {@link #iterate(Select, org.apache.cayenne.ResultIteratorCallback)} to
-     * get access to objects.
+     * Note that {@code performIteratedQuery} always returns {@link ResultIterator} over DataRows.
+     * <p>
+     * Use {@link #iterate(Select, org.apache.cayenne.ResultIteratorCallback)} to get access to objects.
      */
-    // TODO: deprecate once all selecting queries start implementing Select<T> interface
     @SuppressWarnings({ "rawtypes" })
     public ResultIterator performIteratedQuery(Query query) {
-
-        if (BaseTransaction.getThreadTransaction() != null) {
-            return internalPerformIteratedQuery(query);
-        } else {
-
-
-            // can't use TransactionManger here as it would attempt to commit the transaction at the end...
-
-            // manually manage a transaction, so that a ResultIterator wrapper
-            // could close it when it is done.
-            Transaction tx = getTransactionFactory().createTransaction();
-            BaseTransaction.bindThreadTransaction(tx);
-
-            ResultIterator<?> result;
-            try {
-                result = internalPerformIteratedQuery(query);
-            } catch (Exception e) {
-
-                tx.setRollbackOnly();
-                throw new CayenneRuntimeException(e);
-            } finally {
-
-                // unbind thread tx before returning to the caller. Transaction will be managed internally by the
-                // ResultIterator and should not get in the way of other DB operations that may be performed
-                // within the iterator....
-
-                // TODO: there was an older comment about Ingres breaking when we unbind thread transaction
-                // before closing the iterator. As we have no test environment for ingres, we can't
-                // confirm this here...
-                BaseTransaction.bindThreadTransaction(null);
-
-                if (tx.isRollbackOnly()) {
-                    try {
-                        tx.rollback();
-                    } catch (Exception ignored) {
-                    }
-                }
-            }
-
-            return new TransactionResultIteratorDecorator<>(result, tx);
-        }
+        return performIteratedQueryInternal(query, true);
     }
 
-    /**
-     * Runs an iterated query in a transactional context provided by the caller.
-     */
-    ResultIterator <?> internalPerformIteratedQuery(Query query) {
-        // note that for now DataChannel API does not support cursors (aka
-        // ResultIterator), so we have to go directly to the DataDomain.
-        IteratedSelectObserver observer = new IteratedSelectObserver();
-        getParentDataDomain().performQueries(Collections.singletonList(query), observer);
-        return observer.getResultIterator();
+    @SuppressWarnings("unchecked")
+    private <T> ResultIterator<T> performIteratedQueryInternal(Query query, boolean fetchDataRows) {
+        IteratedQueryDecorator queryDecorator = new IteratedQueryDecorator(query, fetchDataRows);
+        Query queryToRun = nonNullDelegate().willPerformQuery(this, queryDecorator);
+        QueryResponse queryResponse = onQuery(this, queryToRun);
+        return (ResultIterator<T>)queryResponse.firstIterator();
     }
 
     /**
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java
index e6778c442..22f07a2da 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java
@@ -146,6 +146,7 @@ class DataDomainQueryAction implements QueryRouter, OperationObserver {
 
     private boolean interceptIteratedQuery() {
         if (query instanceof IteratedQueryDecorator) {
+            noObjectConversion = ((IteratedQueryDecorator) query).isFetchingDataRows();
             validateIteratedQuery();
             performIteratedQuery();
             return DONE;
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/query/IteratedQueryDecorator.java b/cayenne-server/src/main/java/org/apache/cayenne/query/IteratedQueryDecorator.java
index 9093bd7f9..bbb2e318e 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/query/IteratedQueryDecorator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/query/IteratedQueryDecorator.java
@@ -21,12 +21,19 @@ package org.apache.cayenne.query;
 
 import org.apache.cayenne.map.EntityResolver;
 
-public class IteratedQueryDecorator implements Query{
+/**
+ * A simple decorator for an iterated query.
+ * @see org.apache.cayenne.access.DataContext#iterator(Select)
+ * @since 5.0
+ */
+public class IteratedQueryDecorator implements Query {
 
     private final Query query;
+    private final boolean fetchDataRows;
 
-    public IteratedQueryDecorator(Query query) {
+    public IteratedQueryDecorator(Query query, boolean fetchDataRows) {
         this.query = query;
+        this.fetchDataRows = fetchDataRows;
     }
 
     @Override
@@ -36,7 +43,7 @@ public class IteratedQueryDecorator implements Query{
 
     @Override
     public void route(QueryRouter router, EntityResolver resolver, Query substitutedQuery) {
-        query.route(router,resolver,substitutedQuery);
+        query.route(router, resolver, substitutedQuery);
     }
 
     @Override
@@ -47,4 +54,8 @@ public class IteratedQueryDecorator implements Query{
     public Query getQuery() {
         return query;
     }
+
+    public boolean isFetchingDataRows() {
+        return fetchDataRows;
+    }
 }