From 08f98dc81a6739e4da9876c8078629f2a559819d Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Mon, 8 Mar 2021 22:54:57 +0100 Subject: [PATCH] [jOOQ/jOOQ#11587] Fix ordering of TOP_LEVEL_CTE --- .../main/java/org/jooq/impl/AbstractDMLQuery.java | 6 ++---- .../org/jooq/impl/CommonTableExpressionList.java | 8 +++++++- jOOQ/src/main/java/org/jooq/impl/ScopeMarker.java | 3 +++ .../main/java/org/jooq/impl/SelectQueryImpl.java | 13 +++---------- jOOQ/src/main/java/org/jooq/impl/TopLevelCte.java | 8 ++++++++ 5 files changed, 23 insertions(+), 15 deletions(-) diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractDMLQuery.java b/jOOQ/src/main/java/org/jooq/impl/AbstractDMLQuery.java index 4c9475c479..636a07239e 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractDMLQuery.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractDMLQuery.java @@ -67,6 +67,7 @@ import static org.jooq.SQLDialect.POSTGRES; // ... // ... import static org.jooq.conf.SettingsTools.renderLocale; +import static org.jooq.impl.CommonTableExpressionList.markTopLevelCteAndAccept; import static org.jooq.impl.DSL.name; import static org.jooq.impl.DSL.select; import static org.jooq.impl.DSL.unquotedName; @@ -348,10 +349,7 @@ abstract class AbstractDMLQuery extends AbstractRowCountQuery if (w != null) ctx.visit(w); else - ctx.scopeMarkStart(TOP_LEVEL_CTE.beforeFirst) - .scopeMarkEnd(TOP_LEVEL_CTE.beforeFirst) - .scopeMarkStart(TOP_LEVEL_CTE.afterLast) - .scopeMarkEnd(TOP_LEVEL_CTE.afterLast); + markTopLevelCteAndAccept(ctx, c -> {}); boolean previousDeclareFields = ctx.declareFields(); diff --git a/jOOQ/src/main/java/org/jooq/impl/CommonTableExpressionList.java b/jOOQ/src/main/java/org/jooq/impl/CommonTableExpressionList.java index 0143480419..d5d1d75d38 100644 --- a/jOOQ/src/main/java/org/jooq/impl/CommonTableExpressionList.java +++ b/jOOQ/src/main/java/org/jooq/impl/CommonTableExpressionList.java @@ -39,6 +39,8 @@ package org.jooq.impl; import static org.jooq.impl.ScopeMarker.TOP_LEVEL_CTE; +import java.util.function.Consumer; + import org.jooq.CommonTableExpression; import org.jooq.Context; @@ -56,11 +58,15 @@ final class CommonTableExpressionList extends QueryPartList ctx) { + markTopLevelCteAndAccept(ctx, c -> super.accept(c)); + } + + static void markTopLevelCteAndAccept(Context ctx, Consumer> consumer) { if (ctx.subqueryLevel() == 0) ctx.scopeMarkStart(TOP_LEVEL_CTE.beforeFirst) .scopeMarkEnd(TOP_LEVEL_CTE.beforeFirst); - super.accept(ctx); + consumer.accept(ctx); if (ctx.subqueryLevel() == 0) ctx.scopeMarkStart(TOP_LEVEL_CTE.afterLast) diff --git a/jOOQ/src/main/java/org/jooq/impl/ScopeMarker.java b/jOOQ/src/main/java/org/jooq/impl/ScopeMarker.java index 8a6716846b..7a527cb35a 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ScopeMarker.java +++ b/jOOQ/src/main/java/org/jooq/impl/ScopeMarker.java @@ -130,7 +130,10 @@ enum ScopeMarker { ctx.sql(' '); } + // [#11587] Recurse to allow for deeply nested CTE + ctx.scopeStart().data(DATA_TOP_LEVEL_CTE, new TopLevelCte()); ctx.declareCTE(true).visit(cte).declareCTE(false); + ctx.scopeEnd(); if (noWith) { if (single) diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java index 96f44451cf..376c20741d 100644 --- a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java @@ -102,7 +102,6 @@ import static org.jooq.SQLDialect.SQLITE; // ... // ... // ... -// ... import static org.jooq.SortOrder.DESC; import static org.jooq.conf.ParamType.INLINED; import static org.jooq.impl.AsteriskImpl.SUPPORT_NATIVE_EXCEPT; @@ -112,6 +111,7 @@ import static org.jooq.impl.CombineOperator.INTERSECT; import static org.jooq.impl.CombineOperator.INTERSECT_ALL; import static org.jooq.impl.CombineOperator.UNION; import static org.jooq.impl.CombineOperator.UNION_ALL; +import static org.jooq.impl.CommonTableExpressionList.markTopLevelCteAndAccept; import static org.jooq.impl.DSL.asterisk; import static org.jooq.impl.DSL.createTable; import static org.jooq.impl.DSL.falseCondition; @@ -166,7 +166,6 @@ import static org.jooq.impl.SQLDataType.JSON; import static org.jooq.impl.SQLDataType.JSONB; import static org.jooq.impl.SQLDataType.VARCHAR; import static org.jooq.impl.SQLDataType.XML; -import static org.jooq.impl.ScopeMarker.TOP_LEVEL_CTE; import static org.jooq.impl.Tools.EMPTY_FIELD; import static org.jooq.impl.Tools.EMPTY_SORTFIELD; import static org.jooq.impl.Tools.fieldArray; @@ -251,7 +250,6 @@ import org.jooq.TablePartitionByStep; // ... import org.jooq.WindowDefinition; import org.jooq.XML; -import org.jooq.conf.ParamType; import org.jooq.exception.DataAccessException; import org.jooq.impl.ForLock.ForLockMode; import org.jooq.impl.ForLock.ForLockWaitMode; @@ -262,8 +260,6 @@ import org.jooq.tools.Convert; import org.jooq.tools.JooqLogger; import org.jooq.tools.StringUtils; -import org.jetbrains.annotations.NotNull; - /** * A sub-select is a SELECT statement that can be combined with * other SELECT statement in UNIONs and similar @@ -1348,11 +1344,8 @@ final class SelectQueryImpl extends AbstractResultQuery imp if (with != null) context.visit(with); - else if (topLevelCte && context.subqueryLevel() == 0) - context.scopeMarkStart(TOP_LEVEL_CTE.beforeFirst) - .scopeMarkEnd(TOP_LEVEL_CTE.beforeFirst) - .scopeMarkStart(TOP_LEVEL_CTE.afterLast) - .scopeMarkEnd(TOP_LEVEL_CTE.afterLast); + else if (topLevelCte) + markTopLevelCteAndAccept(context, c -> {}); pushWindow(context); diff --git a/jOOQ/src/main/java/org/jooq/impl/TopLevelCte.java b/jOOQ/src/main/java/org/jooq/impl/TopLevelCte.java index a7dd9c9b7c..b902adeecf 100644 --- a/jOOQ/src/main/java/org/jooq/impl/TopLevelCte.java +++ b/jOOQ/src/main/java/org/jooq/impl/TopLevelCte.java @@ -37,6 +37,9 @@ */ package org.jooq.impl; +import static org.jooq.impl.CommonTableExpressionList.markTopLevelCteAndAccept; + +import org.jooq.Context; import org.jooq.QueryPart; import org.jooq.impl.ScopeMarker.ScopeContent; @@ -50,6 +53,11 @@ final class TopLevelCte extends QueryPartList implements ScopeContent */ private static final long serialVersionUID = 9211135511038680791L; + @Override + public void accept(Context ctx) { + markTopLevelCteAndAccept(ctx, c -> super.accept(c)); + } + @Override public final boolean declaresCTE() { return true;