From ae79dd92ec5a1fe706223307fa5a5edf7df902ff Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Fri, 7 Jan 2022 14:26:21 +0100 Subject: [PATCH] DB2: Experimental: Add QueryPlanLogger for DB2 --- .../server/core/InternalConfiguration.java | 2 + .../server/query/QueryPlanLoggerDb2.java | 55 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 ebean-core/src/main/java/io/ebeaninternal/server/query/QueryPlanLoggerDb2.java diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java index dc24cfdc4..d1146ac15 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java @@ -597,6 +597,8 @@ public final class InternalConfiguration { return new QueryPlanLoggerSqlServer(); case ORACLE: return new QueryPlanLoggerOracle(); + case DB2: + return new QueryPlanLoggerDb2(); default: return new QueryPlanLoggerExplain(); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/QueryPlanLoggerDb2.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/QueryPlanLoggerDb2.java new file mode 100644 index 000000000..4b892f987 --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/QueryPlanLoggerDb2.java @@ -0,0 +1,55 @@ + +package io.ebeaninternal.server.query; + +import io.ebeaninternal.api.CoreLog; +import io.ebeaninternal.api.SpiDbQueryPlan; +import io.ebeaninternal.api.SpiQueryPlan; +import io.ebeaninternal.server.type.bindcapture.BindCapture; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Random; + +/** + * A QueryPlanLogger for DB2. + * + * To use query plan capturing, you have to install the explain tables with + * SYSPROC.SYSINSTALLOBJECTS( 'EXPLAIN', 'C' , '', CURRENT SCHEMA ). + * To do this in a repeatable script, you may use this statement: + * + *
+ * BEGIN    
+ * IF NOT EXISTS (SELECT * FROM SYSCAT.TABLES WHERE TABSCHEMA = CURRENT SCHEMA AND TABNAME = 'EXPLAIN_STREAM') THEN 
+ *    call SYSPROC.SYSINSTALLOBJECTS( 'EXPLAIN', 'C' , '', CURRENT SCHEMA );
+ * END IF;                                                        
+ * END
+ * 
+ * + * @author Roland Praml, FOCONIS AG + */ +public final class QueryPlanLoggerDb2 extends QueryPlanLogger { + + private Random rnd = new Random(); + @Override + public SpiDbQueryPlan collectPlan(Connection conn, SpiQueryPlan plan, BindCapture bind) { + try (Statement stmt = conn.createStatement()) { + int queryNo = rnd.nextInt(Integer.MAX_VALUE); + try (PreparedStatement explainStmt = conn + .prepareStatement("EXPLAIN PLAN SET QUERYNO=" + queryNo + " FOR " + plan.getSql())) { + bind.prepare(explainStmt, conn); + explainStmt.execute(); + } + + try (ResultSet rset = stmt.executeQuery("select * from EXPLAIN_STATEMENT where QUERYNO=" + queryNo)) { + return readQueryPlan(plan, bind, rset); + } + } catch (SQLException e) { + CoreLog.log.warn("Could not log query plan", e); + return null; + } + } + +}