76fe8bfadf
Summary: - Removed BreadthFirstAtom, using EdgeAtom only with a Type enum. - Both variable expansions (breadth and depth first) now have mandatory inner node and edge Identifiers. - Both variable expansions use inline property filtering and support inline lambdas. - BFS and variable expansion now have the same planning process. - Planner modified in the following ways: - Variable expansions support inline property filtering (two filters added to all_filters, one for inline, one for post-expand). - Asserting against existing_edge since we don't support that anymore. - Edge and node symbols bound after variable expansion to disallow post-expand filters to get inlined. - Some things simplified due to different handling. - BreadthFirstExpand logical operator merged into ExpandVariable. Two Cursor classes remain and are dynamically chosen from. As part of planned planner refactor we should ensure that a filter is applied only once. The current implementation is very suboptimal for property filtering in variable expansions. @buda: we will start refactoring this these days. This current planner logic is too dense and complex. It is becoming technical debt. Most of the time I spent working on this has been spent figuring the planning out, and I still needed Teon's help at times. Implementing the correct and optimal version of query execution (avoiding multiple potentially expensive filterings) was out of reach also due to tech debt. Reviewers: buda, teon.banek Reviewed By: teon.banek Subscribers: pullbot, buda Differential Revision: https://phabricator.memgraph.io/D852
203 lines
7.0 KiB
C++
203 lines
7.0 KiB
C++
//
|
|
// Copyright 2017 Memgraph
|
|
// Created by Florijan Stamenkovic on 14.03.17.
|
|
//
|
|
|
|
#pragma once
|
|
|
|
#include <iterator>
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
#include "communication/result_stream_faker.hpp"
|
|
#include "query/common.hpp"
|
|
#include "query/context.hpp"
|
|
#include "query/frontend/semantic/symbol_table.hpp"
|
|
#include "query/interpret/frame.hpp"
|
|
#include "query/plan/operator.hpp"
|
|
|
|
#include "query_common.hpp"
|
|
|
|
using namespace query;
|
|
using namespace query::plan;
|
|
|
|
using Bound = ScanAllByLabelPropertyRange::Bound;
|
|
|
|
/**
|
|
* Helper function that collects all the results from the given
|
|
* Produce into a ResultStreamFaker and returns the results from it.
|
|
*
|
|
* @param produce
|
|
* @param symbol_table
|
|
* @param db_accessor
|
|
* @return
|
|
*/
|
|
std::vector<std::vector<TypedValue>> CollectProduce(
|
|
Produce *produce, SymbolTable &symbol_table, GraphDbAccessor &db_accessor) {
|
|
ResultStreamFaker stream;
|
|
Frame frame(symbol_table.max_position());
|
|
|
|
// top level node in the operator tree is a produce (return)
|
|
// so stream out results
|
|
|
|
// generate header
|
|
std::vector<std::string> header;
|
|
for (auto named_expression : produce->named_expressions())
|
|
header.push_back(named_expression->name_);
|
|
stream.Header(header);
|
|
|
|
// collect the symbols from the return clause
|
|
std::vector<Symbol> symbols;
|
|
for (auto named_expression : produce->named_expressions())
|
|
symbols.emplace_back(symbol_table[*named_expression]);
|
|
|
|
Context context(db_accessor);
|
|
context.symbol_table_ = symbol_table;
|
|
// stream out results
|
|
auto cursor = produce->MakeCursor(db_accessor);
|
|
while (cursor->Pull(frame, context)) {
|
|
std::vector<TypedValue> values;
|
|
for (auto &symbol : symbols) values.emplace_back(frame[symbol]);
|
|
stream.Result(values);
|
|
}
|
|
|
|
stream.Summary({{std::string("type"), TypedValue("r")}});
|
|
|
|
return stream.GetResults();
|
|
}
|
|
|
|
int PullAll(std::shared_ptr<LogicalOperator> logical_op, GraphDbAccessor &db,
|
|
SymbolTable &symbol_table) {
|
|
Frame frame(symbol_table.max_position());
|
|
auto cursor = logical_op->MakeCursor(db);
|
|
int count = 0;
|
|
Context context(db);
|
|
context.symbol_table_ = symbol_table;
|
|
while (cursor->Pull(frame, context)) count++;
|
|
return count;
|
|
}
|
|
|
|
template <typename... TNamedExpressions>
|
|
auto MakeProduce(std::shared_ptr<LogicalOperator> input,
|
|
TNamedExpressions... named_expressions) {
|
|
return std::make_shared<Produce>(
|
|
input, std::vector<NamedExpression *>{named_expressions...});
|
|
}
|
|
|
|
struct ScanAllTuple {
|
|
NodeAtom *node_;
|
|
std::shared_ptr<LogicalOperator> op_;
|
|
Symbol sym_;
|
|
};
|
|
|
|
/**
|
|
* Creates and returns a tuple of stuff for a scan-all starting
|
|
* from the node with the given name.
|
|
*
|
|
* Returns ScanAllTuple(node_atom, scan_all_logical_op, symbol).
|
|
*/
|
|
ScanAllTuple MakeScanAll(AstTreeStorage &storage, SymbolTable &symbol_table,
|
|
const std::string &identifier,
|
|
std::shared_ptr<LogicalOperator> input = {nullptr},
|
|
GraphView graph_view = GraphView::OLD) {
|
|
auto node = NODE(identifier);
|
|
auto symbol = symbol_table.CreateSymbol(identifier, true);
|
|
symbol_table[*node->identifier_] = symbol;
|
|
auto logical_op = std::make_shared<ScanAll>(input, symbol, graph_view);
|
|
return ScanAllTuple{node, logical_op, symbol};
|
|
}
|
|
|
|
/**
|
|
* Creates and returns a tuple of stuff for a scan-all starting
|
|
* from the node with the given name and label.
|
|
*
|
|
* Returns ScanAllTuple(node_atom, scan_all_logical_op, symbol).
|
|
*/
|
|
ScanAllTuple MakeScanAllByLabel(
|
|
AstTreeStorage &storage, SymbolTable &symbol_table,
|
|
const std::string &identifier, const GraphDbTypes::Label &label,
|
|
std::shared_ptr<LogicalOperator> input = {nullptr},
|
|
GraphView graph_view = GraphView::OLD) {
|
|
auto node = NODE(identifier);
|
|
auto symbol = symbol_table.CreateSymbol(identifier, true);
|
|
symbol_table[*node->identifier_] = symbol;
|
|
auto logical_op =
|
|
std::make_shared<ScanAllByLabel>(input, symbol, label, graph_view);
|
|
return ScanAllTuple{node, logical_op, symbol};
|
|
}
|
|
|
|
/**
|
|
* Creates and returns a tuple of stuff for a scan-all starting from the node
|
|
* with the given name and label whose property values are in range.
|
|
*
|
|
* Returns ScanAllTuple(node_atom, scan_all_logical_op, symbol).
|
|
*/
|
|
ScanAllTuple MakeScanAllByLabelPropertyRange(
|
|
AstTreeStorage &storage, SymbolTable &symbol_table, std::string identifier,
|
|
GraphDbTypes::Label label, GraphDbTypes::Property property,
|
|
std::experimental::optional<Bound> lower_bound,
|
|
std::experimental::optional<Bound> upper_bound,
|
|
std::shared_ptr<LogicalOperator> input = {nullptr},
|
|
GraphView graph_view = GraphView::OLD) {
|
|
auto node = NODE(identifier);
|
|
auto symbol = symbol_table.CreateSymbol(identifier, true);
|
|
symbol_table[*node->identifier_] = symbol;
|
|
auto logical_op = std::make_shared<ScanAllByLabelPropertyRange>(
|
|
input, symbol, label, property, lower_bound, upper_bound, graph_view);
|
|
return ScanAllTuple{node, logical_op, symbol};
|
|
}
|
|
|
|
/**
|
|
* Creates and returns a tuple of stuff for a scan-all starting from the node
|
|
* with the given name and label whose property value is equal to given value.
|
|
*
|
|
* Returns ScanAllTuple(node_atom, scan_all_logical_op, symbol).
|
|
*/
|
|
ScanAllTuple MakeScanAllByLabelPropertyValue(
|
|
AstTreeStorage &storage, SymbolTable &symbol_table, std::string identifier,
|
|
GraphDbTypes::Label label, GraphDbTypes::Property property,
|
|
Expression *value, std::shared_ptr<LogicalOperator> input = {nullptr},
|
|
GraphView graph_view = GraphView::OLD) {
|
|
auto node = NODE(identifier);
|
|
auto symbol = symbol_table.CreateSymbol(identifier, true);
|
|
symbol_table[*node->identifier_] = symbol;
|
|
auto logical_op = std::make_shared<ScanAllByLabelPropertyValue>(
|
|
input, symbol, label, property, value, graph_view);
|
|
return ScanAllTuple{node, logical_op, symbol};
|
|
}
|
|
|
|
struct ExpandTuple {
|
|
EdgeAtom *edge_;
|
|
Symbol edge_sym_;
|
|
NodeAtom *node_;
|
|
Symbol node_sym_;
|
|
std::shared_ptr<LogicalOperator> op_;
|
|
};
|
|
|
|
ExpandTuple MakeExpand(AstTreeStorage &storage, SymbolTable &symbol_table,
|
|
std::shared_ptr<LogicalOperator> input,
|
|
Symbol input_symbol, const std::string &edge_identifier,
|
|
EdgeAtom::Direction direction,
|
|
const std::vector<GraphDbTypes::EdgeType> &edge_types,
|
|
const std::string &node_identifier, bool existing_node,
|
|
GraphView graph_view = GraphView::AS_IS) {
|
|
auto edge = EDGE(edge_identifier, direction);
|
|
auto edge_sym = symbol_table.CreateSymbol(edge_identifier, true);
|
|
symbol_table[*edge->identifier_] = edge_sym;
|
|
|
|
auto node = NODE(node_identifier);
|
|
auto node_sym = symbol_table.CreateSymbol(node_identifier, true);
|
|
symbol_table[*node->identifier_] = node_sym;
|
|
|
|
auto op =
|
|
std::make_shared<Expand>(node_sym, edge_sym, direction, edge_types, input,
|
|
input_symbol, existing_node, graph_view);
|
|
|
|
return ExpandTuple{edge, edge_sym, node, node_sym, op};
|
|
}
|
|
|
|
template <typename TIterable>
|
|
auto CountIterable(TIterable iterable) {
|
|
return std::distance(iterable.begin(), iterable.end());
|
|
}
|