docs: private CompiledPlan compileFromXML(VoltXMLElement xmlSQL, String[] paramValues) {
          // Get a parsed statement from the xml
          // The callers of compilePlan are ready to catch any exceptions thrown here.
          // Simple constant expressions (i.e. "1 + 1" or "(2 * 4 + 2)/3") are evaluated and substituted by HSQL;
          // but expressions with functions (i.e. "cast(power(2, 3) to int)" are not.
          AbstractParsedStmt parsedStmt = AbstractParsedStmt.parse(null, m_sql, xmlSQL, paramValues, m_db, m_joinOrder);
          if (parsedStmt == null) {
              m_recentErrorMsg = "Failed to parse SQL statement: " + getOriginalSql();
              return null;
          }
  
          if (m_isUpsert) {
              // no insert/upsert with joins
              if (parsedStmt.m_tableList.size() != 1) {
                  m_recentErrorMsg = "UPSERT is supported only with one single table: " + getOriginalSql();
                  return null;
              }
  
              Table tb = parsedStmt.m_tableList.get(0);
              Constraint pkey = null;
              for (Constraint ct: tb.getConstraints()) {
                  if (ct.getType() == ConstraintType.PRIMARY_KEY.getValue()) {
                      pkey = ct;
                      break;
                  }
              }
  
              if (pkey == null) {
                  m_recentErrorMsg = "Unsupported UPSERT table without primary key: " + getOriginalSql();
                  return null;
              }
          }
          if(parsedStmt instanceof ParsedSelectStmt || parsedStmt instanceof ParsedUnionStmt) {
              final MVQueryRewriter rewriter;
              if (parsedStmt instanceof ParsedSelectStmt) {
                  rewriter = new MVQueryRewriter((ParsedSelectStmt) parsedStmt);
              } else {
                  rewriter = new MVQueryRewriter((ParsedUnionStmt) parsedStmt);
              }
              if (rewriter.rewrite() && m_paramzInfo != null) { // if query is rewritten the #parameters is likely reduced.
                  m_paramzInfo.rewrite();
              }
          }
          m_planSelector.outputParsedStatement(parsedStmt);
  
          if (m_isLargeQuery) {
              if (parsedStmt.isDML()
                      || (parsedStmt instanceof ParsedSelectStmt
                              && ((ParsedSelectStmt)parsedStmt).hasWindowFunctionExpression())) {
                  m_isLargeQuery = false;
              }
          }
  
          // Init Assembler. Each plan assembler requires a new instance of the PlanSelector
          // to keep track of the best plan
          PlanAssembler assembler = new PlanAssembler(m_db, m_partitioning,
                  (PlanSelector) m_planSelector.clone(), m_isLargeQuery);
          // find the plan with minimal cost
          CompiledPlan bestPlan = assembler.getBestCostPlan(parsedStmt);
  
          // This processing of bestPlan outside/after getBestCostPlan
          // allows getBestCostPlan to be called both here and
          // in PlanAssembler.getNextUnion on each branch of a union.
  
          // make sure we got a winner
          if (bestPlan == null) {
              if (DEBUGGING_STATIC_MODE_TO_RETRY_ON_ERROR) {
                  assembler.getBestCostPlan(parsedStmt);
              }
              m_recentErrorMsg = assembler.getErrorMessage();
              if (m_recentErrorMsg == null) {
                  m_recentErrorMsg = "Unable to plan for statement. Error unknown.";
              }
              return null;
          }
  
          // Calculate the UDF dependences.
          Collection<String> dependees = parsedStmt.calculateUDFDependees();
          if (dependees != null) {
              bestPlan.getUDFDependees().addAll(dependees);
          }
  
          if (bestPlan.isReadOnly()) {
              SendPlanNode sendNode = new SendPlanNode();
              // connect the nodes to build the graph
              sendNode.addAndLinkChild(bestPlan.rootPlanGraph);
              // this plan is final, generate schema and resolve all the column index references
              bestPlan.rootPlanGraph = sendNode;
          }
  
          // Execute the generateOutputSchema and resolveColumnIndexes once for the best plan
          bestPlan.rootPlanGraph.generateOutputSchema(m_db);
          // Make sure the schemas for base and recursive plans in common table scans
          // have identical schemas.
          harmonizeCommonTableSchemas(bestPlan);
          bestPlan.rootPlanGraph.resolveColumnIndexes();
          // Now that the plan is all together we
          // can compute the best selection microoptimizations.
          MicroOptimizationRunner.applyAll(bestPlan,
                                           parsedStmt,
                                           MicroOptimizationRunner.Phases.AFTER_COMPLETE_PLAN_ASSEMBLY);
          if (parsedStmt instanceof ParsedSelectStmt) {
              ((ParsedSelectStmt)parsedStmt).checkPlanColumnMatch(bestPlan.rootPlanGraph.getOutputSchema());
          }
  
          // reset all the plan node ids for a given plan
          // this makes the ids deterministic
          bestPlan.resetPlanNodeIds(1);
  
          // Output the best plan debug info
          assembler.finalizeBestCostPlan();
  
          // split up the plan everywhere we see send/receive into multiple plan fragments
          List<AbstractPlanNode> receives = bestPlan.rootPlanGraph.findAllNodesOfClass(AbstractReceivePlanNode.class);
          if (receives.size() > 1) {
              // Have too many receive node for two fragment plan limit
              m_recentErrorMsg = "This join of multiple partitioned tables is too complex. "
                      + "Consider simplifying its subqueries: " + getOriginalSql();
              return null;
          }
  
          /*/ enable for debug ...
          if (receives.size() > 1) {
              System.out.println(plan.rootPlanGraph.toExplainPlanString());
          }
          // ... enable for debug */
          if (receives.size() == 1) {
              AbstractReceivePlanNode recvNode = (AbstractReceivePlanNode) receives.get(0);
              fragmentize(bestPlan, recvNode);
          }
  
          return bestPlan;
      }