diff --git a/jOOQ/src/main/java/org/jooq/impl/DeleteQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/DeleteQueryImpl.java index ccab4186a3..66c62d42ca 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DeleteQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/DeleteQueryImpl.java @@ -254,7 +254,6 @@ implements ctx.scopeStart(this); // [#2682] [#15632] Apply inline derived tables to the target table - // [#15632] TODO: Check if this behaves correctly with aliases // [#15632] TODO: Refactor this logic with UpdateQueryImpl Table t = table(ctx); Table i = InlineDerivedTable.inlineDerivedTable(ctx, t); diff --git a/jOOQ/src/main/java/org/jooq/impl/InlineDerivedTable.java b/jOOQ/src/main/java/org/jooq/impl/InlineDerivedTable.java index 3684d98a27..cb8eb37f89 100644 --- a/jOOQ/src/main/java/org/jooq/impl/InlineDerivedTable.java +++ b/jOOQ/src/main/java/org/jooq/impl/InlineDerivedTable.java @@ -43,14 +43,25 @@ import static org.jooq.impl.DSL.table; import static org.jooq.impl.Tools.anyMatch; import static org.jooq.tools.StringUtils.defaultIfNull; +import java.util.List; + +import org.jooq.Check; import org.jooq.Condition; import org.jooq.Context; +import org.jooq.ForeignKey; +import org.jooq.Identity; +import org.jooq.Index; import org.jooq.QueryPart; import org.jooq.Record; // ... import org.jooq.Select; import org.jooq.Table; +import org.jooq.TableField; // ... +import org.jooq.UniqueKey; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author Lukas Eder @@ -62,7 +73,7 @@ final class InlineDerivedTable extends DerivedTable { final boolean policyGenerated; InlineDerivedTable(TableImpl t) { - this(removeWhere(t), t.where, false); + this(t.where((Condition) null), t.where, false); } InlineDerivedTable(Table table, Condition condition, boolean policyGenerated) { @@ -241,25 +252,6 @@ final class InlineDerivedTable extends DerivedTable { return null; } - private static final Table removeWhere(Table t) { - if (t instanceof TableImpl i) { - return new TableImpl<>( - i.getQualifiedName(), - i.getSchema(), - i.path, - i.childPath, - i.parentPath, - i.alias != null ? removeWhere(i.alias.wrapped) : null, - i.parameters, - i.getCommentPart(), - i.getOptions(), - null - ); - } - else - return t; - } - @Override final FieldsImpl fields0() { diff --git a/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java index 50cb428501..42c9758e02 100644 --- a/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java @@ -66,7 +66,6 @@ import static org.jooq.SQLDialect.MYSQL; import static org.jooq.SQLDialect.POSTGRES; // ... // ... -// ... import static org.jooq.SQLDialect.SQLITE; // ... // ... @@ -83,7 +82,6 @@ import static org.jooq.impl.DSL.select; import static org.jooq.impl.DSL.selectFrom; import static org.jooq.impl.DSL.selectOne; import static org.jooq.impl.FieldMapsForInsert.toSQLInsertSelect; -import static org.jooq.impl.InlineDerivedTable.inlineDerivedTable; import static org.jooq.impl.Keywords.K_AS; import static org.jooq.impl.Keywords.K_DEFAULT; import static org.jooq.impl.Keywords.K_DEFAULT_VALUES; @@ -99,7 +97,6 @@ import static org.jooq.impl.Keywords.K_SET; import static org.jooq.impl.Keywords.K_VALUES; import static org.jooq.impl.Keywords.K_WHERE; import static org.jooq.impl.QueryPartListView.wrap; -import static org.jooq.impl.Tools.aliased; import static org.jooq.impl.Tools.aliasedFields; import static org.jooq.impl.Tools.anyMatch; import static org.jooq.impl.Tools.collect; @@ -108,6 +105,7 @@ import static org.jooq.impl.Tools.flattenCollection; import static org.jooq.impl.Tools.map; import static org.jooq.impl.Tools.orElse; import static org.jooq.impl.Tools.qualify; +import static org.jooq.impl.Tools.unalias; import static org.jooq.impl.Tools.unqualified; import static org.jooq.impl.Tools.BooleanDataKey.DATA_CONSTRAINT_REFERENCE; import static org.jooq.impl.Tools.BooleanDataKey.DATA_INSERT_SELECT; @@ -119,18 +117,15 @@ import static org.jooq.tools.StringUtils.defaultIfNull; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Objects; -import java.util.function.Consumer; import java.util.Set; +import java.util.function.Consumer; -import org.jooq.CheckReturnValue; import org.jooq.Clause; import org.jooq.Condition; import org.jooq.Configuration; @@ -150,7 +145,6 @@ import org.jooq.Operator; import org.jooq.QueryPart; import org.jooq.Record; // ... -// ... import org.jooq.Row; import org.jooq.SQLDialect; import org.jooq.Scope; @@ -158,22 +152,17 @@ import org.jooq.Select; import org.jooq.Table; import org.jooq.TableField; // ... +// ... import org.jooq.UniqueKey; -import org.jooq.conf.ParamType; import org.jooq.conf.WriteIfReadonly; import org.jooq.impl.FieldMapForUpdate.SetClause; import org.jooq.impl.QOM.Insert; -import org.jooq.impl.QOM.UNotYetImplemented; import org.jooq.impl.QOM.UnmodifiableList; import org.jooq.impl.QOM.UnmodifiableMap; -import org.jooq.impl.QOM.With; import org.jooq.impl.Tools.BooleanDataKey; import org.jooq.impl.Tools.ExtendedDataKey; import org.jooq.tools.StringUtils; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - /** * @author Lukas Eder */ @@ -385,12 +374,12 @@ implements insertMaps.set(map); } + @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public final void accept(Context ctx) { ctx.scopeStart(this); - // [#2682] [#15632] Apply inline derived tables to the target table (TODO: Apply also to FROM, etc.) - // [#15632] TODO: Check if this behaves correctly with aliases + // [#2682] [#15632] Apply inline derived tables to the target table Table t = InlineDerivedTable.inlineDerivedTable(ctx, table(ctx)); if (t instanceof InlineDerivedTable i) { copy( @@ -399,7 +388,36 @@ implements // [#15632] SchemaMapping could produce a different table than the one contained // in the inline derived table specification, and the alias must reflect that - Table m = DSL.table(defaultIfNull(ctx.dsl().map(i.table), i.table).getUnqualifiedName()); + Table m = DSL.table(name("t")); + + if ((onDuplicateKeyIgnore || onDuplicateKeyUpdate) && ctx.configuration().requireCommercial(() -> "InlineDerivedTable emulation for INSERT .. ON DUPLICATE KEY clauses is available in the commercial jOOQ editions only")) { + + // [pro] */ + // [#15632] The i.condition may reference columns that aren't part of d.insertMaps, so + // we have to synthetically add explicit defaults for any known fields. + List> fields = (List) i.condition.$traverse(Traversers.findingAll(p -> p instanceof TableField tf + ? tf.getTable() == null || unalias(i.table).equals(unalias(tf.getTable())) + : false + )); + for (Field f : fields) { + if (!d.insertMaps.values.containsKey(f)) + d.addValue(f, (Field) f.getDataType().default_()); + } + + // [#15632] Don't allow for values to be created that don't match the InlineDerivedTable or policy + Condition c, c2; + c = c2 = i.condition; + for (Entry e : d.updateMap.entrySet()) { + c2 = (Condition) c2.$replace(q -> e.getKey().equals(q) + ? (QueryPart) e.getValue() + : q + ); + } + + if (c2 != c) + d.addConditions(c2); + /* [/pro] */ + } d.select = selectFrom( @@ -409,7 +427,9 @@ implements // [#15632] Map the original table reference to the derived table alias // to prevent schema mapping in the condition. - .scopeRegister(i.table, false, m).visit(i.condition) + .scopeRegister(i.table, false, m) + .visit(i.condition) + .scopeRegister(i.table, false, null) )); } }, diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java index 83208df519..8ad7095b0e 100644 --- a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java @@ -156,7 +156,6 @@ import static org.jooq.impl.DSL.regexpReplaceAll; import static org.jooq.impl.DSL.row; import static org.jooq.impl.DSL.rowNumber; // ... -import static org.jooq.impl.DSL.selectFrom; import static org.jooq.impl.DSL.table; import static org.jooq.impl.DSL.trueCondition; import static org.jooq.impl.DSL.unquotedName; @@ -218,7 +217,6 @@ import static org.jooq.impl.Tools.selectQueryImpl; import static org.jooq.impl.Tools.traverseJoins; import static org.jooq.impl.Tools.unalias; import static org.jooq.impl.Tools.unqualified; -import static org.jooq.impl.Tools.unwrap; 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; @@ -287,12 +285,10 @@ import org.jooq.Operator; import org.jooq.OrderField; import org.jooq.Param; // ... -// ... import org.jooq.QualifiedAsterisk; import org.jooq.QueryPart; import org.jooq.Record; // ... -// ... import org.jooq.Result; import org.jooq.Row; import org.jooq.SQLDialect; diff --git a/jOOQ/src/main/java/org/jooq/impl/UpdateQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/UpdateQueryImpl.java index 867c172bbf..005a782077 100644 --- a/jOOQ/src/main/java/org/jooq/impl/UpdateQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/UpdateQueryImpl.java @@ -91,9 +91,7 @@ import static org.jooq.impl.DSL.selectFrom; import static org.jooq.impl.DSL.trueCondition; import static org.jooq.impl.InlineDerivedTable.transformInlineDerivedTables; import static org.jooq.impl.Keywords.K_FROM; -import static org.jooq.impl.Keywords.K_LIMIT; import static org.jooq.impl.Keywords.K_ORDER_BY; -import static org.jooq.impl.Keywords.K_ROWS; import static org.jooq.impl.Keywords.K_SET; import static org.jooq.impl.Keywords.K_UPDATE; import static org.jooq.impl.Keywords.K_WHERE; @@ -566,7 +564,6 @@ implements ctx.scopeStart(this); // [#2682] [#15632] Apply inline derived tables to the target table - // [#15632] TODO: Check if this behaves correctly with aliases // [#15632] TODO: Refactor this logic with DeleteQueryImpl Table t = table(ctx); Table i = InlineDerivedTable.inlineDerivedTable(ctx, t);