CompiledPlan plan = null;
CompiledPlan last_plan = null;
PlanNodeList node_list = null;
QueryPlanner planner = new QueryPlanner(catalog.getClusters().get("cluster"), db, hsql, estimates, true, false);
Throwable first_exception = null;
for (boolean _singleSited : new boolean[]{ true, false }) {
if (_singleSited == false && isMapReduce) continue;
QueryType stmt_type = QueryType.get(catalogStmt.getQuerytype());
String msg = "Creating " + stmt_type.name() + " query plan for " + catalogStmt.fullName() + ": singleSited=" + _singleSited;
if (trace.val) LOG.trace(msg);
compiler.addInfo(msg);
catalogStmt.setSinglepartition(_singleSited);
String name = catalogStmt.getParent().getName() + "-" + catalogStmt.getName();
TrivialCostModel costModel = new TrivialCostModel();
try {
plan = planner.compilePlan(costModel, catalogStmt.getSqltext(),
catalogStmt.getName(), catalogStmt.getParent().getName(),
catalogStmt.getSinglepartition(), null);
} catch (Throwable e) {
LOG.error("Failed to plan for stmt: " + catalogStmt.fullName(), e);
if (first_exception == null) {
if (debug.val) LOG.warn("Ignoring first error for " + catalogStmt.getName() + " :: " + e.getMessage());
first_exception = e;
continue;
}
e.printStackTrace();
throw compiler.new VoltCompilerException("Failed to plan for stmt: " + catalogStmt.fullName());
}
if (plan == null) {
msg = "Failed to plan for stmt: " + catalogStmt.fullName();
String plannerMsg = planner.getErrorMessage();
if (plannerMsg == null) plannerMsg = "PlannerMessage was empty!";
// HACK: Ignore if they were trying to do a single-sited INSERT/UPDATE/DELETE
// on a replicated table
if (plannerMsg.contains("replicated table") && _singleSited) {
if (debug.val)
LOG.warn(String.format("Ignoring error for %s: %s", catalogStmt.fullName(), plannerMsg));
continue;
// HACK: If we get an unknown error message on an multi-sited INSERT/UPDATE/DELETE, assume
// that it's because we are trying to insert on a non-replicated table
} else if (!_singleSited && stmt_type == QueryType.INSERT && plannerMsg.contains("Error unknown")) {
if (debug.val)
LOG.warn(String.format("Ignoring multi-sited %s %s on non-replicated table: %s",
stmt_type.name(), catalogStmt.fullName(), plannerMsg));
continue;
} else if (planner.getError() != null) {
if (debug.val) LOG.error(msg);
throw compiler.new VoltCompilerException(msg, planner.getError());
// Otherwise, report the error
} else {
if (plannerMsg != null)
msg += " with error: \"" + plannerMsg + "\"";
if (debug.val) LOG.error(msg);
throw compiler.new VoltCompilerException(msg);
}
}
if (trace.val)
LOG.trace(String.format("%s Analyzing %s query plan",
catalogStmt.fullName(), (_singleSited == false ? "DTXN" : "SP")));
// serialize full where clause to the catalog
// for the benefit of the designer
if (plan.fullWhereClause != null) {
String json = "ERROR";
try {
// serialize to pretty printed json
String jsonCompact = plan.fullWhereClause.toJSONString();
// pretty printing seems to cause issues
//JSONObject jobj = new JSONObject(jsonCompact);
//json = jobj.toString(4);
json = jsonCompact;
} catch (Exception e) {
// hopefully someone will notice
e.printStackTrace();
}
String hexString = Encoder.hexEncode(json);
catalogStmt.setExptree(hexString);
}
// serialize full plan to the catalog
// for the benefit of the designer
if (plan.fullWinnerPlan != null) {
String json = plan.fullplan_json;
String hexString = Encoder.hexEncode(json);
if (_singleSited) {
catalogStmt.setFullplan(hexString);
} else {
catalogStmt.setMs_fullplan(hexString);
}
}
//Store the list of parameters types and indexes in the plan node list.
/*List<Pair<Integer, VoltType>> parameters = node_list.getParameters();
for (ParameterInfo param : plan.parameters) {
Pair<Integer, VoltType> parameter = new Pair<Integer, VoltType>(param.index, param.type);
parameters.add(parameter);
}*/
int i = 0;
Collections.sort(plan.fragments);
if (trace.val)
LOG.trace(catalogStmt.fullName() + " Plan Fragments: " + plan.fragments);
for (CompiledPlan.Fragment fragment : plan.fragments) {
node_list = new PlanNodeList(fragment.planGraph);
boolean readonly = fragmentReadOnly(fragment.planGraph);
boolean fastAggregate = false; // FIXME
boolean fastCombine = false; // FIXME
// Now update our catalog information
int id = getNextFragmentId(db, readonly, fastAggregate, fastCombine);
String planFragmentName = Integer.toString(id);
PlanFragment planFragment = null;
if (_singleSited) {
planFragment = catalogStmt.getFragments().add(planFragmentName);
catalogStmt.setHas_singlesited(true);
if (trace.val)
LOG.trace(String.format("%s SP PLAN FRAGMENT: %s", catalogStmt.fullName(), planFragment));
} else {
planFragment = catalogStmt.getMs_fragments().add(planFragmentName);
catalogStmt.setHas_multisited(true);
if (trace.val)
LOG.trace(String.format("%s DTXN PLAN FRAGMENT: %s", catalogStmt.fullName(), planFragment));
}
// mark a fragment as non-transactional if it never touches a persistent table
planFragment.setNontransactional(!fragmentReferencesPersistentTable(fragment.planGraph));
planFragment.setReadonly(readonly);
planFragment.setHasdependencies(fragment.hasDependencies);
planFragment.setMultipartition(fragment.multiPartition);
planFragment.setId(id);
String json = null;
try {
JSONObject jobj = new JSONObject(node_list.toJSONString());
json = jobj.toString(4);
} catch (JSONException e2) {
throw new RuntimeException(e2);
}
// TODO: can't re-enable this until the EE accepts PlanColumn GUIDs
// instead of column names because the deserialization is done without
// any connection to the child nodes - required to map the PlanColumn's
// GUID to the child's column name.
// verify the plan serializes and deserializes correctly.
// assert(node_list.testJSONSerialization(db));
// output the plan to disk for debugging
PrintStream plansOut = BuildDirectoryUtils.getDebugOutputPrintStream(
"statement-winner-plans", name + "-" + String.valueOf(i++) + ".txt");
plansOut.println(json);
plansOut.close();
//
// We then stick a serialized version of PlanNodeTree into a PlanFragment
//
try {
FastSerializer fs = new FastSerializer(false, false); // C++ needs little-endian
fs.write(json.getBytes());
String hexString = fs.getHexEncodedBytes();
planFragment.setPlannodetree(hexString);
} catch (Exception e) {
e.printStackTrace();
throw compiler.new VoltCompilerException(e.getMessage());
}
}
last_plan = plan;
} // FOR (multipartition + singlepartition)
if (last_plan == null) {
throw compiler.new VoltCompilerException("Bad news! We don't have a last plan!!");
}
plan = last_plan;
// HACK
AbstractPlanNode root = null;
try {
root = PlanNodeUtil.getRootPlanNodeForStatement(catalogStmt, true);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
assert(root != null);
Collection<Table> tables_accessed = CatalogUtil.getReferencedTablesForTree(db, root);
assert(tables_accessed.isEmpty() == false) : "Failed to find accessed tables for " + catalogStmt + "-- Plan:\n" + PlanNodeUtil.debug(plan.fullWinnerPlan);
boolean all_replicated = true;
for (Table catalog_tbl : tables_accessed) {
if (catalog_tbl.getIsreplicated() == false) {
all_replicated = false;
break;
}
} // FOR
catalogStmt.setReplicatedonly(all_replicated);
// Input Parameters
// We will need to update the system catalogs with this new information
// If this is an ad hoc query then there won't be any parameters
for (ParameterInfo param : plan.parameters) {
StmtParameter catalogParam = catalogStmt.getParameters().add(String.valueOf(param.index));
catalogParam.setJavatype(param.type.getValue());
catalogParam.setIndex(param.index);
}
// Output Columns
int index = 0;
for (Integer colguid : plan.columns) {
PlanColumn planColumn = planner.getPlannerContext().get(colguid);
Column catColumn = catalogStmt.getOutput_columns().add(planColumn.getDisplayName()); // String.valueOf(index));
catColumn.setNullable(false);
catColumn.setIndex(index);
// catColumn.setName(planColumn.displayName());
catColumn.setType(planColumn.type().getValue());