diff --git a/jOOQ/src/main/java/org/jooq/Field.java b/jOOQ/src/main/java/org/jooq/Field.java index 2310ae7f28..428d6b8a9b 100644 --- a/jOOQ/src/main/java/org/jooq/Field.java +++ b/jOOQ/src/main/java/org/jooq/Field.java @@ -4223,6 +4223,7 @@ extends + // ------------------------------------------------------------------------ diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractQuery.java b/jOOQ/src/main/java/org/jooq/impl/AbstractQuery.java index 23ccf8bae4..95a2026a8f 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractQuery.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractQuery.java @@ -54,7 +54,9 @@ import static org.jooq.impl.DSL.using; import static org.jooq.impl.Tools.EMPTY_PARAM; import static org.jooq.impl.Tools.blocking; import static org.jooq.impl.Tools.consumeExceptions; +import static org.jooq.impl.Tools.maxForceSettingsAttempts; import static org.jooq.impl.Tools.BooleanDataKey.DATA_COUNT_BIND_VALUES; +import static org.jooq.impl.Tools.BooleanDataKey.DATA_FORCE_SETTINGS; import static org.jooq.impl.Tools.BooleanDataKey.DATA_FORCE_STATIC_STATEMENT; import java.sql.PreparedStatement; @@ -78,7 +80,9 @@ import org.jooq.conf.QueryPoolable; import org.jooq.conf.SettingsTools; import org.jooq.conf.StatementType; import org.jooq.exception.ControlFlowSignal; +import org.jooq.exception.DataAccessException; import org.jooq.exception.DetachedException; +import org.jooq.impl.DefaultRenderContext.ForceSettingsSignal; import org.jooq.tools.Ints; import org.jooq.tools.JooqLogger; @@ -509,30 +513,47 @@ abstract class AbstractQuery extends AbstractQueryPart implements Query { private final Rendered getSQL0(ExecuteContext ctx) { Rendered result; + DefaultRenderContext render; + Configuration c = configuration; // [#3542] [#4977] Some dialects do not support bind values in DDL statements // [#6474] [#6929] Can this be communicated in a leaner way? - if (ctx.type() == DDL) { - ctx.data(DATA_FORCE_STATIC_STATEMENT, true); - DefaultRenderContext render = new DefaultRenderContext(configuration); - result = new Rendered(render.paramType(INLINED).visit(this).render(), null, render.peekSkipUpdateCounts()); - } - else if (executePreparedStatements(configuration().settings())) { + int i = 0; + forceSettingsLoop: + for (;;) { + render = new DefaultRenderContext(c); + render.data(DATA_FORCE_SETTINGS, true); + try { - DefaultRenderContext render = new DefaultRenderContext(configuration); - render.data(DATA_COUNT_BIND_VALUES, true); - result = new Rendered(render.visit(this).render(), render.bindValues(), render.peekSkipUpdateCounts()); + if (ctx.type() == DDL) { + ctx.data(DATA_FORCE_STATIC_STATEMENT, true); + result = new Rendered(render.paramType(INLINED).visit(this).render(), null, render.peekSkipUpdateCounts()); + } + else if (executePreparedStatements(configuration().settings())) { + try { + render.data(DATA_COUNT_BIND_VALUES, true); + result = new Rendered(render.visit(this).render(), render.bindValues(), render.peekSkipUpdateCounts()); + } + catch (DefaultRenderContext.ForceInlineSignal e) { + ctx.data(DATA_FORCE_STATIC_STATEMENT, true); + result = new Rendered(render.paramType(INLINED).visit(this).render(), null, render.peekSkipUpdateCounts()); + } + } + else { + result = new Rendered(render.paramType(INLINED).visit(this).render(), null, render.peekSkipUpdateCounts()); + } + + break forceSettingsLoop; } - catch (DefaultRenderContext.ForceInlineSignal e) { - ctx.data(DATA_FORCE_STATIC_STATEMENT, true); - DefaultRenderContext render = new DefaultRenderContext(configuration); - result = new Rendered(render.paramType(INLINED).visit(this).render(), null, render.peekSkipUpdateCounts()); + catch (ForceSettingsSignal e) { + if (++i >= maxForceSettingsAttempts) { + log.warn("Infinite loop", "There was an infinite loop trying to render a SQL query, due to ForceSettingsSignal. Please consider reporting this bug here: https://github.com/jOOQ/jOOQ/issues/new/choose"); + throw new DataAccessException("Too many force settings attempts"); + } + + c = c.derive(e.settings); } } - else { - DefaultRenderContext render = new DefaultRenderContext(configuration); - result = new Rendered(render.paramType(INLINED).visit(this).render(), null, render.peekSkipUpdateCounts()); - } diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java index 358a1eea2a..c2abb98f2e 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java @@ -956,4 +956,21 @@ class DefaultRenderContext extends AbstractContext implements Ren log.debug("Re-render query", "Forcing bind variable inlining as " + configuration().dialect() + " does not support " + params + " bind variables (or more) in a single query"); } } + + /** + * A query rendering signal to force re-rendering a query with different + * settings. + */ + static class ForceSettingsSignal extends ControlFlowSignal { + + /** + * Generated UID + */ + private static final long serialVersionUID = -1530836969063166588L; + final Settings settings; + + ForceSettingsSignal(Settings settings) { + this.settings = settings; + } + } } diff --git a/jOOQ/src/main/java/org/jooq/impl/Tools.java b/jOOQ/src/main/java/org/jooq/impl/Tools.java index 15a502f54d..87e26ba4a9 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Tools.java +++ b/jOOQ/src/main/java/org/jooq/impl/Tools.java @@ -282,6 +282,7 @@ import org.jooq.exception.MappingException; import org.jooq.exception.NoDataFoundException; import org.jooq.exception.TemplatingException; import org.jooq.exception.TooManyRowsException; +import org.jooq.impl.DefaultRenderContext.ForceSettingsSignal; import org.jooq.impl.ResultsImpl.ResultOrRowsImpl; import org.jooq.tools.Ints; import org.jooq.tools.JooqLogger; @@ -372,6 +373,12 @@ final class Tools { */ DATA_FORCE_STATIC_STATEMENT, + /** + * [#7312] Allow for {@link ForceSettingsSignal} to be thrown in order + * to override user-defined settings. + */ + DATA_FORCE_SETTINGS, + /** * [#2665] Omit the emission of clause events by {@link QueryPart}s. *

@@ -711,8 +718,9 @@ final class Tools { * {@link #consumeExceptions(Configuration, PreparedStatement, SQLException)} * helps prevent infinite loops and {@link OutOfMemoryError}. */ - private static int maxConsumedExceptions = 256; - private static int maxConsumedResults = 65536; + static int maxForceSettingsAttempts = 16; + static int maxConsumedExceptions = 256; + static int maxConsumedResults = 65536; /** * A pattern for the dash line syntax