diff --git a/jOOQ/src/main/java/org/jooq/impl/DSL.java b/jOOQ/src/main/java/org/jooq/impl/DSL.java index 9fad863f95..37fc6255e7 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DSL.java +++ b/jOOQ/src/main/java/org/jooq/impl/DSL.java @@ -11810,7 +11810,14 @@ public class DSL { @NotNull @Support({ FIREBIRD, MYSQL, POSTGRES, TRINO, YUGABYTEDB }) public static Table lateral(TableLike 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) table; + else + return new Lateral<>(table.asTable()); } /** diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java index 0a7728df87..1de6d18bee 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java @@ -226,19 +226,19 @@ class DefaultRenderContext extends AbstractContext implements Ren if (part instanceof TableImpl) { Table root = (Table) part; Table child = root; - List> tables = new ArrayList<>(); + List> 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 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) { diff --git a/jOOQ/src/main/java/org/jooq/impl/JoinTable.java b/jOOQ/src/main/java/org/jooq/impl/JoinTable.java index 54fb308d42..9ceef57e7d 100755 --- a/jOOQ/src/main/java/org/jooq/impl/JoinTable.java +++ b/jOOQ/src/main/java/org/jooq/impl/JoinTable.java @@ -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. diff --git a/jOOQ/src/main/java/org/jooq/impl/Keywords.java b/jOOQ/src/main/java/org/jooq/impl/Keywords.java index 99f583e066..7b84181d5d 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Keywords.java +++ b/jOOQ/src/main/java/org/jooq/impl/Keywords.java @@ -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"); diff --git a/jOOQ/src/main/java/org/jooq/impl/Lateral.java b/jOOQ/src/main/java/org/jooq/impl/Lateral.java index c694b97131..ff02e4fe38 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Lateral.java +++ b/jOOQ/src/main/java/org/jooq/impl/Lateral.java @@ -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; diff --git a/jOOQ/src/main/java/org/jooq/impl/TableImpl.java b/jOOQ/src/main/java/org/jooq/impl/TableImpl.java index 58108baff5..506638f364 100644 --- a/jOOQ/src/main/java/org/jooq/impl/TableImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/TableImpl.java @@ -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();