From d3dc0ac85743b225ebdb7f4b2c84fd4c08231ee3 Mon Sep 17 00:00:00 2001 From: lukaseder Date: Wed, 6 Feb 2019 15:32:01 +0100 Subject: [PATCH] [#8302] Emulate procedural languages in H2 --- jOOQ/src/main/java/org/jooq/DSLContext.java | 4 +- jOOQ/src/main/java/org/jooq/Declaration.java | 1 + jOOQ/src/main/java/org/jooq/ForByStep.java | 2 + jOOQ/src/main/java/org/jooq/ForInStep.java | 1 + jOOQ/src/main/java/org/jooq/IfElseStep.java | 1 + jOOQ/src/main/java/org/jooq/IfThenStep.java | 1 + jOOQ/src/main/java/org/jooq/LoopStep.java | 1 + .../main/java/org/jooq/RepeatUntilStep.java | 1 + jOOQ/src/main/java/org/jooq/Variable.java | 1 + .../main/java/org/jooq/impl/Assignment.java | 51 ++++++++ .../main/java/org/jooq/impl/BlockImpl.java | 113 ++++++++++++++++-- .../src/main/java/org/jooq/impl/Continue.java | 10 ++ jOOQ/src/main/java/org/jooq/impl/DSL.java | 4 +- .../java/org/jooq/impl/DeclarationImpl.java | 18 +++ jOOQ/src/main/java/org/jooq/impl/Exit.java | 10 ++ jOOQ/src/main/java/org/jooq/impl/IfImpl.java | 16 +++ .../src/main/java/org/jooq/impl/Keywords.java | 2 + .../main/java/org/jooq/impl/LabelImpl.java | 1 + .../java/org/jooq/impl/LabelledStatement.java | 1 + .../src/main/java/org/jooq/impl/LoopImpl.java | 72 +++++++++++ .../main/java/org/jooq/impl/VariableImpl.java | 18 +++ 21 files changed, 315 insertions(+), 14 deletions(-) diff --git a/jOOQ/src/main/java/org/jooq/DSLContext.java b/jOOQ/src/main/java/org/jooq/DSLContext.java index e907a1b92e..52e77aaa8a 100644 --- a/jOOQ/src/main/java/org/jooq/DSLContext.java +++ b/jOOQ/src/main/java/org/jooq/DSLContext.java @@ -742,7 +742,7 @@ public interface DSLContext extends Scope , AutoCloseable { * * @see DSL#begin(Statement...) */ - @Support({ FIREBIRD, MARIADB, POSTGRES }) + @Support({ FIREBIRD, H2, MARIADB, POSTGRES }) Block begin(Statement... statements); /** @@ -750,7 +750,7 @@ public interface DSLContext extends Scope , AutoCloseable { * * @see DSL#begin(Collection) */ - @Support({ FIREBIRD, MARIADB, POSTGRES }) + @Support({ FIREBIRD, H2, MARIADB, POSTGRES }) Block begin(Collection statements); diff --git a/jOOQ/src/main/java/org/jooq/Declaration.java b/jOOQ/src/main/java/org/jooq/Declaration.java index 4357e8be0d..160afcdc7f 100644 --- a/jOOQ/src/main/java/org/jooq/Declaration.java +++ b/jOOQ/src/main/java/org/jooq/Declaration.java @@ -106,6 +106,7 @@ package org.jooq; + \ No newline at end of file diff --git a/jOOQ/src/main/java/org/jooq/ForByStep.java b/jOOQ/src/main/java/org/jooq/ForByStep.java index 2de0d8bc5e..00b8e1d56f 100644 --- a/jOOQ/src/main/java/org/jooq/ForByStep.java +++ b/jOOQ/src/main/java/org/jooq/ForByStep.java @@ -64,6 +64,8 @@ package org.jooq; + + diff --git a/jOOQ/src/main/java/org/jooq/ForInStep.java b/jOOQ/src/main/java/org/jooq/ForInStep.java index b41f337d98..b5ccf31078 100644 --- a/jOOQ/src/main/java/org/jooq/ForInStep.java +++ b/jOOQ/src/main/java/org/jooq/ForInStep.java @@ -89,6 +89,7 @@ package org.jooq; + \ No newline at end of file diff --git a/jOOQ/src/main/java/org/jooq/IfElseStep.java b/jOOQ/src/main/java/org/jooq/IfElseStep.java index b3e6a02663..033de42c64 100644 --- a/jOOQ/src/main/java/org/jooq/IfElseStep.java +++ b/jOOQ/src/main/java/org/jooq/IfElseStep.java @@ -73,6 +73,7 @@ package org.jooq; + \ No newline at end of file diff --git a/jOOQ/src/main/java/org/jooq/IfThenStep.java b/jOOQ/src/main/java/org/jooq/IfThenStep.java index 00b8e1d56f..748703fd91 100644 --- a/jOOQ/src/main/java/org/jooq/IfThenStep.java +++ b/jOOQ/src/main/java/org/jooq/IfThenStep.java @@ -67,6 +67,7 @@ package org.jooq; + \ No newline at end of file diff --git a/jOOQ/src/main/java/org/jooq/LoopStep.java b/jOOQ/src/main/java/org/jooq/LoopStep.java index 00b8e1d56f..748703fd91 100644 --- a/jOOQ/src/main/java/org/jooq/LoopStep.java +++ b/jOOQ/src/main/java/org/jooq/LoopStep.java @@ -67,6 +67,7 @@ package org.jooq; + \ No newline at end of file diff --git a/jOOQ/src/main/java/org/jooq/RepeatUntilStep.java b/jOOQ/src/main/java/org/jooq/RepeatUntilStep.java index 3ca5dc9deb..45b3b50fe5 100644 --- a/jOOQ/src/main/java/org/jooq/RepeatUntilStep.java +++ b/jOOQ/src/main/java/org/jooq/RepeatUntilStep.java @@ -59,6 +59,7 @@ package org.jooq; + \ No newline at end of file diff --git a/jOOQ/src/main/java/org/jooq/Variable.java b/jOOQ/src/main/java/org/jooq/Variable.java index b3d8367d8f..788e2689e2 100644 --- a/jOOQ/src/main/java/org/jooq/Variable.java +++ b/jOOQ/src/main/java/org/jooq/Variable.java @@ -93,6 +93,7 @@ package org.jooq; + \ No newline at end of file diff --git a/jOOQ/src/main/java/org/jooq/impl/Assignment.java b/jOOQ/src/main/java/org/jooq/impl/Assignment.java index 72e1c2d8fc..ed9c1e68c4 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Assignment.java +++ b/jOOQ/src/main/java/org/jooq/impl/Assignment.java @@ -72,6 +72,57 @@ package org.jooq.impl; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jOOQ/src/main/java/org/jooq/impl/BlockImpl.java b/jOOQ/src/main/java/org/jooq/impl/BlockImpl.java index a201199b77..af97ac210c 100644 --- a/jOOQ/src/main/java/org/jooq/impl/BlockImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/BlockImpl.java @@ -41,15 +41,20 @@ package org.jooq.impl; // ... // ... import static org.jooq.SQLDialect.FIREBIRD; +import static org.jooq.SQLDialect.H2; import static org.jooq.SQLDialect.MARIADB; // ... import static org.jooq.SQLDialect.POSTGRES; import static org.jooq.conf.ParamType.INLINED; +import static org.jooq.impl.Keywords.K_ALIAS; import static org.jooq.impl.Keywords.K_AS; import static org.jooq.impl.Keywords.K_ATOMIC; import static org.jooq.impl.Keywords.K_BEGIN; +import static org.jooq.impl.Keywords.K_CALL; +import static org.jooq.impl.Keywords.K_CREATE; import static org.jooq.impl.Keywords.K_DECLARE; import static org.jooq.impl.Keywords.K_DO; +import static org.jooq.impl.Keywords.K_DROP; import static org.jooq.impl.Keywords.K_END; import static org.jooq.impl.Keywords.K_EXECUTE_BLOCK; import static org.jooq.impl.Keywords.K_EXECUTE_IMMEDIATE; @@ -73,8 +78,10 @@ import org.jooq.DDLQuery; // ... import org.jooq.Field; // ... +import org.jooq.Query; import org.jooq.SQLDialect; import org.jooq.Statement; +// ... /** * @author Lukas Eder @@ -158,6 +165,36 @@ final class BlockImpl extends AbstractQuery implements Block { break; } + case H2: { + String name = "block_" + System.currentTimeMillis() + "_" + (long) (10000000L * Math.random()); + + // TODO: create a non-ambiguous name + if (increment(ctx.data(), DATA_BLOCK_NESTING)) { + ctx.paramType(INLINED) + .visit(K_CREATE).sql(' ') + .visit(K_ALIAS).sql(' ').sql(name).sql(' ') + .visit(K_AS).sql(" $$") + .formatIndentStart() + .formatSeparator() + .sql("void x(Connection c) throws SQLException "); + + ctx.data(DATA_FORCE_STATIC_STATEMENT, true); + } + + accept0(ctx); + + if (decrement(ctx.data(), DATA_BLOCK_NESTING)) + ctx.formatIndentEnd() + .formatSeparator() + .sql("$$;") + .formatSeparator() + .visit(K_CALL).sql(' ').sql(name).sql("();") + .formatSeparator() + .visit(K_DROP).sql(' ').visit(K_ALIAS).sql(' ').sql(name).sql(';'); + + break; + } + @@ -261,6 +298,9 @@ final class BlockImpl extends AbstractQuery implements Block { + + + ctx.sql(';'); } @@ -276,7 +316,10 @@ final class BlockImpl extends AbstractQuery implements Block { private static final void acceptNonDeclarations(Context ctx, List statements, boolean wrapInBeginEnd) { if (wrapInBeginEnd) { - ctx.visit(K_BEGIN); + if (ctx.family() == H2) + ctx.sql('{'); + else + ctx.visit(K_BEGIN); if (ctx.family() == MARIADB) ctx.sql(' ').visit(K_NOT).sql(' ').visit(K_ATOMIC); @@ -297,6 +340,7 @@ final class BlockImpl extends AbstractQuery implements Block { + case H2: case FIREBIRD: case MARIADB: default: @@ -330,7 +374,37 @@ final class BlockImpl extends AbstractQuery implements Block { - ctx.visit(s); + if (ctx.family() == H2 && s instanceof Query && !(s instanceof Block)) { + ArrayList> list = new ArrayList>(); + + ctx.data(STATEMENT_VARIABLES, list); + ctx.sql("try (PreparedStatement s = c.prepareStatement(") + .formatIndentStart() + .formatNewLine() + .sql('"') + .sql(ctx.render(s).replace("\"", "\\\"").replace("\n", "\\n\" +\n\"")) + .sql('"') + .formatIndentEnd() + .formatNewLine() + .sql(")) {") + .formatIndentStart() + .formatSeparator(); + + for (int j = 0; j < list.size(); j++) + ctx.sql("s.setObject(" + (j + 1) + ", ") + .sql(list.get(j).getName()) + .sql(");") + .formatSeparator(); + + ctx.sql("s.execute();") + .formatIndentEnd() + .formatSeparator() + .sql('}'); + + ctx.data().remove(STATEMENT_VARIABLES); + } + else + ctx.visit(s); @@ -347,12 +421,17 @@ final class BlockImpl extends AbstractQuery implements Block { private static final void end(Context ctx) { ctx.formatIndentEnd() - .formatSeparator() - .visit(K_END); + .formatSeparator(); - switch (ctx.family()) { - case FIREBIRD: - break; + if (ctx.family() == H2) + ctx.sql('}'); + else + ctx.visit(K_END); + + switch (ctx.family()) { + case H2: + case FIREBIRD: + break; @@ -365,8 +444,22 @@ final class BlockImpl extends AbstractQuery implements Block { - default: - ctx.sql(';'); - } + default: + ctx.sql(';'); + } } + + static final String STATEMENT_VARIABLES = "org.jooq.impl.BlockImpl.statement-variables"; + + + + + + + + + + + + } diff --git a/jOOQ/src/main/java/org/jooq/impl/Continue.java b/jOOQ/src/main/java/org/jooq/impl/Continue.java index c59c84238e..f72cc0f1ee 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Continue.java +++ b/jOOQ/src/main/java/org/jooq/impl/Continue.java @@ -107,6 +107,16 @@ package org.jooq.impl; + + + + + + + + + + diff --git a/jOOQ/src/main/java/org/jooq/impl/DSL.java b/jOOQ/src/main/java/org/jooq/impl/DSL.java index b1312184da..2ddb7619c7 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DSL.java +++ b/jOOQ/src/main/java/org/jooq/impl/DSL.java @@ -9750,7 +9750,7 @@ public class DSL { * * @see DSLContext#begin(Statement...) */ - @Support({ FIREBIRD, MARIADB, POSTGRES }) + @Support({ FIREBIRD, H2, MARIADB, POSTGRES }) public static Block begin(Statement... statements) { return begin(Arrays.asList(statements)); } @@ -9760,7 +9760,7 @@ public class DSL { * * @see DSLContext#begin(Collection) */ - @Support({ FIREBIRD, MARIADB, POSTGRES }) + @Support({ FIREBIRD, H2, MARIADB, POSTGRES }) public static Block begin(Collection statements) { return DSL.using(new DefaultConfiguration()).begin(statements); } diff --git a/jOOQ/src/main/java/org/jooq/impl/DeclarationImpl.java b/jOOQ/src/main/java/org/jooq/impl/DeclarationImpl.java index b3fd3afaea..20c30ad3f6 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DeclarationImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/DeclarationImpl.java @@ -101,6 +101,24 @@ package org.jooq.impl; + + + + + + + + + + + + + + + + + + diff --git a/jOOQ/src/main/java/org/jooq/impl/Exit.java b/jOOQ/src/main/java/org/jooq/impl/Exit.java index 70d1b706a6..5ad08c0e27 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Exit.java +++ b/jOOQ/src/main/java/org/jooq/impl/Exit.java @@ -108,6 +108,16 @@ package org.jooq.impl; + + + + + + + + + + diff --git a/jOOQ/src/main/java/org/jooq/impl/IfImpl.java b/jOOQ/src/main/java/org/jooq/impl/IfImpl.java index ba585edcc8..694c3b6680 100644 --- a/jOOQ/src/main/java/org/jooq/impl/IfImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/IfImpl.java @@ -170,6 +170,22 @@ package org.jooq.impl; + + + + + + + + + + + + + + + + diff --git a/jOOQ/src/main/java/org/jooq/impl/Keywords.java b/jOOQ/src/main/java/org/jooq/impl/Keywords.java index 3a0a371b2c..f8e1d3e875 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Keywords.java +++ b/jOOQ/src/main/java/org/jooq/impl/Keywords.java @@ -49,6 +49,7 @@ import org.jooq.Keyword; final class Keywords { static final Keyword K_ADD = keyword("add"); + static final Keyword K_ALIAS = keyword("alias"); static final Keyword K_ALTER = keyword("alter"); static final Keyword K_ALTER_COLUMN = keyword("alter column"); static final Keyword K_ALTER_CONSTRAINT = keyword("alter constraint"); @@ -72,6 +73,7 @@ final class Keywords { static final Keyword K_BULK_COLLECT_INTO = keyword("bulk collect into"); static final Keyword K_BY = keyword("by"); static final Keyword K_CACHE = keyword("cache"); + static final Keyword K_CALL = keyword("call"); static final Keyword K_CASCADE = keyword("cascade"); static final Keyword K_CASE = keyword("case"); static final Keyword K_CAST = keyword("cast"); diff --git a/jOOQ/src/main/java/org/jooq/impl/LabelImpl.java b/jOOQ/src/main/java/org/jooq/impl/LabelImpl.java index a4c21d65cb..9c201df35d 100644 --- a/jOOQ/src/main/java/org/jooq/impl/LabelImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/LabelImpl.java @@ -81,6 +81,7 @@ package org.jooq.impl; + \ No newline at end of file diff --git a/jOOQ/src/main/java/org/jooq/impl/LabelledStatement.java b/jOOQ/src/main/java/org/jooq/impl/LabelledStatement.java index 9c201df35d..06e647668c 100644 --- a/jOOQ/src/main/java/org/jooq/impl/LabelledStatement.java +++ b/jOOQ/src/main/java/org/jooq/impl/LabelledStatement.java @@ -82,6 +82,7 @@ package org.jooq.impl; + \ No newline at end of file diff --git a/jOOQ/src/main/java/org/jooq/impl/LoopImpl.java b/jOOQ/src/main/java/org/jooq/impl/LoopImpl.java index 2afecffd00..4b5c9ef684 100644 --- a/jOOQ/src/main/java/org/jooq/impl/LoopImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/LoopImpl.java @@ -199,6 +199,78 @@ package org.jooq.impl; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jOOQ/src/main/java/org/jooq/impl/VariableImpl.java b/jOOQ/src/main/java/org/jooq/impl/VariableImpl.java index 4995d32fd7..15613a8e5d 100644 --- a/jOOQ/src/main/java/org/jooq/impl/VariableImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/VariableImpl.java @@ -74,6 +74,24 @@ package org.jooq.impl; + + + + + + + + + + + + + + + + + +