[jOOQ/jOOQ#12194] MySQL DELETE .. USING with JOIN produces duplicate

table declarations in USING clause
This commit is contained in:
Lukas Eder 2021-07-15 14:08:02 +02:00
parent 8e358aac44
commit 9bc5fe43c0
4 changed files with 32 additions and 21 deletions

View File

@ -83,6 +83,7 @@ import static org.jooq.impl.Keywords.K_LIMIT;
import static org.jooq.impl.Keywords.K_ORDER_BY;
import static org.jooq.impl.Keywords.K_USING;
import static org.jooq.impl.Keywords.K_WHERE;
import static org.jooq.impl.Tools.containsDeclaredTable;
import static org.jooq.impl.Tools.traverseJoins;
import java.util.Arrays;
@ -253,11 +254,12 @@ final class DeleteQueryImpl<R extends Record> extends AbstractDMLQuery<R> implem
if (!using.isEmpty() || multiTableJoin || specialDeleteAsSyntax && Tools.alias(t) != null) {
TableList u;
if (REQUIRE_REPEAT_FROM_IN_USING.contains(ctx.dialect()) && !using.contains(t)) {
if (REQUIRE_REPEAT_FROM_IN_USING.contains(ctx.dialect()) && !containsDeclaredTable(using, t)) {
u = new TableList(t);
u.addAll(using);
}
else if (NO_SUPPORT_REPEAT_FROM_IN_USING.contains(ctx.dialect()) && using.contains(t)) {
else if (NO_SUPPORT_REPEAT_FROM_IN_USING.contains(ctx.dialect()) && containsDeclaredTable(using, t)) {
u = new TableList(using);
u.remove(t);
}

View File

@ -104,9 +104,8 @@ import static org.jooq.impl.Keywords.K_PARTITION_BY;
import static org.jooq.impl.Keywords.K_USING;
import static org.jooq.impl.Names.N_JOIN;
import static org.jooq.impl.QueryPartListView.wrap;
import static org.jooq.impl.Tools.containsUnaliasedTable;
import static org.jooq.impl.Tools.map;
import static org.jooq.impl.Tools.search;
import static org.jooq.impl.Tools.traverseJoins;
import static org.jooq.impl.Tools.BooleanDataKey.DATA_COLLECT_SEMI_ANTI_JOIN;
import static org.jooq.impl.Tools.DataKey.DATA_COLLECTED_SEMI_ANTI_JOIN;
@ -704,7 +703,7 @@ implements
unaliased.set(i, (TableField<?, ?>) alias.wrapped().field(f));
}
if (traverseJoins(lhs, false, r -> r, search(keyFields[0].getTable()))) {
if (containsUnaliasedTable(lhs, keyFields[0].getTable())) {
for (ForeignKey<?, ?> key : lhs.getReferences())
if (key.getFields().containsAll(unaliased) && unaliased.containsAll(key.getFields()))
return onKey(key);
@ -713,7 +712,7 @@ implements
if (key.getFields().containsAll(unaliased))
return onKey(key);
}
else if (traverseJoins(rhs, false, r -> r, search(keyFields[0].getTable()))) {
else if (containsUnaliasedTable(rhs, keyFields[0].getTable())) {
for (ForeignKey<?, ?> key : rhs.getReferences())
if (key.getFields().containsAll(unaliased) && unaliased.containsAll(key.getFields()))
return onKey(key);
@ -729,9 +728,9 @@ implements
@Override
public final JoinTable onKey(ForeignKey<?, ?> key) {
if (traverseJoins(lhs, false, r -> r, search(key.getTable())))
if (containsUnaliasedTable(lhs, key.getTable()))
return onKey(key, lhs, rhs);
else if (traverseJoins(rhs, false, r -> r, search(key.getTable())))
else if (containsUnaliasedTable(rhs, key.getTable()))
return onKey(key, rhs, lhs);
throw onKeyException(OnKeyExceptionReason.NOT_FOUND, null, null);

View File

@ -188,6 +188,7 @@ import static org.jooq.impl.Tools.aliasedFields;
import static org.jooq.impl.Tools.anyMatch;
import static org.jooq.impl.Tools.autoAlias;
import static org.jooq.impl.Tools.camelCase;
import static org.jooq.impl.Tools.containsUnaliasedTable;
import static org.jooq.impl.Tools.fieldArray;
import static org.jooq.impl.Tools.findAny;
import static org.jooq.impl.Tools.hasAmbiguousNames;
@ -197,7 +198,6 @@ import static org.jooq.impl.Tools.isWindow;
import static org.jooq.impl.Tools.map;
import static org.jooq.impl.Tools.qualify;
import static org.jooq.impl.Tools.recordType;
import static org.jooq.impl.Tools.search;
import static org.jooq.impl.Tools.selectQueryImpl;
// ...
import static org.jooq.impl.Tools.traverseJoins;
@ -1374,7 +1374,7 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
&& REQUIRES_DERIVED_TABLE_DML.contains(ctx.dialect())
&& !TRUE.equals(ctx.data(DATA_INSERT_SELECT))
&& (dmlTable = (Table<?>) ctx.data(DATA_DML_TARGET_TABLE)) != null
&& containsTable(dmlTable)) {
&& containsUnaliasedTable(getFrom(), dmlTable)) {
ctx.visit(DSL.select(asterisk()).from(asTable("t")));
}
@ -3795,10 +3795,6 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
return traverseJoins(getFrom(), true, r -> !r, (r, t) -> r && t.fieldsRow().size() > 0);
}
private final boolean containsTable(Table<?> table) {
return traverseJoins(getFrom(), false, r -> r, search(table));
}
@SuppressWarnings("unchecked")
@Override
final Class<? extends R> getRecordType0() {

View File

@ -6131,15 +6131,29 @@ final class Tools {
// TODO: In a new expression tree model, we'll support generic visitors of some sort
// ---------------------------------------------------------------------------------
static final BiFunction<Boolean, Table<?>, Boolean> search(Table<?> table) {
return (r, t) -> {
static final boolean containsDeclaredTable(Table<?> in, Table<?> search) {
return traverseJoins(in, false, r -> r, search(search, t -> t));
}
// [#6304] [#7626] Improved alias discovery
Table<?> t1 = defaultIfNull(Tools.aliased(table), table);
Table<?> t2 = defaultIfNull(Tools.aliased(t), t);
static final boolean containsDeclaredTable(Iterable<? extends Table<?>> in, Table<?> search) {
return traverseJoins(in, false, r -> r, search(search, t -> t));
}
return r || t1.equals(t2);
};
private static final BiFunction<Boolean, Table<?>, Boolean> search(Table<?> table, Function<? super Table<?>, ? extends Table<?>> f) {
Table<?> unaliased = f.apply(table);
return (r, t) -> r || unaliased.equals(f.apply(t));
}
static final boolean containsUnaliasedTable(Table<?> in, Table<?> search) {
// [#6304] [#7626] Improved alias discovery
return traverseJoins(in, false, r -> r, search(search, Tools::unalias));
}
static final boolean containsUnaliasedTable(Iterable<? extends Table<?>> in, Table<?> search) {
// [#6304] [#7626] Improved alias discovery
return traverseJoins(in, false, r -> r, search(search, Tools::unalias));
}
static final void traverseJoins(Iterable<? extends Table<?>> i, Consumer<? super Table<?>> consumer) {