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 <stari...@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; + } }