/**
* Copyright (c) 2009--2014 Red Hat, Inc.
*
* This software is licensed to you under the GNU General Public License,
* version 2 (GPLv2). There is NO WARRANTY for this software, express or
* implied, including the implied warranties of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
* along with this software; if not, see
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* Red Hat trademarks are not licensed under GPLv2. No permission is
* granted to use or replicate Red Hat trademarks that are incorporated
* in this software or its documentation.
*/
package com.redhat.rhn.scripts;
import com.redhat.rhn.common.db.datasource.Mode;
import com.redhat.rhn.common.db.datasource.ModeFactory;
import com.redhat.rhn.common.db.datasource.SelectMode;
import com.redhat.rhn.common.hibernate.HibernateFactory;
import com.redhat.rhn.common.hibernate.HibernateRuntimeException;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeSet;
/**
* Program to generate Exceptions.
* Make sure that you have set rhn.checkout.dir in your
* ~/.rhn.properties file. Without that property, these tests will
* _NOT_ run. When the DataSource xml files get moved into the rhn-java
* repo, that requirement will be removed.
*
* @version $Rev$
*/
public class ExplainPlanGenerator {
private String outfile;
private static final String QUERY_NAME = "ryan_query";
/**
* Create a new explain plan generator
* @param source The path to the cvs rhn checkout.
* @param output The file to write the plans to.
*/
public ExplainPlanGenerator(String source, String output) {
outfile = output;
}
private static final String EXPLAIN_QUERY = "select " +
"to_char(parent_id) explain_parent_id, " +
"to_char(id) explain_id, " +
"lpad(' ',2*(LEVEL-1)) || operation || " +
"' ' || options || ' ' || object_name " +
"explain_operation " +
"from " +
" plan_table " +
"start with id = 1 and statement_id = ? " +
"connect by prior id = parent_id " +
" and statement_id = ?";
private boolean shouldSkip(Mode m) {
/* Don't do plans for queries that use system tables or for
* dummy queries.
*/
return (m != null && m.getQuery() != null &&
(m.getName().equals("tablespace_overview") ||
m.getQuery().getOrigQuery().trim().startsWith("--")));
}
/** Execute the task
* @throws IOException If the output file can't be opened.
* @throws SQLException if something goes wrong with the DB.
*/
public void execute() throws IOException, SQLException {
Session session = null;
Connection conn = null;
try {
session = HibernateFactory.getSession();
conn = session.connection();
PrintStream out = new PrintStream(new FileOutputStream(outfile));
Collection fileKeys = ModeFactory.getKeys();
TreeSet ts = new TreeSet(fileKeys);
Iterator i = ts.iterator();
while (i.hasNext()) {
String file = (String)i.next();
Map queries = ModeFactory.getFileKeys(file);
if (file.equals("test_queries")) {
continue;
}
out.println("\nFile: " + file);
Iterator q = new TreeSet(queries.keySet()).iterator();
int count = 0;
while (q.hasNext()) {
Mode m = (Mode)queries.get(q.next());
/* Don't do plans for queries that use system tables or for
* dummy queries.
*/
if (shouldSkip(m)) {
out.println("\nSkipping dummy query: " + m.getName());
continue;
}
if (!(m instanceof SelectMode)) {
out.println("\nSkipping Write or Callable mode: " + m.getName());
continue;
}
out.println("\nPlan for " + m.getName());
String query = "EXPLAIN PLAN " +
"SET STATEMENT_ID='" + QUERY_NAME + "' FOR " +
m.getQuery().getOrigQuery();
// HACK! Some of the queries actually have %s in them.
// So, replace all %s with :rbb so that the explain plan
// can be generated.
query = query.replaceAll("%s", ":rbb");
PreparedStatement ps = conn.prepareStatement(query);
ps.execute();
ps.close();
// Now that we have generated the explain plan, we just
// need to get it from the DB.
ps = conn.prepareStatement(EXPLAIN_QUERY);
ps.setString(1, QUERY_NAME);
ps.setString(2, QUERY_NAME);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
String parentId = rs.getString("explain_parent_id");
String id = rs.getString("explain_id");
String operation = rs.getString("explain_operation");
out.println(parentId + " " + id + " " + operation);
}
count++;
rs.close();
ps.close();
Statement st = conn.createStatement();
st.execute("Delete FROM plan_table where " +
"STATEMENT_ID='" + QUERY_NAME + "'");
st.close();
}
}
out.close();
}
catch (HibernateException he) {
throw new
HibernateRuntimeException(
"HibernateException in ExplainPlanGenerator.", he);
}
}
/**
* Run the program
* @param args The arguments to the java program.
*/
public static void main(String[] args) {
if (args.length != 2) {
System.err.println("Not enough arguments, usage:");
System.err.println("ExplainPlanGenerator /path/to/rhn " +
"/path/to/output_file");
System.exit(1);
}
ExplainPlanGenerator ep = new ExplainPlanGenerator(args[0], args[1]);
try {
ep.execute();
System.out.println("Done generating explain plans in " + args[1]);
}
catch (SQLException e) {
System.err.println("Something went wrong in the DB: " +
e.getMessage());
}
catch (IOException e) {
System.err.println("Couldn't write to disk: " + e.getMessage());
}
}
}