Remove AS_IS from GraphView

Summary:
Removing `AS_IS` from GraphView because it doesn't seem like it is necessary for query execution and it also has weird semantics (you might get a mix of old and new records). `Unwind`, `OrderBy` and `PullRemoteOrderBy` now use `OLD` graph view.

Remove AS_IS from GraphView

Fix query_cost_estimator tests

Fix query_expression_evaluator tests

Fix query_plan_match_filter_return tests

Fix query_plan_create_set_remove_delete tests

Fix query_plan_accumulate_aggregate tests

Reviewers: teon.banek, buda

Reviewed By: teon.banek

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D1390
This commit is contained in:
Marin Tomic 2018-05-15 13:10:15 +02:00
parent 909e42d414
commit 0a6b8cdf4f
10 changed files with 199 additions and 171 deletions

View File

@ -21,12 +21,8 @@ std::string ParseParameter(const std::string &s);
* see the OLD graph state (the latest state before the
* current transaction+command), or NEW (state as
* changed by the current transaction+command).
*
* Also some part of query execution could leave
* the graph state AS_IS, that is as it was left
* by some previous part of execution.
*/
enum class GraphView { AS_IS, OLD, NEW };
enum class GraphView { OLD, NEW };
/**
* Helper function for recursively reconstructing all the accessors in the
@ -68,4 +64,4 @@ class TypedValueVectorCompare {
// - (list, map, path, vertex, edge) can't compare to anything
bool TypedValueCompare(const TypedValue &a, const TypedValue &b) const;
};
}
} // namespace query

View File

@ -22,7 +22,7 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
ExpressionEvaluator(Frame &frame, const Parameters &parameters,
const SymbolTable &symbol_table,
database::GraphDbAccessor &db_accessor,
GraphView graph_view = GraphView::AS_IS)
GraphView graph_view)
: frame_(frame),
parameters_(parameters),
symbol_table_(symbol_table),
@ -444,7 +444,6 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
// If the given TypedValue contains accessors, switch them to New or Old,
// depending on use_new_ flag.
void SwitchAccessors(TypedValue &value) {
if (graph_view_ == GraphView::AS_IS) return;
switch (value.type()) {
case TypedValue::Type::Vertex: {
auto &vertex = value.Value<VertexAccessor>();

View File

@ -353,10 +353,7 @@ ScanAll::ScanAll(const std::shared_ptr<LogicalOperator> &input,
Symbol output_symbol, GraphView graph_view)
: input_(input ? input : std::make_shared<Once>()),
output_symbol_(output_symbol),
graph_view_(graph_view) {
CHECK(graph_view != GraphView::AS_IS)
<< "ScanAll must have explicitly defined GraphView";
}
graph_view_(graph_view) {}
ACCEPT_WITH_INPUT(ScanAll)
@ -414,32 +411,32 @@ std::unique_ptr<Cursor> ScanAllByLabelPropertyRange::MakeCursor(
-> std::experimental::optional<decltype(
db.Vertices(label_, property_, std::experimental::nullopt,
std::experimental::nullopt, false))> {
ExpressionEvaluator evaluator(frame, context.parameters_,
context.symbol_table_, db, graph_view_);
auto convert = [&evaluator](const auto &bound)
-> std::experimental::optional<utils::Bound<PropertyValue>> {
if (!bound) return std::experimental::nullopt;
auto value = bound->value()->Accept(evaluator);
try {
return std::experimental::make_optional(
utils::Bound<PropertyValue>(value, bound->type()));
} catch (const TypedValueException &) {
throw QueryRuntimeException(
"'{}' cannot be used as a property value.", value.type());
}
};
auto maybe_lower = convert(lower_bound());
auto maybe_upper = convert(upper_bound());
// If any bound is null, then the comparison would result in nulls. This
// is treated as not satisfying the filter, so return no vertices.
if (maybe_lower && maybe_lower->value().IsNull())
return std::experimental::nullopt;
if (maybe_upper && maybe_upper->value().IsNull())
return std::experimental::nullopt;
ExpressionEvaluator evaluator(frame, context.parameters_,
context.symbol_table_, db, graph_view_);
auto convert = [&evaluator](const auto &bound)
-> std::experimental::optional<utils::Bound<PropertyValue>> {
if (!bound) return std::experimental::nullopt;
auto value = bound->value()->Accept(evaluator);
try {
return std::experimental::make_optional(
db.Vertices(label_, property_, maybe_lower, maybe_upper,
graph_view_ == GraphView::NEW));
};
utils::Bound<PropertyValue>(value, bound->type()));
} catch (const TypedValueException &) {
throw QueryRuntimeException("'{}' cannot be used as a property value.",
value.type());
}
};
auto maybe_lower = convert(lower_bound());
auto maybe_upper = convert(upper_bound());
// If any bound is null, then the comparison would result in nulls. This
// is treated as not satisfying the filter, so return no vertices.
if (maybe_lower && maybe_lower->value().IsNull())
return std::experimental::nullopt;
if (maybe_upper && maybe_upper->value().IsNull())
return std::experimental::nullopt;
return std::experimental::make_optional(
db.Vertices(label_, property_, maybe_lower, maybe_upper,
graph_view_ == GraphView::NEW));
};
return std::make_unique<ScanAllCursor<decltype(vertices)>>(
output_symbol_, input_->MakeCursor(db), std::move(vertices), db);
}
@ -462,18 +459,18 @@ std::unique_ptr<Cursor> ScanAllByLabelPropertyValue::MakeCursor(
auto vertices = [this, &db](Frame &frame, Context &context)
-> std::experimental::optional<decltype(
db.Vertices(label_, property_, TypedValue::Null, false))> {
ExpressionEvaluator evaluator(frame, context.parameters_,
context.symbol_table_, db, graph_view_);
auto value = expression_->Accept(evaluator);
if (value.IsNull()) return std::experimental::nullopt;
try {
return std::experimental::make_optional(db.Vertices(
label_, property_, value, graph_view_ == GraphView::NEW));
} catch (const TypedValueException &) {
throw QueryRuntimeException(
"'{}' cannot be used as a property value.", value.type());
}
};
ExpressionEvaluator evaluator(frame, context.parameters_,
context.symbol_table_, db, graph_view_);
auto value = expression_->Accept(evaluator);
if (value.IsNull()) return std::experimental::nullopt;
try {
return std::experimental::make_optional(
db.Vertices(label_, property_, value, graph_view_ == GraphView::NEW));
} catch (const TypedValueException &) {
throw QueryRuntimeException("'{}' cannot be used as a property value.",
value.type());
}
};
return std::make_unique<ScanAllCursor<decltype(vertices)>>(
output_symbol_, input_->MakeCursor(db), std::move(vertices), db);
}
@ -666,8 +663,6 @@ void SwitchAccessor(TAccessor &accessor, GraphView graph_view) {
case GraphView::OLD:
accessor.SwitchOld();
break;
case GraphView::AS_IS:
break;
}
}
} // namespace
@ -907,7 +902,8 @@ class ExpandVariableCursor : public Cursor {
// Evaluate the upper and lower bounds.
ExpressionEvaluator evaluator(frame, context.parameters_,
context.symbol_table_, db_);
context.symbol_table_, db_,
self_.graph_view_);
auto calc_bound = [&evaluator](auto &bound) {
auto value = EvaluateInt(evaluator, bound, "Variable expansion bound");
if (value < 0)
@ -1055,7 +1051,7 @@ class ExpandBreadthFirstCursor : public query::plan::Cursor {
: self_(self), db_(db), input_cursor_(self_.input_->MakeCursor(db)) {}
bool Pull(Frame &frame, Context &context) override {
// evaulator for the filtering condition
// evaluator for the filtering condition
ExpressionEvaluator evaluator(frame, context.parameters_,
context.symbol_table_, db_,
self_.graph_view_);
@ -1224,7 +1220,8 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor {
// For the given (edge, vertex, weight, depth) tuple checks if they
// satisfy the "where" condition. if so, places them in the priority queue.
auto expand_pair = [this, &evaluator, &frame, &create_state](
EdgeAccessor edge, VertexAccessor vertex, double weight, int depth) {
EdgeAccessor edge, VertexAccessor vertex,
double weight, int depth) {
SwitchAccessor(edge, self_.graph_view_);
SwitchAccessor(vertex, self_.graph_view_);
@ -2433,10 +2430,11 @@ Skip::SkipCursor::SkipCursor(const Skip &self, database::GraphDbAccessor &db)
bool Skip::SkipCursor::Pull(Frame &frame, Context &context) {
while (input_cursor_->Pull(frame, context)) {
if (to_skip_ == -1) {
// first successful pull from the input
// evaluate the skip expression
// First successful pull from the input, evaluate the skip expression. The
// skip expression doesn't contain identifiers so graph view parameter is
// not important.
ExpressionEvaluator evaluator(frame, context.parameters_,
context.symbol_table_, db_);
context.symbol_table_, db_, GraphView::OLD);
TypedValue to_skip = self_.expression_->Accept(evaluator);
if (to_skip.type() != TypedValue::Type::Int)
throw QueryRuntimeException("Result of SKIP expression must be an int");
@ -2484,13 +2482,15 @@ Limit::LimitCursor::LimitCursor(const Limit &self,
: self_(self), db_(db), input_cursor_(self_.input_->MakeCursor(db)) {}
bool Limit::LimitCursor::Pull(Frame &frame, Context &context) {
// we need to evaluate the limit expression before the first input Pull
// because it might be 0 and thereby we shouldn't Pull from input at all
// we can do this before Pulling from the input because the limit
// expression is not allowed to contain any identifiers
// We need to evaluate the limit expression before the first input Pull
// because it might be 0 and thereby we shouldn't Pull from input at all.
// We can do this before Pulling from the input because the limit expression
// is not allowed to contain any identifiers.
if (limit_ == -1) {
// Limit expression doesn't contain identifiers so graph view is not
// important.
ExpressionEvaluator evaluator(frame, context.parameters_,
context.symbol_table_, db_);
context.symbol_table_, db_, GraphView::OLD);
TypedValue limit = self_.expression_->Accept(evaluator);
if (limit.type() != TypedValue::Type::Int)
throw QueryRuntimeException("Result of LIMIT expression must be an int");
@ -2552,7 +2552,7 @@ OrderBy::OrderByCursor::OrderByCursor(const OrderBy &self,
bool OrderBy::OrderByCursor::Pull(Frame &frame, Context &context) {
if (!did_pull_all_) {
ExpressionEvaluator evaluator(frame, context.parameters_,
context.symbol_table_, db_);
context.symbol_table_, db_, GraphView::OLD);
while (input_cursor_->Pull(frame, context)) {
// collect the order_by elements
std::vector<TypedValue> order_by;
@ -2782,7 +2782,7 @@ bool Unwind::UnwindCursor::Pull(Frame &frame, Context &context) {
// successful pull from input, initialize value and iterator
ExpressionEvaluator evaluator(frame, context.parameters_,
context.symbol_table_, db_);
context.symbol_table_, db_, GraphView::OLD);
TypedValue input_value = self_.input_expression_->Accept(evaluator);
if (input_value.type() != TypedValue::Type::List)
throw QueryRuntimeException("UNWIND only accepts list values, got '{}'",
@ -3501,7 +3501,8 @@ class PullRemoteOrderByCursor : public Cursor {
bool Pull(Frame &frame, Context &context) {
if (context.db_accessor_.should_abort()) throw HintedAbortError();
ExpressionEvaluator evaluator(frame, context.parameters_,
context.symbol_table_, context.db_accessor_);
context.symbol_table_, context.db_accessor_,
GraphView::OLD);
auto evaluate_result = [this, &evaluator]() {
std::vector<TypedValue> order_by;

View File

@ -645,7 +645,7 @@ expansion")
const std::vector<storage::EdgeType> &edge_types,
const std::shared_ptr<LogicalOperator> &input,
Symbol input_symbol, bool existing_node,
GraphView graph_view = GraphView::AS_IS);
GraphView graph_view);
cpp<#)
(:protected
#>cpp
@ -808,7 +808,7 @@ pulled.")
Symbol input_symbol, bool existing_node, Lambda filter_lambda,
std::experimental::optional<Lambda> weight_lambda,
std::experimental::optional<Symbol> total_weight,
GraphView graph_view = GraphView::AS_IS);
GraphView graph_view);
bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override;
std::unique_ptr<Cursor> MakeCursor(

View File

@ -163,7 +163,7 @@ TEST_F(QueryCostEstimator, ScanAllByLabelPropertyRangeConstExpr) {
TEST_F(QueryCostEstimator, Expand) {
MakeOp<Expand>(NextSymbol(), NextSymbol(), EdgeAtom::Direction::IN,
std::vector<storage::EdgeType>{}, last_op_, NextSymbol(),
false);
false, GraphView::OLD);
EXPECT_COST(CardParam::kExpand * CostParam::kExpand);
}
@ -173,7 +173,7 @@ TEST_F(QueryCostEstimator, ExpandVariable) {
EdgeAtom::Direction::IN, std::vector<storage::EdgeType>{}, false, nullptr,
nullptr, last_op_, NextSymbol(), false,
ExpandVariable::Lambda{NextSymbol(), NextSymbol(), nullptr},
std::experimental::nullopt, std::experimental::nullopt);
std::experimental::nullopt, std::experimental::nullopt, GraphView::OLD);
EXPECT_COST(CardParam::kExpandVariable * CostParam::kExpandVariable);
}
@ -199,11 +199,12 @@ TEST_F(QueryCostEstimator, ExpandUniquenessFilter) {
}
TEST_F(QueryCostEstimator, UnwindLiteral) {
TEST_OP(MakeOp<query::plan::Unwind>(
last_op_, storage_.Create<ListLiteral>(
std::vector<Expression *>(7, nullptr)),
NextSymbol()),
CostParam::kUnwind, 7);
TEST_OP(
MakeOp<query::plan::Unwind>(
last_op_,
storage_.Create<ListLiteral>(std::vector<Expression *>(7, nullptr)),
NextSymbol()),
CostParam::kUnwind, 7);
}
TEST_F(QueryCostEstimator, UnwindNoLiteral) {

View File

@ -33,7 +33,8 @@ struct NoContextExpressionEvaluator {
database::SingleNode db;
database::GraphDbAccessor dba{db};
Parameters parameters;
ExpressionEvaluator eval{frame, parameters, symbol_table, dba};
ExpressionEvaluator eval{frame, parameters, symbol_table, dba,
GraphView::OLD};
};
TypedValue EvaluateFunction(const std::string &function_name,
@ -44,7 +45,8 @@ TypedValue EvaluateFunction(const std::string &function_name,
database::GraphDbAccessor dba(db);
Frame frame{128};
Parameters parameters;
ExpressionEvaluator eval{frame, parameters, symbol_table, dba};
ExpressionEvaluator eval{frame, parameters, symbol_table, dba,
GraphView::OLD};
std::vector<Expression *> expressions;
for (const auto &arg : args) {
@ -719,7 +721,8 @@ TEST(ExpressionEvaluator, Aggregation) {
database::SingleNode db;
database::GraphDbAccessor dba(db);
Parameters parameters;
ExpressionEvaluator eval{frame, parameters, symbol_table, dba};
ExpressionEvaluator eval{frame, parameters, symbol_table, dba,
GraphView::OLD};
auto value = aggr->Accept(eval);
EXPECT_EQ(value.Value<int64_t>(), 1);
}

View File

@ -42,8 +42,9 @@ TEST(QueryPlan, Accumulate) {
SymbolTable symbol_table;
auto n = MakeScanAll(storage, symbol_table, "n");
auto r_m = MakeExpand(storage, symbol_table, n.op_, n.sym_, "r",
EdgeAtom::Direction::BOTH, {}, "m", false);
auto r_m =
MakeExpand(storage, symbol_table, n.op_, n.sym_, "r",
EdgeAtom::Direction::BOTH, {}, "m", false, GraphView::OLD);
auto one = LITERAL(1);
auto n_p = PROPERTY_LOOKUP("n", prop);

View File

@ -176,7 +176,7 @@ ExpandTuple MakeExpand(AstTreeStorage &storage, SymbolTable &symbol_table,
EdgeAtom::Direction direction,
const std::vector<storage::EdgeType> &edge_types,
const std::string &node_identifier, bool existing_node,
GraphView graph_view = GraphView::AS_IS) {
GraphView graph_view) {
auto edge = EDGE(edge_identifier, direction);
auto edge_sym = symbol_table.CreateSymbol(edge_identifier, true);
symbol_table[*edge->identifier_] = edge_sym;

View File

@ -295,8 +295,9 @@ TEST(QueryPlan, Delete) {
// delete all remaining edges
{
auto n = MakeScanAll(storage, symbol_table, "n");
auto r_m = MakeExpand(storage, symbol_table, n.op_, n.sym_, "r",
EdgeAtom::Direction::OUT, {}, "m", false);
auto r_m =
MakeExpand(storage, symbol_table, n.op_, n.sym_, "r",
EdgeAtom::Direction::OUT, {}, "m", false, GraphView::NEW);
auto r_get = storage.Create<Identifier>("r");
symbol_table[*r_get] = r_m.edge_sym_;
auto delete_op = std::make_shared<plan::Delete>(
@ -348,8 +349,9 @@ TEST(QueryPlan, DeleteTwiceDeleteBlockingEdge) {
SymbolTable symbol_table;
auto n = MakeScanAll(storage, symbol_table, "n");
auto r_m = MakeExpand(storage, symbol_table, n.op_, n.sym_, "r",
EdgeAtom::Direction::BOTH, {}, "m", false);
auto r_m =
MakeExpand(storage, symbol_table, n.op_, n.sym_, "r",
EdgeAtom::Direction::BOTH, {}, "m", false, GraphView::OLD);
// getter expressions for deletion
auto n_get = storage.Create<Identifier>("n");
@ -471,8 +473,9 @@ TEST(QueryPlan, SetProperty) {
// scan (n)-[r]->(m)
auto n = MakeScanAll(storage, symbol_table, "n");
auto r_m = MakeExpand(storage, symbol_table, n.op_, n.sym_, "r",
EdgeAtom::Direction::OUT, {}, "m", false);
auto r_m =
MakeExpand(storage, symbol_table, n.op_, n.sym_, "r",
EdgeAtom::Direction::OUT, {}, "m", false, GraphView::OLD);
// set prop1 to 42 on n and r
auto prop1 = dba.Property("prop1");
@ -522,8 +525,9 @@ TEST(QueryPlan, SetProperties) {
// scan (n)-[r]->(m)
auto n = MakeScanAll(storage, symbol_table, "n");
auto r_m = MakeExpand(storage, symbol_table, n.op_, n.sym_, "r",
EdgeAtom::Direction::OUT, {}, "m", false);
auto r_m =
MakeExpand(storage, symbol_table, n.op_, n.sym_, "r",
EdgeAtom::Direction::OUT, {}, "m", false, GraphView::OLD);
auto op = update ? plan::SetProperties::Op::UPDATE
: plan::SetProperties::Op::REPLACE;
@ -625,8 +629,9 @@ TEST(QueryPlan, RemoveProperty) {
// scan (n)-[r]->(m)
auto n = MakeScanAll(storage, symbol_table, "n");
auto r_m = MakeExpand(storage, symbol_table, n.op_, n.sym_, "r",
EdgeAtom::Direction::OUT, {}, "m", false);
auto r_m =
MakeExpand(storage, symbol_table, n.op_, n.sym_, "r",
EdgeAtom::Direction::OUT, {}, "m", false, GraphView::OLD);
auto n_p = PROPERTY_LOOKUP("n", prop1);
symbol_table[*n_p->expression_] = n.sym_;
@ -702,8 +707,9 @@ TEST(QueryPlan, NodeFilterSet) {
// MATCH (n {prop: 42}) -[r]- (m)
auto scan_all = MakeScanAll(storage, symbol_table, "n");
scan_all.node_->properties_[prop] = LITERAL(42);
auto expand = MakeExpand(storage, symbol_table, scan_all.op_, scan_all.sym_,
"r", EdgeAtom::Direction::BOTH, {}, "m", false);
auto expand =
MakeExpand(storage, symbol_table, scan_all.op_, scan_all.sym_, "r",
EdgeAtom::Direction::BOTH, {}, "m", false, GraphView::OLD);
auto *filter_expr =
EQ(storage.Create<PropertyLookup>(scan_all.node_->identifier_, prop),
LITERAL(42));
@ -741,8 +747,9 @@ TEST(QueryPlan, FilterRemove) {
// MATCH (n) -[r]- (m) WHERE n.prop < 43
auto scan_all = MakeScanAll(storage, symbol_table, "n");
scan_all.node_->properties_[prop] = LITERAL(42);
auto expand = MakeExpand(storage, symbol_table, scan_all.op_, scan_all.sym_,
"r", EdgeAtom::Direction::BOTH, {}, "m", false);
auto expand =
MakeExpand(storage, symbol_table, scan_all.op_, scan_all.sym_, "r",
EdgeAtom::Direction::BOTH, {}, "m", false, GraphView::OLD);
auto filter_prop = PROPERTY_LOOKUP("n", prop);
symbol_table[*filter_prop->expression_] = scan_all.sym_;
auto filter =
@ -803,8 +810,9 @@ TEST(QueryPlan, Merge) {
auto n = MakeScanAll(storage, symbol_table, "n");
// merge_match branch
auto r_m = MakeExpand(storage, symbol_table, std::make_shared<Once>(), n.sym_,
"r", EdgeAtom::Direction::BOTH, {}, "m", false);
auto r_m =
MakeExpand(storage, symbol_table, std::make_shared<Once>(), n.sym_, "r",
EdgeAtom::Direction::BOTH, {}, "m", false, GraphView::OLD);
auto m_p = PROPERTY_LOOKUP("m", prop);
symbol_table[*m_p->expression_] = r_m.node_sym_;
auto m_set = std::make_shared<plan::SetProperty>(r_m.op_, m_p, LITERAL(1));

View File

@ -418,10 +418,10 @@ TEST_F(ExpandFixture, Expand) {
return PullAll(produce, dba_, symbol_table);
};
EXPECT_EQ(2, test_expand(EdgeAtom::Direction::OUT, GraphView::AS_IS));
EXPECT_EQ(2, test_expand(EdgeAtom::Direction::IN, GraphView::AS_IS));
EXPECT_EQ(4, test_expand(EdgeAtom::Direction::BOTH, GraphView::AS_IS));
//
EXPECT_EQ(2, test_expand(EdgeAtom::Direction::OUT, GraphView::OLD));
EXPECT_EQ(2, test_expand(EdgeAtom::Direction::IN, GraphView::OLD));
EXPECT_EQ(4, test_expand(EdgeAtom::Direction::BOTH, GraphView::OLD));
// test that expand works well for both old and new graph state
v1.Reconstruct();
v2.Reconstruct();
@ -442,8 +442,9 @@ TEST_F(ExpandFixture, Expand) {
TEST_F(ExpandFixture, ExpandPath) {
auto n = MakeScanAll(storage, symbol_table, "n");
auto r_m = MakeExpand(storage, symbol_table, n.op_, n.sym_, "r",
EdgeAtom::Direction::OUT, {}, "m", false);
auto r_m =
MakeExpand(storage, symbol_table, n.op_, n.sym_, "r",
EdgeAtom::Direction::OUT, {}, "m", false, GraphView::OLD);
Symbol path_sym = symbol_table.CreateSymbol("path", true);
auto path = std::make_shared<ConstructNamedPath>(
r_m.op_, path_sym,
@ -540,7 +541,7 @@ class QueryPlanExpandVariable : public testing::Test {
const std::vector<storage::EdgeType> &edge_types,
std::experimental::optional<size_t> lower,
std::experimental::optional<size_t> upper, Symbol edge_sym,
const std::string &node_to, GraphView graph_view = GraphView::AS_IS,
const std::string &node_to, GraphView graph_view,
bool is_reverse = false) {
auto n_from = MakeScanAll(storage, symbol_table, node_from, input_op);
auto filter_op = std::make_shared<Filter>(
@ -628,7 +629,7 @@ TEST_F(QueryPlanExpandVariable, OneVariableExpansion) {
auto e = Edge("r", direction);
return GetEdgeListSizes(
AddMatch<ExpandVariable>(nullptr, "n", layer, direction, {}, lower,
upper, e, "m", GraphView::AS_IS, reverse),
upper, e, "m", GraphView::OLD, reverse),
e);
};
@ -691,18 +692,19 @@ TEST_F(QueryPlanExpandVariable, EdgeUniquenessSingleAndVariableExpansion) {
if (single_expansion_before) {
symbols.push_back(Edge("r0", direction));
last_op = AddMatch<Expand>(last_op, "n0", layer, direction, {}, lower,
upper, symbols.back(), "m0");
upper, symbols.back(), "m0", GraphView::OLD);
}
auto var_length_sym = Edge("r1", direction);
symbols.push_back(var_length_sym);
last_op = AddMatch<ExpandVariable>(last_op, "n1", layer, direction, {},
lower, upper, var_length_sym, "m1");
last_op =
AddMatch<ExpandVariable>(last_op, "n1", layer, direction, {}, lower,
upper, var_length_sym, "m1", GraphView::OLD);
if (!single_expansion_before) {
symbols.push_back(Edge("r2", direction));
last_op = AddMatch<Expand>(last_op, "n2", layer, direction, {}, lower,
upper, symbols.back(), "m2");
upper, symbols.back(), "m2", GraphView::OLD);
}
if (add_uniqueness_check) {
@ -731,11 +733,13 @@ TEST_F(QueryPlanExpandVariable, EdgeUniquenessTwoVariableExpansions) {
std::experimental::optional<size_t> upper,
bool add_uniqueness_check) {
auto e1 = Edge("r1", direction);
auto first = AddMatch<ExpandVariable>(nullptr, "n1", layer, direction, {},
lower, upper, e1, "m1");
auto first =
AddMatch<ExpandVariable>(nullptr, "n1", layer, direction, {}, lower,
upper, e1, "m1", GraphView::OLD);
auto e2 = Edge("r2", direction);
auto last_op = AddMatch<ExpandVariable>(first, "n2", layer, direction, {},
lower, upper, e2, "m2");
auto last_op =
AddMatch<ExpandVariable>(first, "n2", layer, direction, {}, lower,
upper, e2, "m2", GraphView::OLD);
if (add_uniqueness_check) {
last_op = std::make_shared<ExpandUniquenessFilter<EdgeAccessor>>(
last_op, e2, std::vector<Symbol>{e1});
@ -785,8 +789,9 @@ TEST_F(QueryPlanExpandVariable, GraphState) {
TEST_F(QueryPlanExpandVariable, NamedPath) {
auto e = Edge("r", EdgeAtom::Direction::OUT);
auto expand = AddMatch<ExpandVariable>(
nullptr, "n", 0, EdgeAtom::Direction::OUT, {}, 2, 2, e, "m");
auto expand =
AddMatch<ExpandVariable>(nullptr, "n", 0, EdgeAtom::Direction::OUT, {}, 2,
2, e, "m", GraphView::OLD);
auto find_symbol = [this](const std::string &name) {
for (const auto &pos_sym : symbol_table.table())
if (pos_sym.second.name() == name) return pos_sym.second;
@ -876,7 +881,7 @@ class QueryPlanExpandBreadthFirst : public testing::Test {
// defines and performs a breadth-first expansion with the given params
// returns a vector of pairs. each pair is (vector-of-edges, vertex)
auto ExpandBF(EdgeAtom::Direction direction, int max_depth, Expression *where,
GraphView graph_view = GraphView::AS_IS,
GraphView graph_view,
std::experimental::optional<int> node_id = 0,
ScanAllTuple *existing_node_input = nullptr) {
// scan the nodes optionally filtering on property value
@ -934,7 +939,8 @@ class QueryPlanExpandBreadthFirst : public testing::Test {
#define EXPECT_EITHER(value, a, b) EXPECT_TRUE(value == a || value == b)
TEST_F(QueryPlanExpandBreadthFirst, Basic) {
auto results = ExpandBF(EdgeAtom::Direction::BOTH, 1000, LITERAL(true));
auto results =
ExpandBF(EdgeAtom::Direction::BOTH, 1000, LITERAL(true), GraphView::OLD);
ASSERT_EQ(results.size(), 3);
@ -955,7 +961,8 @@ TEST_F(QueryPlanExpandBreadthFirst, Basic) {
TEST_F(QueryPlanExpandBreadthFirst, EdgeDirection) {
{
auto results = ExpandBF(EdgeAtom::Direction::IN, 1000, LITERAL(true));
auto results =
ExpandBF(EdgeAtom::Direction::IN, 1000, LITERAL(true), GraphView::OLD);
ASSERT_EQ(results.size(), 3);
EXPECT_EQ(GetProp(results[0].second), 2);
EXPECT_EQ(GetProp(results[1].second), 3);
@ -964,7 +971,8 @@ TEST_F(QueryPlanExpandBreadthFirst, EdgeDirection) {
// assume edges are OK because vertices are (tested before)
}
{
auto results = ExpandBF(EdgeAtom::Direction::OUT, 1000, LITERAL(true));
auto results =
ExpandBF(EdgeAtom::Direction::OUT, 1000, LITERAL(true), GraphView::OLD);
ASSERT_EQ(results.size(), 3);
EXPECT_EQ(GetProp(results[0].second), 1);
EXPECT_EQ(GetProp(results[1].second), 3);
@ -976,15 +984,15 @@ TEST_F(QueryPlanExpandBreadthFirst, EdgeDirection) {
TEST_F(QueryPlanExpandBreadthFirst, Where) {
{
auto results =
ExpandBF(EdgeAtom::Direction::BOTH, 1000, PropNe(inner_node, 2));
auto results = ExpandBF(EdgeAtom::Direction::BOTH, 1000,
PropNe(inner_node, 2), GraphView::OLD);
ASSERT_EQ(results.size(), 2);
EXPECT_EQ(GetProp(results[0].second), 1);
EXPECT_EQ(GetProp(results[1].second), 3);
}
{
auto results =
ExpandBF(EdgeAtom::Direction::BOTH, 1000, PropNe(inner_edge, 20));
auto results = ExpandBF(EdgeAtom::Direction::BOTH, 1000,
PropNe(inner_edge, 20), GraphView::OLD);
ASSERT_EQ(results.size(), 3);
EXPECT_EQ(GetProp(results[0].second), 1);
EXPECT_EITHER(GetProp(results[1].second), 3, 2);
@ -1014,7 +1022,7 @@ TEST_F(QueryPlanExpandBreadthFirst, GraphState) {
TEST_F(QueryPlanExpandBreadthFirst, MultipleInputs) {
auto results = ExpandBF(EdgeAtom::Direction::OUT, 1000, LITERAL(true),
GraphView::AS_IS, std::experimental::nullopt);
GraphView::OLD, std::experimental::nullopt);
// expect that each vertex has been returned 3 times
EXPECT_EQ(results.size(), 12);
std::vector<int> found(4, 0);
@ -1037,7 +1045,7 @@ TEST_F(QueryPlanExpandBreadthFirst, ExistingNode) {
}
return ExpandBF(EdgeAtom::Direction::OUT, 1000, LITERAL(true),
GraphView::AS_IS, std::experimental::nullopt, &n0);
GraphView::OLD, std::experimental::nullopt, &n0);
};
EXPECT_EQ(ExpandPreceeding(std::experimental::nullopt).size(), 12);
@ -1112,8 +1120,7 @@ class QueryPlanExpandWeightedShortestPath : public testing::Test {
// returns a vector of pairs. each pair is (vector-of-edges, vertex)
auto ExpandWShortest(EdgeAtom::Direction direction,
std::experimental::optional<int> max_depth,
Expression *where,
GraphView graph_view = GraphView::AS_IS,
Expression *where, GraphView graph_view,
std::experimental::optional<int> node_id = 0,
ScanAllTuple *existing_node_input = nullptr) {
// scan the nodes optionally filtering on property value
@ -1191,8 +1198,8 @@ class QueryPlanExpandWeightedShortestPath : public testing::Test {
// 3 3 3
TEST_F(QueryPlanExpandWeightedShortestPath, Basic) {
auto results =
ExpandWShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true));
auto results = ExpandWShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true),
GraphView::OLD);
ASSERT_EQ(results.size(), 4);
@ -1225,8 +1232,8 @@ TEST_F(QueryPlanExpandWeightedShortestPath, Basic) {
TEST_F(QueryPlanExpandWeightedShortestPath, EdgeDirection) {
{
auto results =
ExpandWShortest(EdgeAtom::Direction::OUT, 1000, LITERAL(true));
auto results = ExpandWShortest(EdgeAtom::Direction::OUT, 1000,
LITERAL(true), GraphView::OLD);
ASSERT_EQ(results.size(), 4);
EXPECT_EQ(GetProp(results[0].vertex), 2);
EXPECT_EQ(results[0].total_weight, 3);
@ -1238,8 +1245,8 @@ TEST_F(QueryPlanExpandWeightedShortestPath, EdgeDirection) {
EXPECT_EQ(results[3].total_weight, 9);
}
{
auto results =
ExpandWShortest(EdgeAtom::Direction::IN, 1000, LITERAL(true));
auto results = ExpandWShortest(EdgeAtom::Direction::IN, 1000, LITERAL(true),
GraphView::OLD);
ASSERT_EQ(results.size(), 4);
EXPECT_EQ(GetProp(results[0].vertex), 4);
EXPECT_EQ(results[0].total_weight, 12);
@ -1255,7 +1262,7 @@ TEST_F(QueryPlanExpandWeightedShortestPath, EdgeDirection) {
TEST_F(QueryPlanExpandWeightedShortestPath, Where) {
{
auto results = ExpandWShortest(EdgeAtom::Direction::BOTH, 1000,
PropNe(filter_node, 2));
PropNe(filter_node, 2), GraphView::OLD);
ASSERT_EQ(results.size(), 3);
EXPECT_EQ(GetProp(results[0].vertex), 1);
EXPECT_EQ(results[0].total_weight, 5);
@ -1266,7 +1273,7 @@ TEST_F(QueryPlanExpandWeightedShortestPath, Where) {
}
{
auto results = ExpandWShortest(EdgeAtom::Direction::BOTH, 1000,
PropNe(filter_node, 1));
PropNe(filter_node, 1), GraphView::OLD);
ASSERT_EQ(results.size(), 3);
EXPECT_EQ(GetProp(results[0].vertex), 2);
EXPECT_EQ(results[0].total_weight, 3);
@ -1299,23 +1306,23 @@ TEST_F(QueryPlanExpandWeightedShortestPath, GraphState) {
}
TEST_F(QueryPlanExpandWeightedShortestPath, ExistingNode) {
auto ExpandPreceeding = [this](
std::experimental::optional<int> preceeding_node_id) {
// scan the nodes optionally filtering on property value
auto n0 = MakeScanAll(storage, symbol_table, "n0");
if (preceeding_node_id) {
auto filter = std::make_shared<Filter>(
n0.op_, EQ(PROPERTY_LOOKUP(n0.node_->identifier_, prop),
LITERAL(*preceeding_node_id)));
// inject the filter op into the ScanAllTuple. that way the filter op
// can be passed into the ExpandWShortest function without too much
// refactor
n0.op_ = filter;
}
auto ExpandPreceeding =
[this](std::experimental::optional<int> preceeding_node_id) {
// scan the nodes optionally filtering on property value
auto n0 = MakeScanAll(storage, symbol_table, "n0");
if (preceeding_node_id) {
auto filter = std::make_shared<Filter>(
n0.op_, EQ(PROPERTY_LOOKUP(n0.node_->identifier_, prop),
LITERAL(*preceeding_node_id)));
// inject the filter op into the ScanAllTuple. that way the filter op
// can be passed into the ExpandWShortest function without too much
// refactor
n0.op_ = filter;
}
return ExpandWShortest(EdgeAtom::Direction::OUT, 1000, LITERAL(true),
GraphView::AS_IS, std::experimental::nullopt, &n0);
};
return ExpandWShortest(EdgeAtom::Direction::OUT, 1000, LITERAL(true),
GraphView::OLD, std::experimental::nullopt, &n0);
};
EXPECT_EQ(ExpandPreceeding(std::experimental::nullopt).size(), 20);
{
@ -1327,8 +1334,9 @@ TEST_F(QueryPlanExpandWeightedShortestPath, ExistingNode) {
TEST_F(QueryPlanExpandWeightedShortestPath, UpperBound) {
{
auto results = ExpandWShortest(EdgeAtom::Direction::BOTH,
std::experimental::nullopt, LITERAL(true));
auto results =
ExpandWShortest(EdgeAtom::Direction::BOTH, std::experimental::nullopt,
LITERAL(true), GraphView::OLD);
ASSERT_EQ(results.size(), 4);
EXPECT_EQ(GetProp(results[0].vertex), 2);
EXPECT_EQ(results[0].total_weight, 3);
@ -1361,7 +1369,8 @@ TEST_F(QueryPlanExpandWeightedShortestPath, UpperBound) {
EXPECT_EQ(results[4].total_weight, 12);
}
{
auto results = ExpandWShortest(EdgeAtom::Direction::BOTH, 2, LITERAL(true));
auto results = ExpandWShortest(EdgeAtom::Direction::BOTH, 2, LITERAL(true),
GraphView::OLD);
ASSERT_EQ(results.size(), 4);
EXPECT_EQ(GetProp(results[0].vertex), 2);
EXPECT_EQ(results[0].total_weight, 3);
@ -1373,7 +1382,8 @@ TEST_F(QueryPlanExpandWeightedShortestPath, UpperBound) {
EXPECT_EQ(results[3].total_weight, 10);
}
{
auto results = ExpandWShortest(EdgeAtom::Direction::BOTH, 1, LITERAL(true));
auto results = ExpandWShortest(EdgeAtom::Direction::BOTH, 1, LITERAL(true),
GraphView::OLD);
ASSERT_EQ(results.size(), 3);
EXPECT_EQ(GetProp(results[0].vertex), 2);
EXPECT_EQ(results[0].total_weight, 3);
@ -1433,8 +1443,9 @@ TEST(QueryPlan, ExpandOptional) {
// MATCH (n) OPTIONAL MATCH (n)-[r]->(m)
auto n = MakeScanAll(storage, symbol_table, "n");
auto r_m = MakeExpand(storage, symbol_table, nullptr, n.sym_, "r",
EdgeAtom::Direction::OUT, {}, "m", false);
auto r_m =
MakeExpand(storage, symbol_table, nullptr, n.sym_, "r",
EdgeAtom::Direction::OUT, {}, "m", false, GraphView::OLD);
auto optional = std::make_shared<plan::Optional>(
n.op_, r_m.op_, std::vector<Symbol>{r_m.edge_sym_, r_m.node_sym_});
@ -1508,8 +1519,9 @@ TEST(QueryPlan, OptionalMatchEmptyDBExpandFromNode) {
symbol_table[*n_ne] = with_n_sym;
auto with = MakeProduce(optional, n_ne);
// MATCH (n) -[r]-> (m)
auto r_m = MakeExpand(storage, symbol_table, with, with_n_sym, "r",
EdgeAtom::Direction::OUT, {}, "m", false);
auto r_m =
MakeExpand(storage, symbol_table, with, with_n_sym, "r",
EdgeAtom::Direction::OUT, {}, "m", false, GraphView::OLD);
// RETURN m
auto m_ne = NEXPR("m", IDENT("m"));
symbol_table[*m_ne->expression_] = r_m.node_sym_;
@ -1558,7 +1570,7 @@ TEST(QueryPlan, OptionalMatchThenExpandToMissingNode) {
symbol_table[*node->identifier_] = with_n_sym;
auto expand = std::make_shared<plan::Expand>(
with_n_sym, edge_sym, edge_direction, std::vector<storage::EdgeType>{},
m.op_, m.sym_, true);
m.op_, m.sym_, true, GraphView::OLD);
// RETURN m
auto m_ne = NEXPR("m", IDENT("m"));
symbol_table[*m_ne->expression_] = m.sym_;
@ -1587,11 +1599,13 @@ TEST(QueryPlan, ExpandExistingNode) {
auto test_existing = [&](bool with_existing, int expected_result_count) {
auto n = MakeScanAll(storage, symbol_table, "n");
auto r_n = MakeExpand(storage, symbol_table, n.op_, n.sym_, "r",
EdgeAtom::Direction::OUT, {}, "n", with_existing);
EdgeAtom::Direction::OUT, {}, "n", with_existing,
GraphView::OLD);
if (with_existing)
r_n.op_ = std::make_shared<Expand>(
n.sym_, r_n.edge_sym_, r_n.edge_->direction_,
std::vector<storage::EdgeType>{}, n.op_, n.sym_, with_existing);
r_n.op_ =
std::make_shared<Expand>(n.sym_, r_n.edge_sym_, r_n.edge_->direction_,
std::vector<storage::EdgeType>{}, n.op_,
n.sym_, with_existing, GraphView::OLD);
// make a named expression and a produce
auto output = NEXPR("n", IDENT("n"));
@ -1622,8 +1636,9 @@ TEST(QueryPlan, ExpandBothCycleEdgeCase) {
SymbolTable symbol_table;
auto n = MakeScanAll(storage, symbol_table, "n");
auto r_ = MakeExpand(storage, symbol_table, n.op_, n.sym_, "r",
EdgeAtom::Direction::BOTH, {}, "_", false);
auto r_ =
MakeExpand(storage, symbol_table, n.op_, n.sym_, "r",
EdgeAtom::Direction::BOTH, {}, "_", false, GraphView::OLD);
EXPECT_EQ(1, PullAll(r_.op_, dba, symbol_table));
}
@ -1670,7 +1685,8 @@ TEST(QueryPlan, EdgeFilter) {
auto n = MakeScanAll(storage, symbol_table, "n");
const auto &edge_type = edge_types[0];
auto r_m = MakeExpand(storage, symbol_table, n.op_, n.sym_, "r",
EdgeAtom::Direction::OUT, {edge_type}, "m", false);
EdgeAtom::Direction::OUT, {edge_type}, "m", false,
GraphView::OLD);
r_m.edge_->edge_types_.push_back(edge_type);
r_m.edge_->properties_[prop] = LITERAL(42);
auto *filter_expr =
@ -1715,7 +1731,8 @@ TEST(QueryPlan, EdgeFilterMultipleTypes) {
// make a scan all
auto n = MakeScanAll(storage, symbol_table, "n");
auto r_m = MakeExpand(storage, symbol_table, n.op_, n.sym_, "r",
EdgeAtom::Direction::OUT, {type_1, type_2}, "m", false);
EdgeAtom::Direction::OUT, {type_1, type_2}, "m", false,
GraphView::OLD);
// make a named expression and a produce
auto output = NEXPR("m", IDENT("m"));
@ -1776,14 +1793,16 @@ TEST(QueryPlan, ExpandUniquenessFilter) {
SymbolTable symbol_table;
auto n1 = MakeScanAll(storage, symbol_table, "n1");
auto r1_n2 = MakeExpand(storage, symbol_table, n1.op_, n1.sym_, "r1",
EdgeAtom::Direction::OUT, {}, "n2", false);
auto r1_n2 =
MakeExpand(storage, symbol_table, n1.op_, n1.sym_, "r1",
EdgeAtom::Direction::OUT, {}, "n2", false, GraphView::OLD);
std::shared_ptr<LogicalOperator> last_op = r1_n2.op_;
if (vertex_uniqueness)
last_op = std::make_shared<ExpandUniquenessFilter<VertexAccessor>>(
last_op, r1_n2.node_sym_, std::vector<Symbol>{n1.sym_});
auto r2_n3 = MakeExpand(storage, symbol_table, last_op, r1_n2.node_sym_,
"r2", EdgeAtom::Direction::OUT, {}, "n3", false);
auto r2_n3 =
MakeExpand(storage, symbol_table, last_op, r1_n2.node_sym_, "r2",
EdgeAtom::Direction::OUT, {}, "n3", false, GraphView::OLD);
last_op = r2_n3.op_;
if (edge_uniqueness)
last_op = std::make_shared<ExpandUniquenessFilter<EdgeAccessor>>(