From 48e882081e1a16ddb2d9b0faff4192a2ee10a096 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Wed, 19 May 2021 11:09:03 +0200 Subject: [PATCH] [jOOQ/jOOQ#11892] Add Settings.fetchIntermediateResult --- .../jooq/conf/FetchIntermediateResult.java | 39 +++++++++++ .../src/main/java/org/jooq/conf/Settings.java | 66 +++++++++++++++++++ .../java/org/jooq/conf/SettingsTools.java | 20 ++++++ .../java/org/jooq/impl/ResultQueryTrait.java | 13 +++- .../resources/xsd/jooq-runtime-3.15.0.xsd | 27 ++++++++ 5 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 jOOQ/src/main/java/org/jooq/conf/FetchIntermediateResult.java diff --git a/jOOQ/src/main/java/org/jooq/conf/FetchIntermediateResult.java b/jOOQ/src/main/java/org/jooq/conf/FetchIntermediateResult.java new file mode 100644 index 0000000000..9aafb4d924 --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/conf/FetchIntermediateResult.java @@ -0,0 +1,39 @@ + +package org.jooq.conf; + +import javax.xml.bind.annotation.XmlEnum; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for FetchIntermediateResult. + * + *

The following schema fragment specifies the expected content contained within this class. + *

+ * <simpleType name="FetchIntermediateResult">
+ *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
+ *     <enumeration value="ALWAYS"/>
+ *     <enumeration value="WHEN_EXECUTE_LISTENERS_PRESENT"/>
+ *     <enumeration value="WHEN_RESULT_REQUESTED"/>
+ *   </restriction>
+ * </simpleType>
+ * 
+ * + */ +@XmlType(name = "FetchIntermediateResult") +@XmlEnum +public enum FetchIntermediateResult { + + ALWAYS, + WHEN_EXECUTE_LISTENERS_PRESENT, + WHEN_RESULT_REQUESTED; + + public String value() { + return name(); + } + + public static FetchIntermediateResult fromValue(String v) { + return valueOf(v); + } + +} diff --git a/jOOQ/src/main/java/org/jooq/conf/Settings.java b/jOOQ/src/main/java/org/jooq/conf/Settings.java index f08180dd25..f09eea4e72 100644 --- a/jOOQ/src/main/java/org/jooq/conf/Settings.java +++ b/jOOQ/src/main/java/org/jooq/conf/Settings.java @@ -106,6 +106,9 @@ public class Settings protected Boolean bindOffsetTimeType = false; @XmlElement(defaultValue = "true") protected Boolean fetchTriggerValuesAfterSQLServerOutput = true; + @XmlElement(defaultValue = "WHEN_RESULT_REQUESTED") + @XmlSchemaType(name = "string") + protected FetchIntermediateResult fetchIntermediateResult = FetchIntermediateResult.WHEN_RESULT_REQUESTED; @XmlElement(defaultValue = "false") protected Boolean transformAnsiJoinToTableLists = false; @XmlElement(defaultValue = "WHEN_NEEDED") @@ -1020,6 +1023,40 @@ public class Settings this.fetchTriggerValuesAfterSQLServerOutput = value; } + /** + * Whether to fetch data into intermediate {@link org.jooq.Result} instances. + *

+ * By default, a {@link org.jooq.ResultQuery} produces no intermediate {@link org.jooq.Result} + * instances if they are not explicitly requested by the caller, e.g. by calling + * {@link org.jooq.ResultQuery#fetch()}, or in the presence of {@link org.jooq.ExecuteListener} + * instances, which may require access to {@link org.jooq.ExecuteContext#result()}. + * This default behaviour helps avoid unnecessary allocations of possibly large data structures. + *

+ * Using this flag, fetching of intermediate results can be turned off even when execute listeners + * are present, or turned on even if they're absent. + * + */ + public FetchIntermediateResult getFetchIntermediateResult() { + return fetchIntermediateResult; + } + + /** + * Whether to fetch data into intermediate {@link org.jooq.Result} instances. + *

+ * By default, a {@link org.jooq.ResultQuery} produces no intermediate {@link org.jooq.Result} + * instances if they are not explicitly requested by the caller, e.g. by calling + * {@link org.jooq.ResultQuery#fetch()}, or in the presence of {@link org.jooq.ExecuteListener} + * instances, which may require access to {@link org.jooq.ExecuteContext#result()}. + * This default behaviour helps avoid unnecessary allocations of possibly large data structures. + *

+ * Using this flag, fetching of intermediate results can be turned off even when execute listeners + * are present, or turned on even if they're absent. + * + */ + public void setFetchIntermediateResult(FetchIntermediateResult value) { + this.fetchIntermediateResult = value; + } + /** * Transform ANSI join to table lists if possible. *

@@ -3123,6 +3160,24 @@ public class Settings return this; } + /** + * Whether to fetch data into intermediate {@link org.jooq.Result} instances. + *

+ * By default, a {@link org.jooq.ResultQuery} produces no intermediate {@link org.jooq.Result} + * instances if they are not explicitly requested by the caller, e.g. by calling + * {@link org.jooq.ResultQuery#fetch()}, or in the presence of {@link org.jooq.ExecuteListener} + * instances, which may require access to {@link org.jooq.ExecuteContext#result()}. + * This default behaviour helps avoid unnecessary allocations of possibly large data structures. + *

+ * Using this flag, fetching of intermediate results can be turned off even when execute listeners + * are present, or turned on even if they're absent. + * + */ + public Settings withFetchIntermediateResult(FetchIntermediateResult value) { + setFetchIntermediateResult(value); + return this; + } + public Settings withTransformAnsiJoinToTableLists(Boolean value) { setTransformAnsiJoinToTableLists(value); return this; @@ -3894,6 +3949,7 @@ public class Settings builder.append("bindOffsetDateTimeType", bindOffsetDateTimeType); builder.append("bindOffsetTimeType", bindOffsetTimeType); builder.append("fetchTriggerValuesAfterSQLServerOutput", fetchTriggerValuesAfterSQLServerOutput); + builder.append("fetchIntermediateResult", fetchIntermediateResult); builder.append("transformAnsiJoinToTableLists", transformAnsiJoinToTableLists); builder.append("transformInConditionSubqueryWithLimitToDerivedTable", transformInConditionSubqueryWithLimitToDerivedTable); builder.append("transformQualify", transformQualify); @@ -4265,6 +4321,15 @@ public class Settings return false; } } + if (fetchIntermediateResult == null) { + if (other.fetchIntermediateResult!= null) { + return false; + } + } else { + if (!fetchIntermediateResult.equals(other.fetchIntermediateResult)) { + return false; + } + } if (transformAnsiJoinToTableLists == null) { if (other.transformAnsiJoinToTableLists!= null) { return false; @@ -5102,6 +5167,7 @@ public class Settings result = ((prime*result)+((bindOffsetDateTimeType == null)? 0 :bindOffsetDateTimeType.hashCode())); result = ((prime*result)+((bindOffsetTimeType == null)? 0 :bindOffsetTimeType.hashCode())); result = ((prime*result)+((fetchTriggerValuesAfterSQLServerOutput == null)? 0 :fetchTriggerValuesAfterSQLServerOutput.hashCode())); + result = ((prime*result)+((fetchIntermediateResult == null)? 0 :fetchIntermediateResult.hashCode())); result = ((prime*result)+((transformAnsiJoinToTableLists == null)? 0 :transformAnsiJoinToTableLists.hashCode())); result = ((prime*result)+((transformInConditionSubqueryWithLimitToDerivedTable == null)? 0 :transformInConditionSubqueryWithLimitToDerivedTable.hashCode())); result = ((prime*result)+((transformQualify == null)? 0 :transformQualify.hashCode())); diff --git a/jOOQ/src/main/java/org/jooq/conf/SettingsTools.java b/jOOQ/src/main/java/org/jooq/conf/SettingsTools.java index 93cec23740..cf974201fd 100644 --- a/jOOQ/src/main/java/org/jooq/conf/SettingsTools.java +++ b/jOOQ/src/main/java/org/jooq/conf/SettingsTools.java @@ -37,6 +37,8 @@ */ package org.jooq.conf; +import static org.jooq.conf.FetchIntermediateResult.WHEN_EXECUTE_LISTENERS_PRESENT; +import static org.jooq.conf.FetchIntermediateResult.WHEN_RESULT_REQUESTED; import static org.jooq.conf.ParamType.INDEXED; import static org.jooq.conf.ParamType.INLINED; import static org.jooq.conf.StatementType.PREPARED_STATEMENT; @@ -50,7 +52,9 @@ import java.sql.Statement; import java.util.ArrayList; import java.util.Locale; +import org.jooq.Configuration; import org.jooq.tools.JooqLogger; +import org.jooq.tools.StringUtils; import org.jooq.util.jaxb.tools.MiniJAXB; /** @@ -391,6 +395,22 @@ public final class SettingsTools { : 0; } + /** + * Return FetchIntermediateResult. + */ + public static final boolean fetchIntermediateResult(Configuration configuration) { + switch (defaultIfNull(configuration.settings().getFetchIntermediateResult(), WHEN_RESULT_REQUESTED)) { + case ALWAYS: + return true; + case WHEN_EXECUTE_LISTENERS_PRESENT: + return configuration.executeListenerProviders().length > 0; + case WHEN_RESULT_REQUESTED: + return false; + default: + throw new IllegalStateException("Unhandled FetchIntermediateResult: " + configuration.settings().getFetchIntermediateResult()); + } + } + /** * Return fetchSize if it is not 0, or the specified * {@link Settings#getFetchSize()}. diff --git a/jOOQ/src/main/java/org/jooq/impl/ResultQueryTrait.java b/jOOQ/src/main/java/org/jooq/impl/ResultQueryTrait.java index a8fb761670..829db086a5 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ResultQueryTrait.java +++ b/jOOQ/src/main/java/org/jooq/impl/ResultQueryTrait.java @@ -41,6 +41,7 @@ import static org.jooq.Records.intoGroups; import static org.jooq.Records.intoList; import static org.jooq.Records.intoMap; import static org.jooq.Records.intoSet; +import static org.jooq.conf.SettingsTools.fetchIntermediateResult; import static org.jooq.impl.Tools.blocking; import static org.jooq.tools.jdbc.JDBCUtils.safeClose; @@ -99,6 +100,7 @@ import org.jooq.ResultQuery; import org.jooq.Results; import org.jooq.Select; import org.jooq.Table; +import org.jooq.conf.SettingsTools; import org.jooq.exception.DataAccessException; import org.jooq.impl.R2DBC.BlockingRecordSubscription; import org.jooq.impl.R2DBC.QuerySubscription; @@ -278,7 +280,10 @@ interface ResultQueryTrait extends QueryPartInternal, ResultQu @Override default ResultSet fetchResultSet() { - return fetchLazy().resultSet(); + if (fetchIntermediateResult(Tools.configuration(this))) + return fetch().intoResultSet(); + else + return fetchLazy().resultSet(); } @Override @@ -298,6 +303,9 @@ interface ResultQueryTrait extends QueryPartInternal, ResultQu @Override default Stream fetchStream() { + if (fetchIntermediateResult(Tools.configuration(this))) + return fetch().stream(); + AtomicReference> r = new AtomicReference<>(); // [#11895] Don't use the Stream.of(1).flatMap(i -> fetchLazy().stream()) @@ -332,6 +340,9 @@ interface ResultQueryTrait extends QueryPartInternal, ResultQu @Override default X collect(Collector collector) { + if (fetchIntermediateResult(Tools.configuration(this))) + return fetch().collect(collector); + try (Cursor c = fetchLazyNonAutoClosing()) { return c.collect(collector); } diff --git a/jOOQ/src/main/resources/xsd/jooq-runtime-3.15.0.xsd b/jOOQ/src/main/resources/xsd/jooq-runtime-3.15.0.xsd index 40bc2ed1a7..ff5c027395 100644 --- a/jOOQ/src/main/resources/xsd/jooq-runtime-3.15.0.xsd +++ b/jOOQ/src/main/resources/xsd/jooq-runtime-3.15.0.xsd @@ -245,6 +245,19 @@ included in the OUTPUT clause. For details, see https://github.com/jOOQ/jOOQ/issues/4498.]]> + + +By default, a {@link org.jooq.ResultQuery} produces no intermediate {@link org.jooq.Result} +instances if they are not explicitly requested by the caller, e.g. by calling +{@link org.jooq.ResultQuery#fetch()}, or in the presence of {@link org.jooq.ExecuteListener} +instances, which may require access to {@link org.jooq.ExecuteContext#result()}. +This default behaviour helps avoid unnecessary allocations of possibly large data structures. +

+Using this flag, fetching of intermediate results can be turned off even when execute listeners +are present, or turned on even if they're absent.]]> + + @@ -1340,4 +1353,18 @@ Either <input/> or <inputExpression/> must be provided]]> + + + + + + + + + + + + + + \ No newline at end of file