diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractBindContext.java b/jOOQ/src/main/java/org/jooq/impl/AbstractBindContext.java index 5b2ab15c4f..0d2c7f6916 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractBindContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractBindContext.java @@ -42,6 +42,7 @@ import java.sql.SQLException; import org.jooq.BindContext; import org.jooq.Configuration; +import org.jooq.ExecuteContext; import org.jooq.Field; import org.jooq.QueryPart; import org.jooq.QueryPartInternal; @@ -54,8 +55,8 @@ import org.jooq.exception.DataAccessException; */ abstract class AbstractBindContext extends AbstractContext implements BindContext { - AbstractBindContext(Configuration configuration, PreparedStatement stmt) { - super(configuration, stmt); + AbstractBindContext(Configuration configuration, ExecuteContext ctx, PreparedStatement stmt) { + super(configuration, ctx, stmt); } // ------------------------------------------------------------------------ diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java b/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java index 6c5c01ebb2..372998b593 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java @@ -54,6 +54,7 @@ import static org.jooq.impl.Tools.EMPTY_QUERYPART; import static org.jooq.impl.Tools.lazy; import static org.jooq.impl.Tools.BooleanDataKey.DATA_NESTED_SET_OPERATIONS; import static org.jooq.impl.Tools.BooleanDataKey.DATA_OMIT_CLAUSE_EVENT_EMISSION; +import static org.jooq.impl.Tools.SimpleDataKey.DATA_EXECUTE_CONTEXT; import java.sql.PreparedStatement; import java.text.DecimalFormat; @@ -79,6 +80,7 @@ import org.jooq.Condition; import org.jooq.Configuration; import org.jooq.Context; import org.jooq.DSLContext; +import org.jooq.ExecuteContext; import org.jooq.Field; import org.jooq.ForeignKey; import org.jooq.JoinType; @@ -159,8 +161,12 @@ abstract class AbstractContext> extends AbstractScope imple private transient DecimalFormat doubleFormat; private transient DecimalFormat floatFormat; - AbstractContext(Configuration configuration, PreparedStatement stmt) { + AbstractContext(Configuration configuration, ExecuteContext ctx, PreparedStatement stmt) { super(configuration); + + if (ctx != null) + data(DATA_EXECUTE_CONTEXT, ctx); + this.stmt = stmt; VisitListenerProvider[] providers = configuration.visitListenerProviders(); diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractQuery.java b/jOOQ/src/main/java/org/jooq/impl/AbstractQuery.java index 095b433701..30fe855db4 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractQuery.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractQuery.java @@ -465,23 +465,23 @@ abstract class AbstractQuery extends AbstractAttachableQueryPa // [#6474] [#6929] Can this be communicated in a leaner way? if (ctx.type() == DDL) { ctx.data(DATA_FORCE_STATIC_STATEMENT, true); - render = new DefaultRenderContext(c); + render = new DefaultRenderContext(c, ctx); result = new Rendered(render.paramType(INLINED).visit(this).render(), null, render.skipUpdateCounts()); } else if (executePreparedStatements(configuration().settings())) { try { - render = new DefaultRenderContext(c); + render = new DefaultRenderContext(c, ctx); render.data(DATA_COUNT_BIND_VALUES, true); result = new Rendered(render.visit(this).render(), render.bindValues(), render.skipUpdateCounts()); } catch (DefaultRenderContext.ForceInlineSignal e) { ctx.data(DATA_FORCE_STATIC_STATEMENT, true); - render = new DefaultRenderContext(c); + render = new DefaultRenderContext(c, ctx); result = new Rendered(render.paramType(INLINED).visit(this).render(), null, render.skipUpdateCounts()); } } else { - render = new DefaultRenderContext(c); + render = new DefaultRenderContext(c, ctx); result = new Rendered(render.paramType(INLINED).visit(this).render(), null, render.skipUpdateCounts()); } diff --git a/jOOQ/src/main/java/org/jooq/impl/BatchSingle.java b/jOOQ/src/main/java/org/jooq/impl/BatchSingle.java index f9fcd6bcd2..3160366dab 100644 --- a/jOOQ/src/main/java/org/jooq/impl/BatchSingle.java +++ b/jOOQ/src/main/java/org/jooq/impl/BatchSingle.java @@ -218,7 +218,7 @@ final class BatchSingle extends AbstractBatch implements BatchBindStep { // list to preserve type information // [#3547] The original query may have no Params specified - e.g. when it was constructed with // plain SQL. In that case, infer the bind value type directly from the bind value - visitAll(new DefaultBindContext(configuration, ctx.statement()), + visitAll(new DefaultBindContext(configuration, ctx, ctx.statement()), (params.length > 0) ? fields(bindValues, params) : fields(bindValues)); diff --git a/jOOQ/src/main/java/org/jooq/impl/CursorImpl.java b/jOOQ/src/main/java/org/jooq/impl/CursorImpl.java index 4f0380d1eb..1d44e984f7 100644 --- a/jOOQ/src/main/java/org/jooq/impl/CursorImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/CursorImpl.java @@ -37,6 +37,7 @@ */ package org.jooq.impl; +import static java.lang.Boolean.TRUE; import static java.util.Collections.emptyList; // ... import static org.jooq.impl.RowAsField.NO_NATIVE_SUPPORT; @@ -44,6 +45,7 @@ import static org.jooq.impl.Tools.embeddedFields; import static org.jooq.impl.Tools.embeddedRecordType; import static org.jooq.impl.Tools.recordFactory; import static org.jooq.impl.Tools.uncoerce; +import static org.jooq.impl.Tools.BooleanDataKey.DATA_MULTISET_CONTENT; import java.io.InputStream; import java.io.Reader; @@ -78,7 +80,6 @@ import org.jooq.BindingGetResultSetContext; import org.jooq.Converter; import org.jooq.ExecuteContext; import org.jooq.ExecuteListener; -import org.jooq.ExecuteType; import org.jooq.Field; // ... import org.jooq.Record; @@ -1548,7 +1549,11 @@ final class CursorImpl extends AbstractCursor { // RowField may have a Row[N].mapping(...) applied Field f = uncoerce(field); - if (f instanceof AbstractRowAsField && NO_NATIVE_SUPPORT.contains(ctx.dialect())) { + // [#13560] Queries may decide themselves to replace the + // flattening emulation by the MULTISET emulation + if (f instanceof AbstractRowAsField + && NO_NATIVE_SUPPORT.contains(ctx.dialect()) + && !TRUE.equals(ctx.data(DATA_MULTISET_CONTENT))) { nested = ((AbstractRowAsField) f).emulatedFields(configuration); recordType = (Class) ((AbstractRowAsField) f).getRecordType(); } diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultBindContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultBindContext.java index 5e7d18ce4d..8da884f68e 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultBindContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultBindContext.java @@ -42,6 +42,7 @@ import java.sql.SQLException; import org.jooq.BindContext; import org.jooq.Configuration; +import org.jooq.ExecuteContext; import org.jooq.Field; /** @@ -49,8 +50,8 @@ import org.jooq.Field; */ final class DefaultBindContext extends AbstractBindContext { - DefaultBindContext(Configuration configuration, PreparedStatement stmt) { - super(configuration, stmt); + DefaultBindContext(Configuration configuration, ExecuteContext ctx, PreparedStatement stmt) { + super(configuration, ctx, stmt); } @Override diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java index 77b83b5a57..e44a164ed9 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java @@ -716,7 +716,7 @@ public class DefaultDSLContext extends AbstractScope implements DSLContext, Seri @Override public RenderContext renderContext() { - return new DefaultRenderContext(configuration()); + return new DefaultRenderContext(configuration(), null); } @Override @@ -760,7 +760,7 @@ public class DefaultDSLContext extends AbstractScope implements DSLContext, Seri @Override public BindContext bindContext(PreparedStatement stmt) { - return new DefaultBindContext(configuration(), stmt); + return new DefaultBindContext(configuration(), null, stmt); } // ------------------------------------------------------------------------- diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java index 3bb98226a7..c415fbd303 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java @@ -46,10 +46,9 @@ import static org.jooq.impl.Identifiers.QUOTES; import static org.jooq.impl.Identifiers.QUOTE_END_DELIMITER; import static org.jooq.impl.Identifiers.QUOTE_END_DELIMITER_ESCAPED; import static org.jooq.impl.Identifiers.QUOTE_START_DELIMITER; -import static org.jooq.impl.Tools.DATAKEY_RESET_IN_SUBQUERY_SCOPE; -import static org.jooq.impl.Tools.lazy; import static org.jooq.impl.Tools.BooleanDataKey.DATA_COUNT_BIND_VALUES; import static org.jooq.impl.Tools.SimpleDataKey.DATA_APPEND_SQL; +import static org.jooq.impl.Tools.SimpleDataKey.DATA_EXECUTE_CONTEXT; import static org.jooq.impl.Tools.SimpleDataKey.DATA_PREPEND_SQL; import java.util.ArrayDeque; @@ -64,6 +63,7 @@ import java.util.regex.Pattern; import org.jooq.BindContext; import org.jooq.Configuration; import org.jooq.Constants; +import org.jooq.ExecuteContext; import org.jooq.Field; import org.jooq.ForeignKey; import org.jooq.Param; @@ -82,9 +82,7 @@ import org.jooq.conf.Settings; import org.jooq.conf.SettingsTools; import org.jooq.exception.ControlFlowSignal; import org.jooq.exception.DataAccessException; -import org.jooq.impl.AbstractContext.ScopeStackElement; import org.jooq.impl.ScopeMarker.ScopeContent; -import org.jooq.impl.Tools.DataKey; import org.jooq.tools.JooqLogger; import org.jooq.tools.StringUtils; @@ -121,8 +119,8 @@ class DefaultRenderContext extends AbstractContext implements Ren String cachedNewline; int cachedPrintMargin; - DefaultRenderContext(Configuration configuration) { - super(configuration, null); + DefaultRenderContext(Configuration configuration, ExecuteContext ctx) { + super(configuration, ctx, null); Settings settings = configuration.settings(); @@ -148,7 +146,7 @@ class DefaultRenderContext extends AbstractContext implements Ren } DefaultRenderContext(RenderContext context, boolean copyLocalState) { - this(context.configuration()); + this(context.configuration(), (ExecuteContext) context.data(DATA_EXECUTE_CONTEXT)); paramType(context.paramType()); qualifyCatalog(context.qualifyCatalog()); diff --git a/jOOQ/src/main/java/org/jooq/impl/ParamCollector.java b/jOOQ/src/main/java/org/jooq/impl/ParamCollector.java index 29fdd8b1f7..f86da9b73c 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ParamCollector.java +++ b/jOOQ/src/main/java/org/jooq/impl/ParamCollector.java @@ -68,7 +68,7 @@ final class ParamCollector extends AbstractBindContext { private final boolean includeInlinedParams; ParamCollector(Configuration configuration, boolean includeInlinedParams) { - super(configuration, null); + super(configuration, null, null); this.includeInlinedParams = includeInlinedParams; } diff --git a/jOOQ/src/main/java/org/jooq/impl/ParsingConnection.java b/jOOQ/src/main/java/org/jooq/impl/ParsingConnection.java index 267a37f1e5..238b4d4eed 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ParsingConnection.java +++ b/jOOQ/src/main/java/org/jooq/impl/ParsingConnection.java @@ -195,7 +195,7 @@ final class ParsingConnection extends DefaultConnection { if (i > 0) rendered = translate(configuration, sql, p.get(i).toArray(EMPTY_PARAM)); - new DefaultBindContext(configuration, s).visit(rendered.bindValues); + new DefaultBindContext(configuration, null, s).visit(rendered.bindValues); // TODO: Find a less hacky way to signal that we're batching. Currently: // - ArrayList>> = batching diff --git a/jOOQ/src/main/java/org/jooq/impl/R2DBC.java b/jOOQ/src/main/java/org/jooq/impl/R2DBC.java index d2f1f0cd28..4cdc1f777e 100644 --- a/jOOQ/src/main/java/org/jooq/impl/R2DBC.java +++ b/jOOQ/src/main/java/org/jooq/impl/R2DBC.java @@ -400,7 +400,7 @@ final class R2DBC { try { Rendered rendered = rendered(configuration, query); Statement stmt = c.createStatement(sql = rendered.sql); - new DefaultBindContext(configuration, new R2DBCPreparedStatement(configuration, stmt)).visit(rendered.bindValues); + new DefaultBindContext(configuration, null, new R2DBCPreparedStatement(configuration, stmt)).visit(rendered.bindValues); // TODO: Reuse org.jooq.impl.Tools.setFetchSize(ExecuteContext ctx, int fetchSize) AbstractResultQuery q1 = abstractResultQuery(query); @@ -501,7 +501,7 @@ final class R2DBC { // list to preserve type information // [#3547] The original query may have no Params specified - e.g. when it was constructed with // plain SQL. In that case, infer the bind value type directly from the bind value - visitAll(new DefaultBindContext(batch.configuration, new R2DBCPreparedStatement(batch.query.configuration(), stmt)), + visitAll(new DefaultBindContext(batch.configuration, null, new R2DBCPreparedStatement(batch.query.configuration(), stmt)), (params.length > 0) ? fields(bindValues, params) : fields(bindValues)); @@ -728,7 +728,7 @@ final class R2DBC { static final Rendered rendered(Configuration configuration, Query query) { DefaultRenderContext render = new DefaultRenderContext(configuration.deriveSettings(s -> setParamType(configuration.dialect(), s) - )); + ), null); return new Rendered(render.paramType(NAMED).visit(query).render(), render.bindValues(), render.skipUpdateCounts()); } diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java index 91ca2cb202..8a09491bfc 100644 --- a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java @@ -208,6 +208,7 @@ import static org.jooq.impl.Tools.BooleanDataKey.DATA_COLLECT_SEMI_ANTI_JOIN; import static org.jooq.impl.Tools.BooleanDataKey.DATA_FORCE_LIMIT_WITH_ORDER_BY; import static org.jooq.impl.Tools.BooleanDataKey.DATA_INSERT_SELECT; import static org.jooq.impl.Tools.BooleanDataKey.DATA_INSERT_SELECT_WITHOUT_INSERT_COLUMN_LIST; +import static org.jooq.impl.Tools.BooleanDataKey.DATA_MULTISET_CONTENT; import static org.jooq.impl.Tools.BooleanDataKey.DATA_NESTED_SET_OPERATIONS; import static org.jooq.impl.Tools.BooleanDataKey.DATA_OMIT_INTO_CLAUSE; import static org.jooq.impl.Tools.BooleanDataKey.DATA_RENDER_TRAILING_LIMIT_IF_APPLICABLE; @@ -216,6 +217,7 @@ import static org.jooq.impl.Tools.BooleanDataKey.DATA_WRAP_DERIVED_TABLES_IN_PAR import static org.jooq.impl.Tools.ExtendedDataKey.DATA_TRANSFORM_ROWNUM_TO_LIMIT; import static org.jooq.impl.Tools.SimpleDataKey.DATA_COLLECTED_SEMI_ANTI_JOIN; import static org.jooq.impl.Tools.SimpleDataKey.DATA_DML_TARGET_TABLE; +import static org.jooq.impl.Tools.SimpleDataKey.DATA_EXECUTE_CONTEXT; import static org.jooq.impl.Tools.SimpleDataKey.DATA_OVERRIDE_ALIASES_IN_ORDER_BY; import static org.jooq.impl.Tools.SimpleDataKey.DATA_RENDERING_DATA_CHANGE_DELTA_TABLE; import static org.jooq.impl.Tools.SimpleDataKey.DATA_SELECT_ALIASES; @@ -248,6 +250,7 @@ import org.jooq.Condition; import org.jooq.Configuration; import org.jooq.Context; import org.jooq.DataType; +import org.jooq.ExecuteContext; import org.jooq.Field; import org.jooq.ForeignKey; import org.jooq.GeneratorStatementType; @@ -2052,6 +2055,9 @@ final class SelectQueryImpl extends AbstractResultQuery imp + + + diff --git a/jOOQ/src/main/java/org/jooq/impl/Tools.java b/jOOQ/src/main/java/org/jooq/impl/Tools.java index 78857d8182..a69863b95e 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Tools.java +++ b/jOOQ/src/main/java/org/jooq/impl/Tools.java @@ -188,6 +188,7 @@ import static org.jooq.impl.SQLDataType.VARCHAR; import static org.jooq.impl.SQLDataType.XML; import static org.jooq.impl.Tools.anyMatch; import static org.jooq.impl.Tools.SimpleDataKey.DATA_BLOCK_NESTING; +import static org.jooq.impl.Tools.SimpleDataKey.DATA_EXECUTE_CONTEXT; import static org.jooq.tools.StringUtils.defaultIfNull; import java.lang.annotation.Annotation; @@ -673,6 +674,12 @@ final class Tools { */ enum SimpleDataKey implements DataKey { + /** + * [#13560] [#13599] The {@link ExecuteContext} in whose scope another + * {@link Scope} may have been created. + */ + DATA_EXECUTE_CONTEXT, + /** * The level of anonymous block nesting, in case we're generating a block. */ @@ -2776,8 +2783,7 @@ final class Tools { char[] sqlChars = sql.toCharArray(); // [#1593] Create a dummy renderer if we're in bind mode - if (render == null) render = new DefaultRenderContext(bind.configuration()); - + if (render == null) render = new DefaultRenderContext(bind.configuration(), (ExecuteContext) ctx.data(DATA_EXECUTE_CONTEXT)); SQLDialect family = render.family(); boolean mysql = SUPPORTS_HASH_COMMENT_SYNTAX.contains(render.dialect()); char[][][] quotes = QUOTES.get(family);