/*
* DBeaver - Universal Database Manager
* Copyright (C) 2013-2015 Denis Forveille (titou10.titou10@gmail.com)
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jkiss.dbeaver.ext.db2.model.plan;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.exec.DBCException;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCPreparedStatement;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCResultSet;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCSession;
import org.jkiss.dbeaver.model.exec.plan.DBCPlan;
import org.jkiss.dbeaver.model.exec.plan.DBCPlanNode;
import java.sql.SQLException;
import java.util.Collection;
import java.util.concurrent.atomic.AtomicInteger;
/**
* DB2 execution plan analyser
*
* @author Denis Forveille
*/
public class DB2PlanAnalyser implements DBCPlan {
private static final Log LOG = Log.getLog(DB2PlanAnalyser.class);
// See init below
private static String PT_DELETE;
private static final String PT_EXPLAIN = "EXPLAIN PLAN SET QUERYNO = %d FOR %s";
private static final String SEL_STMT = "SELECT * FROM %s.EXPLAIN_STATEMENT WHERE QUERYNO = ? AND EXPLAIN_LEVEL = 'P' WITH UR";
private static AtomicInteger STMT_NO_GEN = new AtomicInteger(Long.valueOf(System.currentTimeMillis() / 10000000L).intValue());
private String query;
private String planTableSchema;
private Collection<DB2PlanNode> listNodes;
private DB2PlanStatement db2PlanStatement;
// ------------
// Constructors
// ------------
public DB2PlanAnalyser(String query, String planTableSchema)
{
this.query = query;
this.planTableSchema = planTableSchema;
}
// ----------------
// Standard Getters
// ----------------
@Override
public String getQueryString()
{
return query;
}
@Override
public String getPlanQueryString() {
return String.format(PT_EXPLAIN, STMT_NO_GEN.get(), query);
}
@Override
public Collection<? extends DBCPlanNode> getPlanNodes()
{
return listNodes;
}
// ----------------
// Business Methods
// ----------------
public void explain(JDBCSession session) throws DBCException
{
Integer stmtNo = STMT_NO_GEN.incrementAndGet();
String explainStmt = String.format(PT_EXPLAIN, stmtNo, query);
LOG.debug("Schema=" + planTableSchema + " : " + explainStmt);
try {
// Start by cleaning old rows for safety
cleanExplainTables(session, stmtNo, planTableSchema);
// Explain
try (JDBCPreparedStatement dbStat = session.prepareStatement(explainStmt)) {
dbStat.execute();
}
// Build Node Structure
try (JDBCPreparedStatement dbStat = session.prepareStatement(String.format(SEL_STMT, planTableSchema))) {
dbStat.setInt(1, stmtNo);
try (JDBCResultSet dbResult = dbStat.executeQuery()) {
dbResult.next();
db2PlanStatement = new DB2PlanStatement(session, dbResult, planTableSchema);
}
}
listNodes = db2PlanStatement.buildNodes();
// Clean afterward
cleanExplainTables(session, stmtNo, planTableSchema);
} catch (SQLException e) {
throw new DBCException(e, session.getDataSource());
}
}
// ----------------
// Helpers
// ----------------
private void cleanExplainTables(JDBCSession session, Integer stmtNo, String planTableSchema) throws SQLException
{
// Delete previous statement rows
try (JDBCPreparedStatement dbStat = session.prepareStatement(String.format(PT_DELETE, planTableSchema, planTableSchema))) {
dbStat.setInt(1, stmtNo);
dbStat.execute();
}
}
static {
StringBuilder sb = new StringBuilder(256);
sb.append("DELETE");
sb.append(" FROM %s.EXPLAIN_INSTANCE I");
sb.append(" WHERE EXISTS (SELECT 1");
sb.append(" FROM %s.EXPLAIN_STATEMENT S");
sb.append(" WHERE S.EXPLAIN_TIME = I.EXPLAIN_TIME");
sb.append(" AND S.SOURCE_NAME = I.SOURCE_NAME");
sb.append(" AND S.SOURCE_SCHEMA = I.SOURCE_SCHEMA");
sb.append(" AND S.SOURCE_VERSION = I.SOURCE_VERSION");
sb.append(" AND QUERYNO = ?)");
PT_DELETE = sb.toString();
}
}