[jOOQ/jOOQ#14988] Emulate LATERAL (TableImpl | JoinTable) where not
supported This includes: - [jOOQ/jOOQ#14985] Ensuring path joins work with APPLY - [jOOQ/jOOQ#14985] Ensuring path joins work with LATERAL In the latter case, we currently just omit the problem of making path joins work with LATERAL by avoiding wrapping a path in LATERAL. There might be a better solution for this in the future.
This commit is contained in:
parent
185792157d
commit
fa6fb4bb0d
@ -11810,7 +11810,14 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support({ FIREBIRD, MYSQL, POSTGRES, TRINO, YUGABYTEDB })
|
||||
public static <R extends Record> Table<R> lateral(TableLike<R> table) {
|
||||
return new Lateral<>(table.asTable());
|
||||
|
||||
// [#14988] LATERAL (table reference) isn't supported in any dialect
|
||||
// and it's also superfluous, so we'll just omit it to make
|
||||
// sure things like APPLY table reference are emulated correctly
|
||||
if (table instanceof TableImpl || table instanceof JoinTable)
|
||||
return (Table<R>) table;
|
||||
else
|
||||
return new Lateral<>(table.asTable());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -226,19 +226,19 @@ class DefaultRenderContext extends AbstractContext<RenderContext> implements Ren
|
||||
if (part instanceof TableImpl) {
|
||||
Table<?> root = (Table<?>) part;
|
||||
Table<?> child = root;
|
||||
List<Table<?>> tables = new ArrayList<>();
|
||||
List<TableImpl<?>> tables = new ArrayList<>();
|
||||
|
||||
// [#14985] Traverse paths only when referencing paths (!forceNew),
|
||||
// not when declaring them in FROM (forceNew)
|
||||
if (!forceNew) {
|
||||
while (root instanceof TableImpl && (child = ((TableImpl<?>) root).child) != null) {
|
||||
while ((child = TableImpl.child(root)) != null) {
|
||||
|
||||
// [#14985] If a subpath has been declared in FROM, join
|
||||
// to that, instead of the root.
|
||||
if (scopeStack.get(root) != null)
|
||||
break;
|
||||
|
||||
tables.add(root);
|
||||
tables.add((TableImpl<?>) root);
|
||||
root = child;
|
||||
}
|
||||
}
|
||||
@ -252,8 +252,8 @@ class DefaultRenderContext extends AbstractContext<RenderContext> implements Ren
|
||||
|
||||
JoinNode childNode = e.joinNode;
|
||||
for (int i = tables.size() - 1; i >= 0; i--) {
|
||||
Table<?> t = tables.get(i);
|
||||
ForeignKey<?, ?> k = ((TableImpl<?>) t).childPath;
|
||||
TableImpl<?> t = tables.get(i);
|
||||
ForeignKey<?, ?> k = t.childPath;
|
||||
|
||||
JoinNode next = childNode.children.get(k);
|
||||
if (next == null) {
|
||||
|
||||
@ -59,7 +59,6 @@ import static org.jooq.Clause.TABLE_JOIN_PARTITION_BY;
|
||||
import static org.jooq.Clause.TABLE_JOIN_SEMI_LEFT;
|
||||
import static org.jooq.Clause.TABLE_JOIN_STRAIGHT;
|
||||
import static org.jooq.Clause.TABLE_JOIN_USING;
|
||||
import static org.jooq.JoinType.CROSS_APPLY;
|
||||
import static org.jooq.JoinType.CROSS_JOIN;
|
||||
import static org.jooq.JoinType.FULL_OUTER_JOIN;
|
||||
import static org.jooq.JoinType.JOIN;
|
||||
@ -70,7 +69,6 @@ import static org.jooq.JoinType.NATURAL_FULL_OUTER_JOIN;
|
||||
import static org.jooq.JoinType.NATURAL_JOIN;
|
||||
import static org.jooq.JoinType.NATURAL_LEFT_OUTER_JOIN;
|
||||
import static org.jooq.JoinType.NATURAL_RIGHT_OUTER_JOIN;
|
||||
import static org.jooq.JoinType.OUTER_APPLY;
|
||||
import static org.jooq.JoinType.RIGHT_OUTER_JOIN;
|
||||
// ...
|
||||
// ...
|
||||
@ -98,13 +96,11 @@ import static org.jooq.SQLDialect.YUGABYTEDB;
|
||||
import static org.jooq.impl.ConditionProviderImpl.extractCondition;
|
||||
import static org.jooq.impl.DSL.condition;
|
||||
import static org.jooq.impl.DSL.exists;
|
||||
import static org.jooq.impl.DSL.lateral;
|
||||
import static org.jooq.impl.DSL.noCondition;
|
||||
import static org.jooq.impl.DSL.notExists;
|
||||
import static org.jooq.impl.DSL.selectFrom;
|
||||
import static org.jooq.impl.DSL.selectOne;
|
||||
import static org.jooq.impl.DSL.trueCondition;
|
||||
import static org.jooq.impl.Keywords.K_CROSS_JOIN_LATERAL;
|
||||
import static org.jooq.impl.Keywords.K_LEFT_JOIN_LATERAL;
|
||||
import static org.jooq.impl.Keywords.K_LEFT_OUTER_JOIN_LATERAL;
|
||||
import static org.jooq.impl.Keywords.K_ON;
|
||||
import static org.jooq.impl.Keywords.K_PARTITION_BY;
|
||||
import static org.jooq.impl.Keywords.K_USING;
|
||||
@ -238,11 +234,23 @@ implements
|
||||
|
||||
|
||||
|
||||
// [#14985] APPLY or LATERAL with path joins
|
||||
if ((this instanceof CrossApply || this instanceof OuterApply) && TableImpl.child(rhs) != null)
|
||||
ctx.visit($table2(selectFrom(rhs).asTable(rhs)));
|
||||
else if (rhs instanceof Lateral && TableImpl.child(((Lateral<?>) rhs).$arg1()) != null)
|
||||
ctx.visit($table2(lateral(selectFrom(((Lateral<?>) rhs).$arg1()).asTable(((Lateral<?>) rhs).$arg1()))));
|
||||
|
||||
// [#14988] Make sure APPLY table reference continues working by wrapping lateral(rhs)
|
||||
else if (this instanceof CrossApply && EMULATE_APPLY.contains(ctx.dialect()))
|
||||
ctx.visit(lhs.crossJoin(lateral(rhs)));
|
||||
else if (this instanceof OuterApply && EMULATE_APPLY.contains(ctx.dialect()))
|
||||
ctx.visit(lhs.leftJoin(lateral(rhs)).on(noCondition()));
|
||||
|
||||
|
||||
|
||||
|
||||
accept0(ctx);
|
||||
else
|
||||
accept0(ctx);
|
||||
}
|
||||
|
||||
private final void accept0(Context<?> ctx) {
|
||||
@ -319,17 +327,6 @@ implements
|
||||
toSQLJoinCondition(ctx);
|
||||
ctx.formatIndentEnd();
|
||||
}
|
||||
else if (OUTER_APPLY == translatedType && EMULATE_APPLY.contains(ctx.dialect())) {
|
||||
ctx.formatIndentStart()
|
||||
.formatSeparator()
|
||||
.start(TABLE_JOIN_ON)
|
||||
.visit(K_ON)
|
||||
.sql(' ')
|
||||
.visit(trueCondition())
|
||||
.end(TABLE_JOIN_ON)
|
||||
.formatIndentEnd();
|
||||
}
|
||||
|
||||
ctx.end(translatedClause)
|
||||
.formatIndentEnd();
|
||||
}
|
||||
@ -448,15 +445,6 @@ implements
|
||||
break;
|
||||
}
|
||||
|
||||
if (translatedType == CROSS_APPLY && EMULATE_APPLY.contains(ctx.dialect()))
|
||||
keyword = K_CROSS_JOIN_LATERAL;
|
||||
else if (translatedType == OUTER_APPLY && EMULATE_APPLY.contains(ctx.dialect()))
|
||||
if (ctx.settings().getRenderOptionalOuterKeyword() == RenderOptionalKeyword.OFF)
|
||||
keyword = K_LEFT_JOIN_LATERAL;
|
||||
else
|
||||
keyword = K_LEFT_OUTER_JOIN_LATERAL;
|
||||
|
||||
|
||||
return keyword;
|
||||
}
|
||||
|
||||
@ -572,8 +560,7 @@ implements
|
||||
}
|
||||
|
||||
// [#14985] Path joins additional conditions
|
||||
else if (rhs instanceof TableImpl
|
||||
&& ((TableImpl<?>) rhs).child != null
|
||||
else if (TableImpl.child(rhs) != null
|
||||
|
||||
// Do this only if we're *not* rendering implicit joins, in case of which join paths
|
||||
// are expected, and their predicates are already present.
|
||||
|
||||
@ -106,7 +106,6 @@ final class Keywords {
|
||||
static final Keyword K_CONTINUE = keyword("continue");
|
||||
static final Keyword K_COUNT = keyword("count");
|
||||
static final Keyword K_CREATE = keyword("create");
|
||||
static final Keyword K_CROSS_JOIN_LATERAL = keyword("cross join lateral");
|
||||
static final Keyword K_CUBE = keyword("cube");
|
||||
static final Keyword K_CURRENT = keyword("current");
|
||||
static final Keyword K_CURRENT_ROW = keyword("current row");
|
||||
@ -247,8 +246,6 @@ final class Keywords {
|
||||
static final Keyword K_LATERAL = keyword("lateral");
|
||||
static final Keyword K_LEADING = keyword("leading");
|
||||
static final Keyword K_LEAVE = keyword("leave");
|
||||
static final Keyword K_LEFT_JOIN_LATERAL = keyword("left join lateral");
|
||||
static final Keyword K_LEFT_OUTER_JOIN_LATERAL = keyword("left outer join lateral");
|
||||
static final Keyword K_LET = keyword("let");
|
||||
static final Keyword K_LIKE = keyword("like");
|
||||
static final Keyword K_LIKE_REGEX = keyword("like_regex");
|
||||
|
||||
@ -38,6 +38,7 @@
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.DSL.lateral;
|
||||
import static org.jooq.impl.DSL.selectFrom;
|
||||
import static org.jooq.impl.Keywords.K_LATERAL;
|
||||
|
||||
import org.jooq.Context;
|
||||
|
||||
@ -288,6 +288,14 @@ implements
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
static final Table<?> child(Table<?> t) {
|
||||
if (t instanceof TableImpl<?> ti)
|
||||
if (ti.child != null)
|
||||
return ti.child;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
final Condition childPathCondition() {
|
||||
if (child == null)
|
||||
return noCondition();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user