static String genrateStatementRow(Procedure procedure, Statement statement) { StringBuilder sb = new StringBuilder(); sb.append(" <tr class='primaryrow2'>"); // name column String anchor = (procedure.getTypeName() + "-" + statement.getTypeName()).toLowerCase(); sb.append( "<td style='white-space: nowrap'><i id='p-" + anchor + "--icon' class='icon-chevron-right'></i> <a href='#' id='p-"); sb.append(anchor).append("' class='togglex'>"); sb.append(statement.getTypeName()); sb.append("</a></td>"); // sql column sb.append("<td><tt>"); sb.append(statement.getSqltext()); sb.append("</td></tt>"); // params column sb.append("<td>"); List<StmtParameter> params = CatalogUtil.getSortedCatalogItems(statement.getParameters(), "index"); List<String> paramTypes = new ArrayList<String>(); for (StmtParameter param : params) { paramTypes.add(VoltType.get((byte) param.getJavatype()).name()); } if (paramTypes.size() == 0) { sb.append("<i>None</i>"); } sb.append(StringUtils.join(paramTypes, ", ")); sb.append("</td>"); // r/w column sb.append("<td>"); if (statement.getReadonly()) { tag(sb, "success", "Read"); } else { tag(sb, "warning", "Write"); } sb.append("</td>"); // attributes sb.append("<td>"); if (!statement.getIscontentdeterministic() || !statement.getIsorderdeterministic()) { tag(sb, "inverse", "Determinism"); } if (statement.getSeqscancount() > 0) { tag(sb, "important", "Scans"); } sb.append("</td>"); sb.append("</tr>\n"); // BUILD THE DROPDOWN FOR THE PLAN/DETAIL TABLE sb.append( "<tr class='dropdown2'><td colspan='5' id='p-" + procedure.getTypeName().toLowerCase() + "-" + statement.getTypeName().toLowerCase() + "--dropdown'>\n"); sb.append("<div class='well well-small'><h4>Explain Plan:</h4>\n"); StatementAnnotation annotation = (StatementAnnotation) statement.getAnnotation(); if (annotation != null) { String plan = annotation.explainPlan; plan = plan.replace("\n", "<br/>"); plan = plan.replace(" ", " "); for (Table t : annotation.tablesRead) { String name = t.getTypeName().toUpperCase(); String link = "\"<a href='#s-" + t.getTypeName() + "'>" + name + "</a>\""; plan = plan.replace("\"" + name + "\"", link); } for (Table t : annotation.tablesUpdated) { String name = t.getTypeName().toUpperCase(); String link = "\"<a href='#s-" + t.getTypeName() + "'>" + name + "</a>\""; plan = plan.replace("\"" + name + "\"", link); } for (Index i : annotation.indexesUsed) { Table t = (Table) i.getParent(); String name = i.getTypeName().toUpperCase(); String link = "\"<a href='#s-" + t.getTypeName() + "-" + i.getTypeName() + "'>" + name + "</a>\""; plan = plan.replace("\"" + name + "\"", link); } sb.append("<tt>").append(plan).append("</tt>"); } else { sb.append("<i>No SQL explain plan found.</i>\n"); } sb.append("</div>\n"); sb.append("</td></tr>\n"); return sb.toString(); }
/** * Compile and cache the statement and plan and return the final plan graph. * * @param sql * @param paramCount */ public List<AbstractPlanNode> compile( String sql, int paramCount, String joinOrder, Object partitionParameter, boolean inferSP, boolean lockInSP) { Statement catalogStmt = proc.getStatements().add("stmt-" + String.valueOf(compileCounter++)); catalogStmt.setSqltext(sql); catalogStmt.setSinglepartition(partitionParameter != null); catalogStmt.setBatched(false); catalogStmt.setParamnum(paramCount); // determine the type of the query QueryType qtype = QueryType.SELECT; catalogStmt.setReadonly(true); if (sql.toLowerCase().startsWith("insert")) { qtype = QueryType.INSERT; catalogStmt.setReadonly(false); } if (sql.toLowerCase().startsWith("update")) { qtype = QueryType.UPDATE; catalogStmt.setReadonly(false); } if (sql.toLowerCase().startsWith("delete")) { qtype = QueryType.DELETE; catalogStmt.setReadonly(false); } catalogStmt.setQuerytype(qtype.getValue()); // name will look like "basename-stmt-#" String name = catalogStmt.getParent().getTypeName() + "-" + catalogStmt.getTypeName(); DatabaseEstimates estimates = new DatabaseEstimates(); TrivialCostModel costModel = new TrivialCostModel(); PartitioningForStatement partitioning = new PartitioningForStatement(partitionParameter, inferSP, lockInSP); QueryPlanner planner = new QueryPlanner( catalogStmt.getSqltext(), catalogStmt.getTypeName(), catalogStmt.getParent().getTypeName(), catalog.getClusters().get("cluster"), db, partitioning, hsql, estimates, false, StatementCompiler.DEFAULT_MAX_JOIN_TABLES, costModel, null, joinOrder); CompiledPlan plan = null; planner.parse(); plan = planner.plan(); assert (plan != null); // Input Parameters // We will need to update the system catalogs with this new information // If this is an adhoc query then there won't be any parameters for (int i = 0; i < plan.parameters.length; ++i) { StmtParameter catalogParam = catalogStmt.getParameters().add(String.valueOf(i)); catalogParam.setJavatype(plan.parameters[i].getValue()); catalogParam.setIndex(i); } // Output Columns int index = 0; for (SchemaColumn col : plan.columns.getColumns()) { Column catColumn = catalogStmt.getOutput_columns().add(String.valueOf(index)); catColumn.setNullable(false); catColumn.setIndex(index); catColumn.setName(col.getColumnName()); catColumn.setType(col.getType().getValue()); catColumn.setSize(col.getSize()); index++; } List<PlanNodeList> nodeLists = new ArrayList<PlanNodeList>(); nodeLists.add(new PlanNodeList(plan.rootPlanGraph)); if (plan.subPlanGraph != null) { nodeLists.add(new PlanNodeList(plan.subPlanGraph)); } // Store the list of parameters types and indexes in the plan node list. List<Pair<Integer, VoltType>> parameters = nodeLists.get(0).getParameters(); for (int i = 0; i < plan.parameters.length; ++i) { Pair<Integer, VoltType> parameter = new Pair<Integer, VoltType>(i, plan.parameters[i]); parameters.add(parameter); } // Now update our catalog information // HACK: We're using the node_tree's hashCode() as it's name. It would be really // nice if the Catalog code give us an guid without needing a name first... String json = null; try { JSONObject jobj = new JSONObject(nodeLists.get(0).toJSONString()); json = jobj.toString(4); } catch (JSONException e2) { // TODO Auto-generated catch block e2.printStackTrace(); System.exit(-1); } // // We then stick a serialized version of PlanNodeTree into a PlanFragment // try { BuildDirectoryUtils.writeFile("statement-plans", name + "_json.txt", json); BuildDirectoryUtils.writeFile( "statement-plans", name + ".dot", nodeLists.get(0).toDOTString("name")); } catch (Exception e) { e.printStackTrace(); } List<AbstractPlanNode> plannodes = new ArrayList<AbstractPlanNode>(); for (PlanNodeList nodeList : nodeLists) { plannodes.add(nodeList.getRootPlanNode()); } m_currentPlan = plan; return plannodes; }