From 9bc5fe43c0f8239f6b7c22248bd26ca044f60b8a Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Thu, 15 Jul 2021 14:08:02 +0200 Subject: [PATCH] [jOOQ/jOOQ#12194] MySQL DELETE .. USING with JOIN produces duplicate table declarations in USING clause --- .../java/org/jooq/impl/DeleteQueryImpl.java | 6 ++-- .../main/java/org/jooq/impl/JoinTable.java | 11 ++++---- .../java/org/jooq/impl/SelectQueryImpl.java | 8 ++---- jOOQ/src/main/java/org/jooq/impl/Tools.java | 28 ++++++++++++++----- 4 files changed, 32 insertions(+), 21 deletions(-) diff --git a/jOOQ/src/main/java/org/jooq/impl/DeleteQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/DeleteQueryImpl.java index e172a70d0c..f32b20c391 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DeleteQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/DeleteQueryImpl.java @@ -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 extends AbstractDMLQuery 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); } diff --git a/jOOQ/src/main/java/org/jooq/impl/JoinTable.java b/jOOQ/src/main/java/org/jooq/impl/JoinTable.java index 00423601e6..6fc051505a 100755 --- a/jOOQ/src/main/java/org/jooq/impl/JoinTable.java +++ b/jOOQ/src/main/java/org/jooq/impl/JoinTable.java @@ -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); diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java index ced1ced171..71c7cc8cf4 100644 --- a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java @@ -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 extends AbstractResultQuery 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 extends AbstractResultQuery 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 getRecordType0() { diff --git a/jOOQ/src/main/java/org/jooq/impl/Tools.java b/jOOQ/src/main/java/org/jooq/impl/Tools.java index 8a23f5ac12..4e590d3543 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Tools.java +++ b/jOOQ/src/main/java/org/jooq/impl/Tools.java @@ -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> 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> in, Table search) { + return traverseJoins(in, false, r -> r, search(search, t -> t)); + } - return r || t1.equals(t2); - }; + private static final BiFunction, Boolean> search(Table table, Function, ? 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> in, Table search) { + + // [#6304] [#7626] Improved alias discovery + return traverseJoins(in, false, r -> r, search(search, Tools::unalias)); } static final void traverseJoins(Iterable> i, Consumer> consumer) {