/**
   * Miscellaneous post parse activity .
   *
   * @param sql
   * @param db
   * @param joinOrder
   */
  @Override
  void postParse(String sql, String joinOrder) {
    for (AbstractParsedStmt selectStmt : m_children) {
      selectStmt.postParse(sql, joinOrder);
    }

    // these just shouldn't happen right?
    assert (noTableSelectionList.size() == 0);

    this.sql = sql;
    this.joinOrder = joinOrder;
  }
  @Override
  void parse(VoltXMLElement stmtNode) {
    String type = stmtNode.attributes.get("uniontype");
    // Set operation type
    m_unionType = UnionType.valueOf(type);

    assert (stmtNode.children.size() == m_children.size());
    int i = 0;
    for (VoltXMLElement selectSQL : stmtNode.children) {
      AbstractParsedStmt nextSelectStmt = m_children.get(i++);
      nextSelectStmt.parse(selectSQL);
    }
  }
  /**
   * Parse tables and parameters
   *
   * @param root
   * @param db
   */
  @Override
  void parseTablesAndParams(VoltXMLElement stmtNode) {

    assert (stmtNode.children.size() > 1);
    tableList.clear();
    for (VoltXMLElement childSQL : stmtNode.children) {
      if (childSQL.name.equalsIgnoreCase(SELECT_NODE_NAME)) {
        AbstractParsedStmt childStmt = new ParsedSelectStmt(this.m_paramValues, this.m_db);
        childStmt.parseTablesAndParams(childSQL);
        m_children.add(childStmt);

        // So far T UNION T (as well as T JOIN T) are not handled properly
        // by the fragmentizer. Need to give an error if any table is mentioned
        // in the UNION TREE more than once.
        if (childStmt.scanColumns != null) {
          for (Table table : childStmt.tableList) {
            String tableName = table.getTypeName();
            if (m_uniqueTables.contains(tableName)) {
              // The table is not 'unique' across the union
              throw new PlanningErrorException(
                  "Table " + tableName + " appears more than once in the union statement");
            } else {
              m_uniqueTables.add(tableName);
            }
          }
        } else {
          throw new PlanningErrorException("Scan columns are NULL the UNION statement");
        }
        // Add statement's tables to the consolidated list
        tableList.addAll(childStmt.tableList);
      } else if (childSQL.name.equalsIgnoreCase(UNION_NODE_NAME)) {
        ParsedUnionStmt childStmt = new ParsedUnionStmt(this.m_paramValues, this.m_db);
        // Pass already accumulated unique tables to the child union
        childStmt.m_uniqueTables = m_uniqueTables;
        childStmt.parseTablesAndParams(childSQL);
        m_children.add(childStmt);
        // Add statement's tables to the consolidated list
        tableList.addAll(childStmt.tableList);
        // Child's unique tables now contains the consolidated list
        m_uniqueTables = childStmt.m_uniqueTables;
      } else {
        throw new PlanningErrorException("Unexpected Element in UNION statement: " + childSQL.name);
      }
    }
  }
Beispiel #4
0
  /**
   * @param sql
   * @param xmlSQL
   * @param db
   */
  public static AbstractParsedStmt parse(
      String sql,
      VoltXMLElement stmtTypeElement,
      String[] paramValues,
      Database db,
      String joinOrder) {

    AbstractParsedStmt retval = null;

    if (stmtTypeElement == null) {
      System.err.println("Unexpected error parsing hsql parsed stmt xml");
      throw new RuntimeException("Unexpected error parsing hsql parsed stmt xml");
    }

    // create non-abstract instances
    if (stmtTypeElement.name.equalsIgnoreCase(INSERT_NODE_NAME)) {
      retval = new ParsedInsertStmt(paramValues, db);
    } else if (stmtTypeElement.name.equalsIgnoreCase(UPDATE_NODE_NAME)) {
      retval = new ParsedUpdateStmt(paramValues, db);
    } else if (stmtTypeElement.name.equalsIgnoreCase(DELETE_NODE_NAME)) {
      retval = new ParsedDeleteStmt(paramValues, db);
    } else if (stmtTypeElement.name.equalsIgnoreCase(SELECT_NODE_NAME)) {
      retval = new ParsedSelectStmt(paramValues, db);
    } else if (stmtTypeElement.name.equalsIgnoreCase(UNION_NODE_NAME)) {
      retval = new ParsedUnionStmt(paramValues, db);
    } else {
      throw new RuntimeException("Unexpected Element: " + stmtTypeElement.name);
    }

    // parse tables and parameters
    retval.parseTablesAndParams(stmtTypeElement);

    // parse specifics
    retval.parse(stmtTypeElement);

    // post parse action
    retval.postParse(sql, joinOrder);

    return retval;
  }
Beispiel #5
0
  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.
    AbstractParsedStmt parsedStmt =
        AbstractParsedStmt.parse(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 support 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;
      }
    }

    m_planSelector.outputParsedStatement(parsedStmt);

    // Init Assembler. Each plan assembler requires a new instance of the PlanSelector
    // to keep track of the best plan
    PlanAssembler assembler =
        new PlanAssembler(m_cluster, m_db, m_partitioning, (PlanSelector) m_planSelector.clone());
    // 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 (m_debuggingStaticModeToRetryOnError) {
        assembler.getBestCostPlan(parsedStmt);
      }
      m_recentErrorMsg = assembler.getErrorMessage();
      if (m_recentErrorMsg == null) {
        m_recentErrorMsg = "Unable to plan for statement. Error unknown.";
      }
      return null;
    }

    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);
    bestPlan.rootPlanGraph.resolveColumnIndexes();

    if (parsedStmt instanceof ParsedSelectStmt) {
      List<SchemaColumn> columns = bestPlan.rootPlanGraph.getOutputSchema().getColumns();
      ((ParsedSelectStmt) parsedStmt).checkPlanColumnMatch(columns);
    }

    // Output the best plan debug info
    assembler.finalizeBestCostPlan();

    // reset all the plan node ids for a given plan
    // this makes the ids deterministic
    bestPlan.resetPlanNodeIds(1);

    // split up the plan everywhere we see send/recieve 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;
  }