memgraph/tests/unit/query_plan_common.hpp
florijan 76fe8bfadf Variable expansion consolidaton
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
2017-10-05 13:12:39 +02:00

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());
}