[jOOQ/jOOQ#5810] Emulate QUALIFY where not supported - WIP
This commit is contained in:
parent
4febe602d8
commit
66d875a922
@ -61,6 +61,7 @@ import static org.jooq.impl.DSL.sql;
|
||||
import static org.jooq.impl.DSL.table;
|
||||
import static org.jooq.impl.DSL.val;
|
||||
import static org.jooq.impl.Tools.EMPTY_FIELD;
|
||||
import static org.jooq.impl.Tools.traverseJoins;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
@ -590,7 +591,7 @@ abstract class AbstractTable<R extends Record> extends AbstractNamed implements
|
||||
List<ForeignKey<R, O>> result = new ArrayList<>();
|
||||
|
||||
for (ForeignKey<R, ?> reference : getReferences()) {
|
||||
for (Table<?> o : flattenJoins(other)) {
|
||||
traverseJoins(other, o -> {
|
||||
if (o.equals(reference.getKey().getTable())) {
|
||||
result.add((ForeignKey<R, O>) reference);
|
||||
}
|
||||
@ -602,27 +603,12 @@ abstract class AbstractTable<R extends Record> extends AbstractNamed implements
|
||||
if (aliased != null && aliased.equals(reference.getKey().getTable()))
|
||||
result.add((ForeignKey<R, O>) reference);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(result);
|
||||
}
|
||||
|
||||
private final List<Table<?>> flattenJoins(Table<?> other) {
|
||||
return flattenJoins(other, new ArrayList<>());
|
||||
}
|
||||
|
||||
private final List<Table<?>> flattenJoins(Table<?> other, List<Table<?>> list) {
|
||||
if (other instanceof JoinTable) {
|
||||
flattenJoins(((JoinTable) other).lhs, list);
|
||||
flattenJoins(((JoinTable) other).rhs, list);
|
||||
}
|
||||
else
|
||||
list.add(other);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>
|
||||
|
||||
@ -102,12 +102,13 @@ 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.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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@ -665,7 +666,7 @@ implements
|
||||
unaliased.set(i, (TableField<?, ?>) alias.wrapped().field(f));
|
||||
}
|
||||
|
||||
if (search(lhs, keyFields[0].getTable()) != null) {
|
||||
if (traverseJoins(lhs, false, r -> r, search(keyFields[0].getTable()))) {
|
||||
for (ForeignKey<?, ?> key : lhs.getReferences())
|
||||
if (key.getFields().containsAll(unaliased) && unaliased.containsAll(key.getFields()))
|
||||
return onKey(key);
|
||||
@ -674,7 +675,7 @@ implements
|
||||
if (key.getFields().containsAll(unaliased))
|
||||
return onKey(key);
|
||||
}
|
||||
else if (search(rhs, keyFields[0].getTable()) != null) {
|
||||
else if (traverseJoins(rhs, false, r -> r, search(keyFields[0].getTable()))) {
|
||||
for (ForeignKey<?, ?> key : rhs.getReferences())
|
||||
if (key.getFields().containsAll(unaliased) && unaliased.containsAll(key.getFields()))
|
||||
return onKey(key);
|
||||
@ -690,40 +691,14 @@ implements
|
||||
|
||||
@Override
|
||||
public final JoinTable onKey(ForeignKey<?, ?> key) {
|
||||
if (search(lhs, key.getTable()) != null)
|
||||
if (traverseJoins(lhs, false, r -> r, search(key.getTable())))
|
||||
return onKey(key, lhs, rhs);
|
||||
else if (search(rhs, key.getTable()) != null)
|
||||
else if (traverseJoins(rhs, false, r -> r, search(key.getTable())))
|
||||
return onKey(key, rhs, lhs);
|
||||
|
||||
throw onKeyException(OnKeyExceptionReason.NOT_FOUND, null, null);
|
||||
}
|
||||
|
||||
private final Table<?> search(Table<?> tree, Table<?> search) {
|
||||
|
||||
// [#6304] [#7626] Improved alias discovery
|
||||
Alias<? extends Table<?>> treeAlias = Tools.alias(tree);
|
||||
Alias<? extends Table<?>> searchAlias = Tools.alias(search);
|
||||
|
||||
if (treeAlias != null || searchAlias != null) {
|
||||
return search(
|
||||
treeAlias != null ? treeAlias.wrapped() : tree,
|
||||
searchAlias != null ? searchAlias.wrapped() : search
|
||||
);
|
||||
}
|
||||
else if (tree instanceof JoinTable) {
|
||||
JoinTable t = (JoinTable) tree;
|
||||
|
||||
Table<?> r = search(t.lhs, search);
|
||||
if (r == null)
|
||||
r = search(t.rhs, search);
|
||||
|
||||
return r;
|
||||
}
|
||||
else {
|
||||
return search.equals(tree) ? tree : null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private final JoinTable onKey(ForeignKey<?, ?> key, Table<?> fk, Table<?> pk) {
|
||||
JoinTable result = this;
|
||||
|
||||
@ -176,6 +176,7 @@ import static org.jooq.impl.Tools.hasAmbiguousNames;
|
||||
import static org.jooq.impl.Tools.isNotEmpty;
|
||||
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.traverseConditions;
|
||||
import static org.jooq.impl.Tools.traverseJoins;
|
||||
@ -199,6 +200,7 @@ import static org.jooq.impl.Tools.DataKey.DATA_SELECT_ALIASES;
|
||||
import static org.jooq.impl.Tools.DataKey.DATA_SELECT_INTO_TABLE;
|
||||
import static org.jooq.impl.Tools.DataKey.DATA_TOP_LEVEL_CTE;
|
||||
import static org.jooq.impl.Tools.DataKey.DATA_WINDOW_DEFINITIONS;
|
||||
import static org.jooq.tools.StringUtils.defaultIfNull;
|
||||
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.util.ArrayDeque;
|
||||
@ -606,7 +608,7 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
|
||||
|
||||
private final SelectQueryImpl<R> nest(SelectQueryImpl<R> result, SelectQueryImpl<R> nested, Function<? super SelectQueryImpl<R>, ? extends SelectQueryImpl<R>> nestedFinisher) {
|
||||
|
||||
// [#10716] TODO: Qualify all fields with c1, c2, to avoid ambiguous
|
||||
// [#10716] TODO: Qualify all fields with c1, c2, to avoid ambiguous fields in derived tables
|
||||
nested = nestedFinisher.apply(nested);
|
||||
Table<R> t = nested.asTable("t");
|
||||
traverseJoins(from, t0 -> result.localQueryPartMapping.put(t0, t));
|
||||
@ -1351,7 +1353,6 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@ -3656,40 +3657,11 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
|
||||
}
|
||||
|
||||
private final boolean knownTableSource() {
|
||||
for (Table<?> table : getFrom())
|
||||
if (!knownTable(table))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private final boolean knownTable(Table<?> table) {
|
||||
if (table instanceof JoinTable)
|
||||
return knownTable(((JoinTable) table).lhs) && knownTable(((JoinTable) table).rhs);
|
||||
else
|
||||
return table.fieldsRow().size() > 0;
|
||||
return traverseJoins(getFrom(), true, r -> !r, (r, t) -> r && t.fieldsRow().size() > 0);
|
||||
}
|
||||
|
||||
private final boolean containsTable(Table<?> table) {
|
||||
for (Table<?> t : getFrom())
|
||||
if (containsTable(t, table))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private final boolean containsTable(Table<?> table, Table<?> contained) {
|
||||
Table<?> alias;
|
||||
|
||||
if ((alias = Tools.aliased(table)) != null)
|
||||
return containsTable(alias, contained);
|
||||
else if ((alias = Tools.aliased(contained)) != null)
|
||||
return containsTable(table, alias);
|
||||
else if (table instanceof JoinTable)
|
||||
return containsTable(((JoinTable) table).lhs, contained)
|
||||
|| containsTable(((JoinTable) table).rhs, contained);
|
||||
else
|
||||
return contained.equals(table);
|
||||
return traverseJoins(getFrom(), false, r -> r, search(table));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@ -105,6 +105,7 @@ import static org.jooq.impl.DSL.row;
|
||||
import static org.jooq.impl.DSL.select;
|
||||
import static org.jooq.impl.DSL.val;
|
||||
import static org.jooq.impl.DefaultExecuteContext.localConnection;
|
||||
import static org.jooq.impl.DefaultParseContext.SUPPORTS_HASH_COMMENT_SYNTAX;
|
||||
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;
|
||||
@ -154,7 +155,6 @@ import static org.jooq.impl.Keywords.K_START_WITH;
|
||||
import static org.jooq.impl.Keywords.K_THEN;
|
||||
import static org.jooq.impl.Keywords.K_THROW;
|
||||
import static org.jooq.impl.Keywords.K_WHEN;
|
||||
import static org.jooq.impl.DefaultParseContext.SUPPORTS_HASH_COMMENT_SYNTAX;
|
||||
import static org.jooq.impl.SQLDataType.BLOB;
|
||||
import static org.jooq.impl.SQLDataType.CLOB;
|
||||
import static org.jooq.impl.SQLDataType.JSON;
|
||||
@ -217,7 +217,9 @@ import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.ForkJoinPool.ManagedBlocker;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@ -6093,18 +6095,62 @@ 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) -> {
|
||||
|
||||
// [#6304] [#7626] Improved alias discovery
|
||||
Table<?> t1 = defaultIfNull(Tools.aliased(table), table);
|
||||
Table<?> t2 = defaultIfNull(Tools.aliased(t), t);
|
||||
|
||||
return r || t1.equals(t2);
|
||||
};
|
||||
}
|
||||
|
||||
static final void traverseJoins(Iterable<? extends Table<?>> i, Consumer<? super Table<?>> consumer) {
|
||||
for (Table<?> t : i)
|
||||
traverseJoins(t, consumer);
|
||||
}
|
||||
|
||||
static final void traverseJoins(Table<?> t, Consumer<? super Table<?>> consumer) {
|
||||
traverseJoins(t, null, x -> false, (result, x) -> { consumer.accept(x); return result; });
|
||||
}
|
||||
|
||||
static final <T> T traverseJoins(
|
||||
Iterable<? extends Table<?>> i,
|
||||
T result,
|
||||
Predicate<? super T> abort,
|
||||
BiFunction<? super T, ? super Table<?>, ? extends T> function
|
||||
) {
|
||||
for (Table<?> t : i)
|
||||
if (abort.test(result))
|
||||
return result;
|
||||
else
|
||||
result = traverseJoins(t, result, abort, function);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static final <T> T traverseJoins(
|
||||
Table<?> t,
|
||||
T result,
|
||||
Predicate<? super T> abort,
|
||||
BiFunction<? super T, ? super Table<?>, ? extends T> function
|
||||
) {
|
||||
if (abort.test(result))
|
||||
return result;
|
||||
|
||||
if (t instanceof JoinTable) {
|
||||
traverseJoins(((JoinTable) t).lhs, consumer);
|
||||
traverseJoins(((JoinTable) t).rhs, consumer);
|
||||
result = traverseJoins(((JoinTable) t).lhs, result, abort, function);
|
||||
|
||||
if (abort.test(result))
|
||||
return result;
|
||||
|
||||
result = traverseJoins(((JoinTable) t).rhs, result, abort, function);
|
||||
}
|
||||
else
|
||||
consumer.accept(t);
|
||||
result = function.apply(result, t);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static final void traverseSelectList(SelectFieldList<?> list, Consumer<? super Field<?>> consumer) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user