std::unique_ptr VisitExprImpl()

in src/search/passes/index_selection.h [183:318]


  std::unique_ptr<PlanOperator> VisitExprImpl(Expr *node) {
    struct AggregatedNodes {
      std::set<Node *> nodes;
      IntervalSet intervals;
    };

    std::map<const FieldInfo *, AggregatedNodes> agg_nodes;
    std::vector<std::variant<QueryExpr *, const FieldInfo *>> rest_nodes;

    for (const auto &n : node->inners) {
      IntervalSet is;
      const FieldInfo *field = nullptr;

      if (auto iter = intervals.find(n.get()); iter != intervals.end()) {
        field = iter->second.field_info;
        is = iter->second.intervals;
      } else if (auto expr = dynamic_cast<NumericCompareExpr *>(n.get()); expr && expr->op != NumericCompareExpr::NE) {
        field = expr->field->info;
        is = IntervalSet(expr->op, expr->num->val);
      } else {
        rest_nodes.emplace_back(n.get());
        continue;
      }

      if (!field->HasIndex()) {
        rest_nodes.emplace_back(n.get());
        continue;
      }

      if (auto jter = agg_nodes.find(field); jter != agg_nodes.end()) {
        jter->second.nodes.emplace(n.get());
        if constexpr (std::is_same_v<Expr, AndExpr>) {
          jter->second.intervals = jter->second.intervals & is;
        } else {
          jter->second.intervals = jter->second.intervals | is;
        }
      } else {
        rest_nodes.emplace_back(field);
        agg_nodes.emplace(field, AggregatedNodes{std::set<Node *>{n.get()}, is});
      }
    }

    if constexpr (std::is_same_v<Expr, AndExpr>) {
      struct SelectionInfo {
        std::unique_ptr<PlanOperator> plan;
        std::set<Node *> selected_nodes;
        size_t cost;

        SelectionInfo(std::unique_ptr<PlanOperator> &&plan, std::set<Node *> nodes)
            : plan(std::move(plan)), selected_nodes(std::move(nodes)), cost(CostModel::Transform(this->plan.get())) {}
      };

      std::vector<SelectionInfo> available_plans;

      available_plans.emplace_back(std::make_unique<FullIndexScan>(index->CloneAs<IndexRef>()), std::set<Node *>{});

      for (auto v : rest_nodes) {
        if (std::holds_alternative<QueryExpr *>(v)) {
          auto n = std::get<QueryExpr *>(v);
          auto op = TransformExpr(n);

          available_plans.emplace_back(std::move(op), std::set<Node *>{n});
        } else {
          auto n = std::get<const FieldInfo *>(v);
          const auto &agg_info = agg_nodes.at(n);
          auto field_ref = std::make_unique<FieldRef>(n->name, n);
          available_plans.emplace_back(PlanFromInterval(agg_info.intervals, field_ref.get(), SortByClause::ASC),
                                       agg_info.nodes);
        }
      }

      auto &best_plan = *std::min_element(available_plans.begin(), available_plans.end(),
                                          [](const auto &l, const auto &r) { return l.cost < r.cost; });

      std::vector<std::unique_ptr<QueryExpr>> filter_nodes;
      for (const auto &n : node->inners) {
        if (best_plan.selected_nodes.count(n.get()) == 0) filter_nodes.push_back(n->template CloneAs<QueryExpr>());
      }

      if (filter_nodes.empty()) {
        return std::move(best_plan.plan);
      } else if (filter_nodes.size() == 1) {
        return std::make_unique<Filter>(std::move(best_plan.plan), std::move(filter_nodes.front()));
      } else {
        return std::make_unique<Filter>(std::move(best_plan.plan), std::make_unique<AndExpr>(std::move(filter_nodes)));
      }
    } else {
      auto full_scan_plan = MakeFullIndexFilter(node);

      std::vector<std::unique_ptr<PlanOperator>> merged_elems;
      std::vector<std::unique_ptr<QueryExpr>> elem_filter;

      auto add_filter = [&elem_filter](std::unique_ptr<PlanOperator> op) {
        if (!elem_filter.empty()) {
          std::unique_ptr<QueryExpr> filter = std::make_unique<NotExpr>(OrExpr::Create(CloneExprs(elem_filter)));

          PushDownNotExpr pdne;
          filter = Node::MustAs<QueryExpr>(pdne.Transform(std::move(filter)));
          SimplifyAndOrExpr saoe;
          filter = Node::MustAs<QueryExpr>(saoe.Transform(std::move(filter)));

          op = std::make_unique<Filter>(std::move(op), std::move(filter));
        }

        return op;
      };

      for (auto v : rest_nodes) {
        if (std::holds_alternative<QueryExpr *>(v)) {
          auto n = std::get<QueryExpr *>(v);
          auto op = add_filter(TransformExpr(n));

          merged_elems.push_back(std::move(op));
          elem_filter.push_back(n->CloneAs<QueryExpr>());
        } else {
          auto n = std::get<const FieldInfo *>(v);
          const auto &agg_info = agg_nodes.at(n);
          auto field_ref = std::make_unique<FieldRef>(n->name, n);
          auto elem = PlanFromInterval(agg_info.intervals, field_ref.get(), SortByClause::ASC);
          elem = add_filter(std::move(elem));

          merged_elems.push_back(std::move(elem));
          for (auto nn : agg_info.nodes) {
            elem_filter.push_back(nn->template CloneAs<QueryExpr>());
          }
        }
      }

      auto merge_plan = Merge::Create(std::move(merged_elems));
      auto &best_plan = const_cast<std::unique_ptr<PlanOperator> &>(std::min(
          full_scan_plan, merge_plan,
          [](const auto &l, const auto &r) { return CostModel::Transform(l.get()) < CostModel::Transform(r.get()); }));

      return std::move(best_plan);
    }
  }