Commit f2572162 authored by Paul Asmuth's avatar Paul Asmuth
Browse files

QueryPlanBuilder cleanup...

parent 60398761
Loading
Loading
Loading
Loading
+2 −40
Original line number Diff line number Diff line
@@ -121,49 +121,11 @@ ui::Canvas* Query::getChart(size_t index) const {
  assert(index < charts_.size()); // FIXPAUL
  return charts_[index].get();
}

/*
bool Query::execute(ChartRenderTarget* target) {
  Drawable* drawable = nullptr;

  for (const auto& stmt : statements_) {

    if (drawable == nullptr) {
      continue;
    }

    auto series_stmt = dynamic_cast<query::SeriesStatement*>(stmt.get());
    if (series_stmt != nullptr) {
      series_stmt->execute();
      for (const auto& series : series_stmt->getSeries()) {
        drawable->addSeries(series);
      }
    }
  }

  if (drawable == nullptr) {
    // FIXPAUL add error no drawables defined
  } else {
    drawable->draw(target);
  }

  return true;
}

Drawable* Query::makeDrawable(query::DrawStatement* stmt) {
  switch (stmt->getType()) {
    case query::DrawStatement::T_BAR_CHART:
      return new BarChart();
    default:
      assert(0); // FIXPAUL
  }
}
*/

bool Query::addStatement(
    query::ASTNode* statement,
    query::TableRepository* repo) {
  auto query_plan = query::QueryPlan::buildQueryPlan(statement, repo);
  DefaultQueryPlanBuilder query_plan_builder;
  auto query_plan = query_plan_builder.buildQueryPlan(statement, repo);
  if (query_plan == nullptr) {
    fprintf(stderr, "cant build statement");
    return false;
+0 −42
Original line number Diff line number Diff line
@@ -24,48 +24,6 @@ namespace query {
class LimitClause : public QueryPlanNode {
public:

  static LimitClause* build(ASTNode* ast, TableRepository* repo) {
    if (!(*ast == ASTNode::T_SELECT) || ast->getChildren().size() < 3) {
      return nullptr;
    }

    for (const auto& child : ast->getChildren()) {
      int limit = 0;
      int offset = 0;

      if (child->getType() != ASTNode::T_LIMIT) {
        continue;
      }

      auto limit_token = child->getToken();
      assert(limit_token);
      assert(*limit_token == Token::T_NUMERIC);
      limit = limit_token->getInteger();

      if (child->getChildren().size() == 1) {
        assert(child->getChildren()[0]->getType() == ASTNode::T_OFFSET);
        auto offset_token = child->getChildren()[0]->getToken();
        assert(offset_token);
        assert(*offset_token == Token::T_NUMERIC);
        offset = offset_token->getInteger();
      }

      auto new_ast = ast->deepCopy();
      const auto& new_ast_children = new_ast->getChildren();

      for (int i = 0; i < new_ast_children.size(); ++i) {
        if (new_ast_children[i]->getType() == ASTNode::T_LIMIT) {
          new_ast->removeChild(i);
          break;
        }
      }

      return new LimitClause(limit, offset, QueryPlan::buildQueryPlan(new_ast, repo));
    }

    return nullptr;
  }

  LimitClause(int limit, int offset, QueryPlanNode* child) :
      limit_(limit),
      offset_(offset),
+52 −9
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@
namespace fnordmetric {
namespace query {

QueryPlanNode* QueryPlan::buildQueryPlan(ASTNode* ast, TableRepository* repo) {
QueryPlanNode* DefaultQueryPlanBuilder::buildQueryPlan(ASTNode* ast, TableRepository* repo) {
  QueryPlanNode* exec = nullptr;

  /* axis statement */
@@ -40,7 +40,7 @@ QueryPlanNode* QueryPlan::buildQueryPlan(ASTNode* ast, TableRepository* repo) {
  }

  /* internal nodes: multi table query (joins), order, aggregation, limit */
  if ((exec = LimitClause::build(ast, repo)) != nullptr) {
  if ((exec = buildLimitClause(ast, repo)) != nullptr) {
    return exec;
  }

@@ -64,7 +64,7 @@ QueryPlanNode* QueryPlan::buildQueryPlan(ASTNode* ast, TableRepository* repo) {
      "can't figure out a query plan for this, sorry :(");
}

bool QueryPlan::hasGroupByClause(ASTNode* ast) {
bool DefaultQueryPlanBuilder::hasGroupByClause(ASTNode* ast) {
  if (!(*ast == ASTNode::T_SELECT) || ast->getChildren().size() < 2) {
    return false;
  }
@@ -78,7 +78,7 @@ bool QueryPlan::hasGroupByClause(ASTNode* ast) {
  return false;
}

bool QueryPlan::hasAggregationInSelectList(ASTNode* ast) {
bool DefaultQueryPlanBuilder::hasAggregationInSelectList(ASTNode* ast) {
  if (!(*ast == ASTNode::T_SELECT) || ast->getChildren().size() < 2) {
    return false;
  }
@@ -89,7 +89,7 @@ bool QueryPlan::hasAggregationInSelectList(ASTNode* ast) {
  return hasAggregationExpression(select_list);
}

bool QueryPlan::hasAggregationExpression(ASTNode* ast) {
bool DefaultQueryPlanBuilder::hasAggregationExpression(ASTNode* ast) {
  if (ast->getType() == ASTNode::T_METHOD_CALL) {
    assert(ast->getToken() != nullptr);
    auto symbol = lookupSymbol(ast->getToken()->getString());
@@ -108,7 +108,7 @@ bool QueryPlan::hasAggregationExpression(ASTNode* ast) {
  return false;
}

QueryPlanNode* QueryPlan::buildDrawStatement(ASTNode* ast) {
QueryPlanNode* DefaultQueryPlanBuilder::buildDrawStatement(ASTNode* ast) {
  DrawStatement::kDrawStatementType type;
  switch (ast->getToken()->getType()) {
    case Token::T_BAR:
@@ -131,13 +131,13 @@ QueryPlanNode* QueryPlan::buildDrawStatement(ASTNode* ast) {
  return new DrawStatement(type);
}

QueryPlanNode* QueryPlan::buildAxisStatement(
QueryPlanNode* DefaultQueryPlanBuilder::buildAxisStatement(
    ASTNode* ast,
    TableRepository* repo) {
  return new AxisStatement();
}

QueryPlanNode* QueryPlan::buildGroupBy(ASTNode* ast, TableRepository* repo) {
QueryPlanNode* DefaultQueryPlanBuilder::buildGroupBy(ASTNode* ast, TableRepository* repo) {
  ASTNode group_exprs(ASTNode::T_GROUP_BY);
  assert(ast->getChildren()[0]->getType() == ASTNode::T_SELECT_LIST);

@@ -204,7 +204,7 @@ QueryPlanNode* QueryPlan::buildGroupBy(ASTNode* ast, TableRepository* repo) {
}


bool QueryPlan::buildInternalSelectList(
bool DefaultQueryPlanBuilder::buildInternalSelectList(
    ASTNode* node,
    ASTNode* target_select_list) {
  /* search for column references recursively */
@@ -239,6 +239,49 @@ bool QueryPlan::buildInternalSelectList(
  }
}

QueryPlanNode* DefaultQueryPlanBuilder::buildLimitClause(
    ASTNode* ast,
    TableRepository* repo) {
  if (!(*ast == ASTNode::T_SELECT) || ast->getChildren().size() < 3) {
    return nullptr;
  }

  for (const auto& child : ast->getChildren()) {
    int limit = 0;
    int offset = 0;

    if (child->getType() != ASTNode::T_LIMIT) {
      continue;
    }

    auto limit_token = child->getToken();
    assert(limit_token);
    assert(*limit_token == Token::T_NUMERIC);
    limit = limit_token->getInteger();

    if (child->getChildren().size() == 1) {
      assert(child->getChildren()[0]->getType() == ASTNode::T_OFFSET);
      auto offset_token = child->getChildren()[0]->getToken();
      assert(offset_token);
      assert(*offset_token == Token::T_NUMERIC);
      offset = offset_token->getInteger();
    }

    auto new_ast = ast->deepCopy();
    const auto& new_ast_children = new_ast->getChildren();

    for (int i = 0; i < new_ast_children.size(); ++i) {
      if (new_ast_children[i]->getType() == ASTNode::T_LIMIT) {
        new_ast->removeChild(i);
        break;
      }
    }

    return new LimitClause(limit, offset, buildQueryPlan(new_ast, repo));
  }

  return nullptr;
}

}
}
+26 −12
Original line number Diff line number Diff line
@@ -22,42 +22,54 @@ namespace query {
class QueryPlanNode;
class TableRepository;

class QueryPlan {
class QueryPlanBuilder {
public:
  QueryPlanBuilder() {}
  virtual ~QueryPlanBuilder() {}

  /* Build a query plan for the provided SELECT staement */
  static QueryPlanNode* buildQueryPlan(
      ASTNode* select_statement, TableRepository* repo);
  virtual QueryPlanNode* buildQueryPlan(
      ASTNode* statement,
      TableRepository* repo) = 0;

};

class DefaultQueryPlanBuilder : public QueryPlanBuilder {
public:
  DefaultQueryPlanBuilder() {}

  QueryPlanNode* buildQueryPlan(
      ASTNode* statement,
      TableRepository* repo) override;

protected:

  static QueryPlanNode* buildDrawStatement(ASTNode* ast);
  static QueryPlanNode* buildSeriesStatement(ASTNode* ast, TableRepository* repo);
  static QueryPlanNode* buildAxisStatement(ASTNode* ast, TableRepository* repo);
  QueryPlanNode* buildDrawStatement(ASTNode* ast);
  QueryPlanNode* buildSeriesStatement(ASTNode* ast, TableRepository* repo);
  QueryPlanNode* buildAxisStatement(ASTNode* ast, TableRepository* repo);

  /**
   * Returns true if the ast is a SELECT statement that has a GROUP BY clause,
   * otherwise false
   */
  static bool hasGroupByClause(ASTNode* ast);
  bool hasGroupByClause(ASTNode* ast);

  /**
   * Returns true if the ast is a SELECT statement with a select list that
   * contains at least one aggregation expression, otherwise false.
   */
  static bool hasAggregationInSelectList(ASTNode* ast);
  bool hasAggregationInSelectList(ASTNode* ast);

  /**
   * Walks the ast recursively and returns true if at least one aggregation
   * expression was found, otherwise false.
   */
  static bool hasAggregationExpression(ASTNode* ast);
  bool hasAggregationExpression(ASTNode* ast);

  /**
   * Build a group by query plan node for a SELECT statement that has a GROUP
   * BY clause
   */
  static QueryPlanNode* buildGroupBy(ASTNode* ast, TableRepository* repo);
  QueryPlanNode* buildGroupBy(ASTNode* ast, TableRepository* repo);

  /**
   * Recursively walk the provided ast and search for column references. For
@@ -67,7 +79,9 @@ protected:
   *
   * This is used to create child select lists for nested query plan nodes.
   */
  static bool buildInternalSelectList(ASTNode* ast, ASTNode* select_list);
  bool buildInternalSelectList(ASTNode* ast, ASTNode* select_list);

  QueryPlanNode* buildLimitClause(ASTNode* ast, TableRepository* repo);

};