diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java b/jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java index f9dfe20e06..1b97131a90 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java @@ -143,6 +143,7 @@ abstract class AbstractResultQuery extends AbstractQuery imple private transient boolean lazy; private transient boolean many; private transient Cursor cursor; + private transient boolean autoclosing = true; private Result result; private ResultsImpl results; @@ -316,7 +317,7 @@ abstract class AbstractResultQuery extends AbstractQuery imple } Field[] fields = getFields(ctx.resultSet().getMetaData()); - cursor = new CursorImpl(ctx, listener, fields, intern.internIndexes(fields), keepStatement(), keepResultSet(), getRecordType(), SettingsTools.getMaxRows(maxRows, ctx.settings())); + cursor = new CursorImpl(ctx, listener, fields, intern.internIndexes(fields), keepStatement(), keepResultSet(), getRecordType(), SettingsTools.getMaxRows(maxRows, ctx.settings()), autoclosing); if (!lazy) { result = cursor.fetch(); @@ -386,7 +387,7 @@ abstract class AbstractResultQuery extends AbstractQuery imple try { if (c == null) - c = fetchLazy(); + c = fetchLazyNonAutoClosing(); if (buffer == null) buffer = new ArrayDeque(); @@ -457,7 +458,7 @@ abstract class AbstractResultQuery extends AbstractQuery imple @Override public final X collect(Collector collector) { - try (Cursor c = fetchLazy()) { + try (Cursor c = fetchLazyNonAutoClosing()) { return c.collect(collector); } } @@ -469,6 +470,24 @@ abstract class AbstractResultQuery extends AbstractQuery imple return fetchLazy(fetchSize); } + /** + * When we manage the lifecycle of a returned {@link Cursor} internally in + * jOOQ, then the cursor must not be auto-closed. + */ + final Cursor fetchLazyNonAutoClosing() { + final boolean previousAutoClosing = autoclosing; + + // [#3515] TODO: Avoid modifying a Query's per-execution state + autoclosing = false; + + try { + return fetchLazy(); + } + finally { + autoclosing = previousAutoClosing; + } + } + @Override @Deprecated public final Cursor fetchLazy(int size) { @@ -631,7 +650,7 @@ abstract class AbstractResultQuery extends AbstractQuery imple @Override public final R fetchOne() { - return Tools.fetchOne(fetchLazy(), hasLimit1()); + return Tools.fetchOne(fetchLazyNonAutoClosing(), hasLimit1()); } @Override @@ -726,7 +745,7 @@ abstract class AbstractResultQuery extends AbstractQuery imple @Override public final R fetchSingle() { - return Tools.fetchSingle(fetchLazy(), hasLimit1()); + return Tools.fetchSingle(fetchLazyNonAutoClosing(), hasLimit1()); } @Override @@ -912,7 +931,7 @@ abstract class AbstractResultQuery extends AbstractQuery imple @Override public final R fetchAny() { - Cursor c = fetchLazy(); + Cursor c = fetchLazyNonAutoClosing(); try { return c.fetchNext(); diff --git a/jOOQ/src/main/java/org/jooq/impl/CursorImpl.java b/jOOQ/src/main/java/org/jooq/impl/CursorImpl.java index 6087ea9c61..db426f9921 100644 --- a/jOOQ/src/main/java/org/jooq/impl/CursorImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/CursorImpl.java @@ -104,6 +104,7 @@ final class CursorImpl extends AbstractCursor implements Cu private final boolean[] intern; private final boolean keepResultSet; private final boolean keepStatement; + private final boolean autoclosing; private final int maxRows; private final RecordFactory factory; private boolean isClosed; @@ -123,10 +124,10 @@ final class CursorImpl extends AbstractCursor implements Cu @SuppressWarnings("unchecked") CursorImpl(ExecuteContext ctx, ExecuteListener listener, Field[] fields, int[] internIndexes, boolean keepStatement, boolean keepResultSet) { - this(ctx, listener, fields, internIndexes, keepStatement, keepResultSet, (Class) RecordImpl.class, 0); + this(ctx, listener, fields, internIndexes, keepStatement, keepResultSet, (Class) RecordImpl.class, 0, true); } - CursorImpl(ExecuteContext ctx, ExecuteListener listener, Field[] fields, int[] internIndexes, boolean keepStatement, boolean keepResultSet, Class type, int maxRows) { + CursorImpl(ExecuteContext ctx, ExecuteListener listener, Field[] fields, int[] internIndexes, boolean keepStatement, boolean keepResultSet, Class type, int maxRows, boolean autoclosing) { super(ctx.configuration(), new Fields(fields)); this.ctx = ctx; @@ -142,6 +143,7 @@ final class CursorImpl extends AbstractCursor implements Cu this.maxRows = maxRows; this.lockRowsForUpdate = TRUE.equals(ctx.data(DATA_LOCK_ROWS_FOR_UPDATE)); + this.autoclosing = autoclosing; if (internIndexes != null) { this.intern = new boolean[fields.length]; @@ -1630,10 +1632,10 @@ final class CursorImpl extends AbstractCursor implements Cu throw ctx.exception(); } - // [#1868] [#2373] [#2385] This calls through to Utils.safeClose() - // if necessary, lazy-terminating the ExecuteListener lifecycle if - // the result is not eager-fetched. - if (record == null) { + // [#1868] [#2373] [#2385] [#8544] This calls through to + // Utils.safeClose() if necessary, lazy-terminating the ExecuteListener + // lifecycle if the result is not eager-fetched. + if (record == null && autoclosing) { CursorImpl.this.close(); }