if (m_bestAndOnlyPlanWasGenerated) {
return null;
}
m_bestAndOnlyPlanWasGenerated = true;
// Simply return an union plan node with a corresponding union type set
AbstractPlanNode subUnionRoot = new UnionPlanNode(m_parsedUnion.m_unionType);
m_recentErrorMsg = null;
ArrayList<CompiledPlan> childrenPlans = new ArrayList<CompiledPlan>();
StatementPartitioning commonPartitioning = null;
// Build best plans for the children first
int planId = 0;
for (AbstractParsedStmt parsedChildStmt : m_parsedUnion.m_children) {
StatementPartitioning partitioning = (StatementPartitioning)m_partitioning.clone();
PlanSelector processor = (PlanSelector) m_planSelector.clone();
processor.m_planId = planId;
PlanAssembler assembler = new PlanAssembler(
m_catalogCluster, m_catalogDb, partitioning, processor);
CompiledPlan bestChildPlan = assembler.getBestCostPlan(parsedChildStmt);
partitioning = assembler.getPartition();
// make sure we got a winner
if (bestChildPlan == null) {
m_recentErrorMsg = assembler.getErrorMessage();
if (m_recentErrorMsg == null) {
m_recentErrorMsg = "Unable to plan for statement. Error unknown.";
}
return null;
}
childrenPlans.add(bestChildPlan);
// Make sure that next child's plans won't override current ones.
planId = processor.m_planId;
// Decide whether child statements' partitioning is compatible.
if (commonPartitioning == null) {
commonPartitioning = partitioning;
continue;
}
AbstractExpression statementPartitionExpression = partitioning.singlePartitioningExpression();
if (commonPartitioning.requiresTwoFragments()) {
if (partitioning.requiresTwoFragments() || statementPartitionExpression != null) {
// If two child statements need to use a second fragment,
// it can't currently be a two-fragment plan.
// The coordinator expects a single-table result from each partition.
// Also, currently the coordinator of a two-fragment plan is not allowed to
// target a particular partition, so neither can the union of the coordinator
// and a statement that wants to run single-partition.
throw new PlanningErrorException(
"Statements are too complex in set operation using multiple partitioned tables.");
}
// the new statement is apparently a replicated read and has no effect on partitioning
continue;
}
AbstractExpression commonPartitionExpression = commonPartitioning.singlePartitioningExpression();
if (commonPartitionExpression == null) {
// the prior statement(s) were apparently replicated reads
// and have no effect on partitioning
commonPartitioning = partitioning;
continue;
}
if (partitioning.requiresTwoFragments()) {
// Again, currently the coordinator of a two-fragment plan is not allowed to
// target a particular partition, so neither can the union of the coordinator
// and a statement that wants to run single-partition.
throw new PlanningErrorException(
"Statements are too complex in set operation using multiple partitioned tables.");
}
if (statementPartitionExpression == null) {
// the new statement is apparently a replicated read and has no effect on partitioning
continue;
}
if ( ! commonPartitionExpression.equals(statementPartitionExpression)) {
throw new PlanningErrorException(
"Statements use conflicting partitioned table filters in set operation or sub-query.");
}
}
if (commonPartitioning != null) {
m_partitioning = commonPartitioning;
}
// need to reset plan id for the entire UNION
m_planSelector.m_planId = planId;
// Add and link children plans
for (CompiledPlan selectPlan : childrenPlans) {
subUnionRoot.addAndLinkChild(selectPlan.rootPlanGraph);
}
CompiledPlan retval = new CompiledPlan();
retval.rootPlanGraph = subUnionRoot;
retval.setReadOnly(true);