From 16cd34b15805fbfd448d12ac6b1cab6a8db08136 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Wed, 3 Feb 2021 23:13:12 +0100 Subject: [PATCH] [jOOQ/jOOQ#11366] Collect nested DECLARE statements in Firebird and pull them up to the top level block --- .../main/java/org/jooq/impl/BlockImpl.java | 26 ++++++++-- .../org/jooq/impl/CreateProcedureImpl.java | 3 ++ .../java/org/jooq/impl/DeclarationImpl.java | 29 +++++++++++ .../org/jooq/impl/DefaultRenderContext.java | 49 ++++++++++++++++--- .../src/main/java/org/jooq/impl/LoopImpl.java | 5 ++ .../main/java/org/jooq/impl/ScopeMarkers.java | 1 + jOOQ/src/main/java/org/jooq/impl/Tools.java | 7 +++ 7 files changed, 110 insertions(+), 10 deletions(-) diff --git a/jOOQ/src/main/java/org/jooq/impl/BlockImpl.java b/jOOQ/src/main/java/org/jooq/impl/BlockImpl.java index 6ca52716c6..add1cfb840 100644 --- a/jOOQ/src/main/java/org/jooq/impl/BlockImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/BlockImpl.java @@ -64,14 +64,17 @@ import static org.jooq.impl.Keywords.K_EXECUTE_IMMEDIATE; import static org.jooq.impl.Keywords.K_EXECUTE_STATEMENT; import static org.jooq.impl.Keywords.K_NOT; import static org.jooq.impl.Keywords.K_PROCEDURE; +import static org.jooq.impl.ScopeMarkers.BEFORE_FIRST_TOP_LEVEL_DECLARATION; import static org.jooq.impl.Tools.decrement; import static org.jooq.impl.Tools.increment; import static org.jooq.impl.Tools.toplevel; import static org.jooq.impl.Tools.BooleanDataKey.DATA_FORCE_STATIC_STATEMENT; import static org.jooq.impl.Tools.DataKey.DATA_BLOCK_NESTING; +import static org.jooq.impl.Tools.DataKey.DATA_TOP_LEVEL_DECLARATIONS; import java.util.ArrayList; import java.util.Collection; +import java.util.LinkedHashMap; import java.util.List; import java.util.Set; @@ -125,12 +128,13 @@ final class BlockImpl extends AbstractRowCountQuery implements Block { case FIREBIRD: { if (increment(ctx.data(), DATA_BLOCK_NESTING)) { ctx.paramType(INLINED) - .visit(K_EXECUTE_BLOCK).sql(' ').visit(K_AS).sql(' '); + .visit(K_EXECUTE_BLOCK).sql(' ').visit(K_AS).formatSeparator(); ctx.data(DATA_FORCE_STATIC_STATEMENT, true); + topLevelDeclarations(ctx, () -> accept0(ctx)); } - - accept0(ctx); + else + accept0(ctx); decrement(ctx.data(), DATA_BLOCK_NESTING); break; @@ -229,6 +233,21 @@ final class BlockImpl extends AbstractRowCountQuery implements Block { } } + static final void topLevelDeclarations(Context ctx, Runnable runnable) { + + + + + + + runnable.run(); + + + + + } + + static final void bodyAsString(Context ctx, Keyword keyword, Runnable runnable) { ParamType previous = ctx.paramType(); @@ -350,6 +369,7 @@ final class BlockImpl extends AbstractRowCountQuery implements Block { + ctx.sql(';'); diff --git a/jOOQ/src/main/java/org/jooq/impl/CreateProcedureImpl.java b/jOOQ/src/main/java/org/jooq/impl/CreateProcedureImpl.java index 35cde4cee1..2aa8956fb1 100644 --- a/jOOQ/src/main/java/org/jooq/impl/CreateProcedureImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/CreateProcedureImpl.java @@ -286,6 +286,9 @@ package org.jooq.impl; + + + diff --git a/jOOQ/src/main/java/org/jooq/impl/DeclarationImpl.java b/jOOQ/src/main/java/org/jooq/impl/DeclarationImpl.java index 7eeac22b0b..0e86c28b4d 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DeclarationImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/DeclarationImpl.java @@ -148,6 +148,35 @@ package org.jooq.impl; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java index 41de57578d..0fa90e2ff2 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java @@ -50,9 +50,11 @@ import static org.jooq.impl.Identifiers.QUOTE_START_DELIMITER; import static org.jooq.impl.Keywords.K_WITH; import static org.jooq.impl.ScopeMarkers.AFTER_LAST_TOP_LEVEL_CTE; import static org.jooq.impl.ScopeMarkers.BEFORE_FIRST_TOP_LEVEL_CTE; +import static org.jooq.impl.Tools.increment; import static org.jooq.impl.Tools.BooleanDataKey.DATA_COUNT_BIND_VALUES; import static org.jooq.impl.Tools.DataKey.DATA_PREPEND_SQL; import static org.jooq.impl.Tools.DataKey.DATA_TOP_LEVEL_CTE; +import static org.jooq.impl.Tools.DataKey.DATA_TOP_LEVEL_DECLARATIONS; import java.util.ArrayDeque; import java.util.ArrayList; @@ -60,6 +62,7 @@ import java.util.Arrays; import java.util.Deque; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.regex.Pattern; @@ -73,7 +76,9 @@ import org.jooq.QueryPart; import org.jooq.QueryPartInternal; import org.jooq.RenderContext; import org.jooq.SQLDialect; +import org.jooq.Statement; import org.jooq.Table; +// ... import org.jooq.conf.RenderFormatting; import org.jooq.conf.RenderKeywordCase; import org.jooq.conf.RenderNameCase; @@ -82,6 +87,7 @@ import org.jooq.conf.Settings; import org.jooq.conf.SettingsTools; import org.jooq.exception.ControlFlowSignal; import org.jooq.exception.DataAccessException; +import org.jooq.impl.Tools.DataKey; import org.jooq.tools.JooqLogger; import org.jooq.tools.StringUtils; @@ -226,21 +232,33 @@ class DefaultRenderContext extends AbstractContext implements Ren return this; } + @SuppressWarnings("unchecked") @Override void scopeEnd0() { // TODO: Think about a more appropriate location for this logic, rather // than the generic DefaultRenderContext, which shouldn't know anything // about the individual query parts that it is rendering. + + + + TopLevelCte cte = null; ScopeStackElement beforeFirstCte = null; ScopeStackElement afterLastCte = null; - if (subqueryLevel() == 0 - && (cte = (TopLevelCte) data(DATA_TOP_LEVEL_CTE)) != null - && !cte.isEmpty()) { - beforeFirstCte = scopeStack.get(BEFORE_FIRST_TOP_LEVEL_CTE); - afterLastCte = scopeStack.get(AFTER_LAST_TOP_LEVEL_CTE); + if (subqueryLevel() == 0) { + + + + + + + + if ((cte = (TopLevelCte) data(DATA_TOP_LEVEL_CTE)) != null && !cte.isEmpty()) { + beforeFirstCte = scopeStack.get(BEFORE_FIRST_TOP_LEVEL_CTE); + afterLastCte = scopeStack.get(AFTER_LAST_TOP_LEVEL_CTE); + } } outer: @@ -253,8 +271,25 @@ class DefaultRenderContext extends AbstractContext implements Ren else if (e1.positions == null) { continue outer; } - else if (e1 == beforeFirstCte) { - boolean single = cte != null && cte.size() == 1; + + + + + + + + + + + + + + + + + + else if (e1 == beforeFirstCte && cte != null) { + boolean single = cte.size() == 1; RenderContext render = configuration.dsl().renderContext(); // There is no WITH clause diff --git a/jOOQ/src/main/java/org/jooq/impl/LoopImpl.java b/jOOQ/src/main/java/org/jooq/impl/LoopImpl.java index cce77f9d43..00da33fb1b 100644 --- a/jOOQ/src/main/java/org/jooq/impl/LoopImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/LoopImpl.java @@ -343,6 +343,11 @@ package org.jooq.impl; + + + + + diff --git a/jOOQ/src/main/java/org/jooq/impl/ScopeMarkers.java b/jOOQ/src/main/java/org/jooq/impl/ScopeMarkers.java index 57b027b61d..45ae604c9e 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ScopeMarkers.java +++ b/jOOQ/src/main/java/org/jooq/impl/ScopeMarkers.java @@ -49,6 +49,7 @@ import org.jooq.RenderContext; */ enum ScopeMarkers implements QueryPartInternal { + BEFORE_FIRST_TOP_LEVEL_DECLARATION, BEFORE_FIRST_TOP_LEVEL_CTE, AFTER_LAST_TOP_LEVEL_CTE; diff --git a/jOOQ/src/main/java/org/jooq/impl/Tools.java b/jOOQ/src/main/java/org/jooq/impl/Tools.java index 58010ad85e..98d6cb3d39 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Tools.java +++ b/jOOQ/src/main/java/org/jooq/impl/Tools.java @@ -601,6 +601,13 @@ final class Tools { + + + + + + +