Migrate tests to storage v2 part 2

Reviewers: teon.banek

Reviewed By: teon.banek

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D2559
This commit is contained in:
Matej Ferencevic 2019-11-21 18:25:25 +01:00
parent 9cc10e131d
commit f61a8c3358
7 changed files with 592 additions and 567 deletions

View File

@ -52,7 +52,7 @@ add_unit_test(deferred_deleter.cpp)
target_link_libraries(${test_prefix}deferred_deleter mg-single-node kvstore_dummy_lib)
add_unit_test(bfs_single_node.cpp)
target_link_libraries(${test_prefix}bfs_single_node mg-single-node kvstore_dummy_lib)
target_link_libraries(${test_prefix}bfs_single_node mg-single-node-v2 mg-auth kvstore_dummy_lib)
add_unit_test(durability.cpp)
target_link_libraries(${test_prefix}durability mg-single-node kvstore_dummy_lib)
@ -127,10 +127,10 @@ add_unit_test(query_plan_accumulate_aggregate.cpp)
target_link_libraries(${test_prefix}query_plan_accumulate_aggregate mg-single-node kvstore_dummy_lib)
add_unit_test(query_plan_bag_semantics.cpp)
target_link_libraries(${test_prefix}query_plan_bag_semantics mg-single-node kvstore_dummy_lib)
target_link_libraries(${test_prefix}query_plan_bag_semantics mg-single-node-v2 mg-auth kvstore_dummy_lib)
add_unit_test(query_plan_create_set_remove_delete.cpp)
target_link_libraries(${test_prefix}query_plan_create_set_remove_delete mg-single-node kvstore_dummy_lib)
target_link_libraries(${test_prefix}query_plan_create_set_remove_delete mg-single-node-v2 mg-auth kvstore_dummy_lib)
# Storage V2 in query execution
add_unit_test(query_plan_v2_create_set_remove_delete.cpp)
@ -163,7 +163,7 @@ add_unit_test(query_semantic.cpp)
target_link_libraries(${test_prefix}query_semantic mg-single-node-v2 mg-auth kvstore_dummy_lib)
add_unit_test(query_variable_start_planner.cpp)
target_link_libraries(${test_prefix}query_variable_start_planner mg-single-node kvstore_dummy_lib)
target_link_libraries(${test_prefix}query_variable_start_planner mg-single-node-v2 mg-auth kvstore_dummy_lib)
add_unit_test(queue.cpp)
target_link_libraries(${test_prefix}queue mg-single-node kvstore_dummy_lib)

View File

@ -26,15 +26,6 @@ void PrintTo(const query::EdgeAtom::Direction &dir, std::ostream *os) {
}
} // namespace query
#ifdef MG_SINGLE_NODE
using VertexAddress = mvcc::VersionList<Vertex> *;
using EdgeAddress = mvcc::VersionList<Edge> *;
#endif
#ifdef MG_SINGLE_NODE_HA
using VertexAddress = mvcc::VersionList<Vertex> *;
using EdgeAddress = mvcc::VersionList<Edge> *;
#endif
const auto kVertexCount = 6;
// Maps vertices to workers
const std::vector<int> kVertexLocations = {0, 1, 1, 0, 2, 2};
@ -203,8 +194,7 @@ enum class FilterLambdaType { NONE, USE_FRAME, USE_FRAME_NULL, USE_CTX, ERROR };
// Common interface for single-node and distributed Memgraph.
class Database {
public:
virtual std::unique_ptr<database::GraphDbAccessor> Access() = 0;
virtual void AdvanceCommand(tx::TransactionId tx_id) = 0;
virtual storage::Storage::Accessor Access() = 0;
virtual std::unique_ptr<query::plan::LogicalOperator> MakeBfsOperator(
query::Symbol source_sym, query::Symbol sink_sym, query::Symbol edge_sym,
query::EdgeAtom::Direction direction,
@ -213,9 +203,9 @@ class Database {
bool existing_node, query::Expression *lower_bound,
query::Expression *upper_bound,
const query::plan::ExpansionLambda &filter_lambda) = 0;
virtual std::pair<std::vector<VertexAddress>, std::vector<EdgeAddress>>
BuildGraph(database::GraphDbAccessor *dba,
const std::vector<int> &vertex_locations,
virtual std::pair<std::vector<query::VertexAccessor>,
std::vector<query::EdgeAccessor>>
BuildGraph(query::DbAccessor *dba, const std::vector<int> &vertex_locations,
const std::vector<std::tuple<int, int, std::string>> &edges) = 0;
virtual ~Database() {}
@ -224,14 +214,14 @@ class Database {
// Returns an operator that yields vertices given by their address. We will also
// include query::TypedValue() to account for the optional match case.
std::unique_ptr<query::plan::LogicalOperator> YieldVertices(
database::GraphDbAccessor *dba, std::vector<VertexAddress> vertices,
query::DbAccessor *dba, std::vector<query::VertexAccessor> vertices,
query::Symbol symbol,
std::shared_ptr<query::plan::LogicalOperator> input_op) {
std::vector<std::vector<query::TypedValue>> frames;
frames.push_back(std::vector<query::TypedValue>{query::TypedValue()});
for (const auto &vertex : vertices) {
frames.emplace_back(std::vector<query::TypedValue>{query::TypedValue(
query::VertexAccessor(VertexAccessor(vertex, *dba)))});
frames.emplace_back(
std::vector<query::TypedValue>{query::TypedValue(vertex)});
}
return std::make_unique<Yield>(input_op, std::vector<query::Symbol>{symbol},
frames);
@ -239,42 +229,31 @@ std::unique_ptr<query::plan::LogicalOperator> YieldVertices(
// Returns an operator that yields edges and vertices given by their address.
std::unique_ptr<query::plan::LogicalOperator> YieldEntities(
database::GraphDbAccessor *dba, std::vector<VertexAddress> vertices,
std::vector<EdgeAddress> edges, query::Symbol symbol,
query::DbAccessor *dba, std::vector<query::VertexAccessor> vertices,
std::vector<query::EdgeAccessor> edges, query::Symbol symbol,
std::shared_ptr<query::plan::LogicalOperator> input_op) {
std::vector<std::vector<query::TypedValue>> frames;
for (const auto &vertex : vertices) {
frames.emplace_back(std::vector<query::TypedValue>{query::TypedValue(
query::VertexAccessor(VertexAccessor(vertex, *dba)))});
frames.emplace_back(
std::vector<query::TypedValue>{query::TypedValue(vertex)});
}
for (const auto &edge : edges) {
frames.emplace_back(std::vector<query::TypedValue>{
query::TypedValue(query::EdgeAccessor(EdgeAccessor(edge, *dba)))});
frames.emplace_back(
std::vector<query::TypedValue>{query::TypedValue(edge)});
}
return std::make_unique<Yield>(input_op, std::vector<query::Symbol>{symbol},
frames);
}
template <class TRecord>
auto GetProp(const RecordAccessor<TRecord> &rec, std::string prop,
database::GraphDbAccessor *dba) {
return rec.PropsAt(dba->Property(prop));
}
inline auto GetProp(const query::VertexAccessor &rec, std::string prop,
database::GraphDbAccessor *dba) {
return GetProp(rec.impl_, prop, dba);
}
inline auto GetProp(const query::EdgeAccessor &rec, std::string prop,
database::GraphDbAccessor *dba) {
return GetProp(rec.impl_, prop, dba);
auto GetProp(const TRecord &rec, std::string prop, query::DbAccessor *dba) {
return *rec.GetProperty(storage::View::OLD, dba->NameToProperty(prop));
}
// Checks if the given path is actually a path from source to sink and if all
// of its edges exist in the given edge list.
template <class TPathAllocator>
void CheckPath(database::GraphDbAccessor *dba, const query::VertexAccessor &source,
void CheckPath(query::DbAccessor *dba, const query::VertexAccessor &source,
const query::VertexAccessor &sink,
const std::vector<query::TypedValue, TPathAllocator> &path,
const std::vector<std::pair<int, int>> &edges) {
@ -298,8 +277,7 @@ void CheckPath(database::GraphDbAccessor *dba, const query::VertexAccessor &sour
// Given a list of BFS results of form (from, to, path, blocked entity),
// checks if all paths are valid and returns the distance matrix.
std::vector<std::vector<int>> CheckPathsAndExtractDistances(
database::GraphDbAccessor *dba,
const std::vector<std::pair<int, int>> edges,
query::DbAccessor *dba, const std::vector<std::pair<int, int>> edges,
const std::vector<std::vector<query::TypedValue>> &results) {
std::vector<std::vector<int>> distances(kVertexCount,
std::vector<int>(kVertexCount, -1));
@ -320,11 +298,10 @@ void BfsTest(Database *db, int lower_bound, int upper_bound,
query::EdgeAtom::Direction direction,
std::vector<std::string> edge_types, bool known_sink,
FilterLambdaType filter_lambda_type) {
auto dba_ptr = db->Access();
auto &dba = *dba_ptr;
auto storage_dba = db->Access();
query::DbAccessor dba(&storage_dba);
query::AstStorage storage;
query::DbAccessor execution_dba(&dba);
query::ExecutionContext context{&execution_dba};
query::ExecutionContext context{&dba};
query::Symbol blocked_sym =
context.symbol_table.CreateSymbol("blocked", true);
query::Symbol source_sym = context.symbol_table.CreateSymbol("source", true);
@ -338,13 +315,12 @@ void BfsTest(Database *db, int lower_bound, int upper_bound,
query::Identifier *inner_node = IDENT("inner_node")->MapTo(inner_node_sym);
query::Identifier *inner_edge = IDENT("inner_edge")->MapTo(inner_edge_sym);
std::vector<VertexAddress> vertices;
std::vector<EdgeAddress> edges;
std::vector<query::VertexAccessor> vertices;
std::vector<query::EdgeAccessor> edges;
std::tie(vertices, edges) =
db->BuildGraph(dba_ptr.get(), kVertexLocations, kEdges);
std::tie(vertices, edges) = db->BuildGraph(&dba, kVertexLocations, kEdges);
db->AdvanceCommand(dba_ptr->transaction_id());
dba.AdvanceCommand();
std::shared_ptr<query::plan::LogicalOperator> input_op;
@ -361,14 +337,12 @@ void BfsTest(Database *db, int lower_bound, int upper_bound,
break;
case FilterLambdaType::USE_FRAME:
// We block each entity in the graph and run BFS.
input_op =
YieldEntities(dba_ptr.get(), vertices, edges, blocked_sym, nullptr);
input_op = YieldEntities(&dba, vertices, edges, blocked_sym, nullptr);
filter_expr = AND(NEQ(inner_node, blocked), NEQ(inner_edge, blocked));
break;
case FilterLambdaType::USE_FRAME_NULL:
// We block each entity in the graph and run BFS.
input_op =
YieldEntities(dba_ptr.get(), vertices, edges, blocked_sym, nullptr);
input_op = YieldEntities(&dba, vertices, edges, blocked_sym, nullptr);
filter_expr = IF(AND(NEQ(inner_node, blocked), NEQ(inner_edge, blocked)),
LITERAL(true), LITERAL(PropertyValue()));
break;
@ -376,8 +350,8 @@ void BfsTest(Database *db, int lower_bound, int upper_bound,
// We only block vertex #5 and run BFS.
input_op = std::make_shared<Yield>(
nullptr, std::vector<query::Symbol>{blocked_sym},
std::vector<std::vector<query::TypedValue>>{{query::TypedValue(
query::VertexAccessor(VertexAccessor(vertices[5], *dba_ptr)))}});
std::vector<std::vector<query::TypedValue>>{
{query::TypedValue(vertices[5])}});
filter_expr = NEQ(PROPERTY_LOOKUP(inner_node, PROPERTY_PAIR("id")),
PARAMETER_LOOKUP(0));
context.evaluation_context.parameters.Add(0, PropertyValue(5));
@ -390,17 +364,17 @@ void BfsTest(Database *db, int lower_bound, int upper_bound,
}
// We run BFS once from each vertex for each blocked entity.
input_op = YieldVertices(dba_ptr.get(), vertices, source_sym, input_op);
input_op = YieldVertices(&dba, vertices, source_sym, input_op);
// If the sink is known, we run BFS for all posible combinations of source,
// sink and blocked entity.
if (known_sink) {
input_op = YieldVertices(dba_ptr.get(), vertices, sink_sym, input_op);
input_op = YieldVertices(&dba, vertices, sink_sym, input_op);
}
std::vector<storage::EdgeType> storage_edge_types;
for (const auto &t : edge_types) {
storage_edge_types.push_back(dba_ptr->EdgeType(t));
storage_edge_types.push_back(dba.NameToEdgeType(t));
}
input_op = db->MakeBfsOperator(
@ -411,9 +385,9 @@ void BfsTest(Database *db, int lower_bound, int upper_bound,
filter_expr});
context.evaluation_context.properties =
query::NamesToProperties(storage.properties_, &execution_dba);
query::NamesToProperties(storage.properties_, &dba);
context.evaluation_context.labels =
query::NamesToLabels(storage.labels_, &execution_dba);
query::NamesToLabels(storage.labels_, &dba);
std::vector<std::vector<query::TypedValue>> results;
// An exception should be thrown on one of the pulls.
@ -438,17 +412,14 @@ void BfsTest(Database *db, int lower_bound, int upper_bound,
query::TypedValue::BoolEqual{}(results[j][3], blocked))
++j;
SCOPED_TRACE(
fmt::format("blocked entity = {}", ToString(blocked, execution_dba)));
SCOPED_TRACE(fmt::format("blocked entity = {}", ToString(blocked, dba)));
// When an edge is blocked, it is blocked in both directions so we remove
// it before modifying edge list to account for direction and edge types;
auto edges = kEdges;
if (blocked.IsEdge()) {
int from =
GetProp(blocked.ValueEdge(), "from", dba_ptr.get()).ValueInt();
int to =
GetProp(blocked.ValueEdge(), "to", dba_ptr.get()).ValueInt();
int from = GetProp(blocked.ValueEdge(), "from", &dba).ValueInt();
int to = GetProp(blocked.ValueEdge(), "to", &dba).ValueInt();
edges.erase(std::remove_if(edges.begin(), edges.end(),
[from, to](const auto &e) {
return std::get<0>(e) == from &&
@ -462,8 +433,7 @@ void BfsTest(Database *db, int lower_bound, int upper_bound,
// When a vertex is blocked, we remove all edges that lead into it.
if (blocked.IsVertex()) {
int id =
GetProp(blocked.ValueVertex(), "id", dba_ptr.get()).ValueInt();
int id = GetProp(blocked.ValueVertex(), "id", &dba).ValueInt();
edges_blocked.erase(
std::remove_if(edges_blocked.begin(), edges_blocked.end(),
[id](const auto &e) { return e.second == id; }),
@ -494,7 +464,7 @@ void BfsTest(Database *db, int lower_bound, int upper_bound,
EXPECT_EQ(j - i, num_results);
auto distances = CheckPathsAndExtractDistances(
dba_ptr.get(), edges_blocked,
&dba, edges_blocked,
std::vector<std::vector<query::TypedValue>>(results.begin() + i,
results.begin() + j));
@ -504,5 +474,5 @@ void BfsTest(Database *db, int lower_bound, int upper_bound,
i = j;
}
dba_ptr->Abort();
dba.Abort();
}

View File

@ -7,16 +7,7 @@ class SingleNodeDb : public Database {
public:
SingleNodeDb() : db_() {}
std::unique_ptr<database::GraphDbAccessor> Access() override {
std::unique_ptr<database::GraphDbAccessor> dba =
std::make_unique<database::GraphDbAccessor>(db_.Access());
return dba;
}
void AdvanceCommand(tx::TransactionId tx_id) override {
auto dba = db_.Access(tx_id);
dba.AdvanceCommand();
}
storage::Storage::Accessor Access() override { return db_.Access(); }
std::unique_ptr<LogicalOperator> MakeBfsOperator(
Symbol source_sym, Symbol sink_sym, Symbol edge_sym,
@ -31,36 +22,42 @@ class SingleNodeDb : public Database {
filter_lambda, std::nullopt, std::nullopt);
}
std::pair<std::vector<VertexAddress>, std::vector<EdgeAddress>> BuildGraph(
database::GraphDbAccessor *dba, const std::vector<int> &vertex_locations,
std::pair<std::vector<query::VertexAccessor>,
std::vector<query::EdgeAccessor>>
BuildGraph(
query::DbAccessor *dba, const std::vector<int> &vertex_locations,
const std::vector<std::tuple<int, int, std::string>> &edges) override {
std::vector<VertexAddress> vertex_addr;
std::vector<EdgeAddress> edge_addr;
std::vector<query::VertexAccessor> vertex_addr;
std::vector<query::EdgeAccessor> edge_addr;
for (size_t id = 0; id < vertex_locations.size(); ++id) {
auto vertex = dba->InsertVertex();
vertex.PropsSet(dba->Property("id"),
PropertyValue(static_cast<int64_t>(id)));
vertex_addr.push_back(vertex.address());
CHECK(vertex
.SetProperty(dba->NameToProperty("id"),
PropertyValue(static_cast<int64_t>(id)))
.HasValue());
vertex_addr.push_back(vertex);
}
for (auto e : edges) {
int u, v;
std::string type;
std::tie(u, v, type) = e;
::VertexAccessor from(vertex_addr[u], *dba);
::VertexAccessor to(vertex_addr[v], *dba);
auto edge = dba->InsertEdge(from, to, dba->EdgeType(type));
edge.PropsSet(dba->Property("from"), PropertyValue(u));
edge.PropsSet(dba->Property("to"), PropertyValue(v));
edge_addr.push_back(edge.address());
auto &from = vertex_addr[u];
auto &to = vertex_addr[v];
auto edge = dba->InsertEdge(&from, &to, dba->NameToEdgeType(type));
CHECK(edge->SetProperty(dba->NameToProperty("from"), PropertyValue(u))
.HasValue());
CHECK(edge->SetProperty(dba->NameToProperty("to"), PropertyValue(v))
.HasValue());
edge_addr.push_back(*edge);
}
return std::make_pair(vertex_addr, edge_addr);
}
protected:
database::GraphDb db_;
storage::Storage db_;
};
class SingleNodeBfsTest

View File

@ -21,8 +21,9 @@ using namespace query;
using namespace query::plan;
TEST(QueryPlan, Skip) {
database::GraphDb db;
auto dba = db.Access();
storage::Storage db;
auto storage_dba = db.Access();
query::DbAccessor dba(&storage_dba);
AstStorage storage;
SymbolTable symbol_table;
@ -30,8 +31,7 @@ TEST(QueryPlan, Skip) {
auto n = MakeScanAll(storage, symbol_table, "n1");
auto skip = std::make_shared<plan::Skip>(n.op_, LITERAL(2));
query::DbAccessor execution_dba(&dba);
auto context = MakeContext(storage, symbol_table, &execution_dba);
auto context = MakeContext(storage, symbol_table, &dba);
EXPECT_EQ(0, PullAll(*skip, &context));
dba.InsertVertex();
@ -52,8 +52,9 @@ TEST(QueryPlan, Skip) {
}
TEST(QueryPlan, Limit) {
database::GraphDb db;
auto dba = db.Access();
storage::Storage db;
auto storage_dba = db.Access();
query::DbAccessor dba(&storage_dba);
AstStorage storage;
SymbolTable symbol_table;
@ -61,8 +62,7 @@ TEST(QueryPlan, Limit) {
auto n = MakeScanAll(storage, symbol_table, "n1");
auto skip = std::make_shared<plan::Limit>(n.op_, LITERAL(2));
query::DbAccessor execution_dba(&dba);
auto context = MakeContext(storage, symbol_table, &execution_dba);
auto context = MakeContext(storage, symbol_table, &dba);
EXPECT_EQ(0, PullAll(*skip, &context));
dba.InsertVertex();
@ -86,8 +86,9 @@ TEST(QueryPlan, CreateLimit) {
// CREATE (n), (m)
// MATCH (n) CREATE (m) LIMIT 1
// in the end we need to have 3 vertices in the db
database::GraphDb db;
auto dba = db.Access();
storage::Storage db;
auto storage_dba = db.Access();
query::DbAccessor dba(&storage_dba);
dba.InsertVertex();
dba.InsertVertex();
dba.AdvanceCommand();
@ -101,19 +102,19 @@ TEST(QueryPlan, CreateLimit) {
auto c = std::make_shared<CreateNode>(n.op_, m);
auto skip = std::make_shared<plan::Limit>(c, LITERAL(1));
query::DbAccessor execution_dba(&dba);
auto context = MakeContext(storage, symbol_table, &execution_dba);
auto context = MakeContext(storage, symbol_table, &dba);
EXPECT_EQ(1, PullAll(*skip, &context));
dba.AdvanceCommand();
EXPECT_EQ(3, CountIterable(dba.Vertices(false)));
EXPECT_EQ(3, CountIterable(dba.Vertices(storage::View::OLD)));
}
TEST(QueryPlan, OrderBy) {
database::GraphDb db;
auto dba = db.Access();
storage::Storage db;
auto storage_dba = db.Access();
query::DbAccessor dba(&storage_dba);
AstStorage storage;
SymbolTable symbol_table;
auto prop = dba.Property("prop");
auto prop = dba.NameToProperty("prop");
// contains a series of tests
// each test defines the ordering a vector of values in the desired order
@ -142,9 +143,10 @@ TEST(QueryPlan, OrderBy) {
values.reserve(order_value_pair.second.size());
for (const auto &v : order_value_pair.second) values.emplace_back(v);
// empty database
for (auto &vertex : dba.Vertices(false)) dba.DetachRemoveVertex(vertex);
for (auto vertex : dba.Vertices(storage::View::OLD))
dba.DetachRemoveVertex(&vertex);
dba.AdvanceCommand();
ASSERT_EQ(0, CountIterable(dba.Vertices(false)));
ASSERT_EQ(0, CountIterable(dba.Vertices(storage::View::OLD)));
// take some effort to shuffle the values
// because we are testing that something not ordered gets ordered
@ -161,7 +163,9 @@ TEST(QueryPlan, OrderBy) {
// create the vertices
for (const auto &value : shuffled)
dba.InsertVertex().PropsSet(prop, PropertyValue(value));
ASSERT_TRUE(dba.InsertVertex()
.SetProperty(prop, PropertyValue(value))
.HasValue());
dba.AdvanceCommand();
// order by and collect results
@ -173,8 +177,7 @@ TEST(QueryPlan, OrderBy) {
auto n_p_ne =
NEXPR("n.p", n_p)->MapTo(symbol_table.CreateSymbol("n.p", true));
auto produce = MakeProduce(order_by, n_p_ne);
query::DbAccessor execution_dba(&dba);
auto context = MakeContext(storage, symbol_table, &execution_dba);
auto context = MakeContext(storage, symbol_table, &dba);
auto results = CollectProduce(*produce, &context);
ASSERT_EQ(values.size(), results.size());
for (int j = 0; j < results.size(); ++j)
@ -183,13 +186,14 @@ TEST(QueryPlan, OrderBy) {
}
TEST(QueryPlan, OrderByMultiple) {
database::GraphDb db;
auto dba = db.Access();
storage::Storage db;
auto storage_dba = db.Access();
query::DbAccessor dba(&storage_dba);
AstStorage storage;
SymbolTable symbol_table;
auto p1 = dba.Property("p1");
auto p2 = dba.Property("p2");
auto p1 = dba.NameToProperty("p1");
auto p2 = dba.NameToProperty("p2");
// create a bunch of vertices that in two properties
// have all the variations (with repetition) of N values.
@ -201,8 +205,8 @@ TEST(QueryPlan, OrderByMultiple) {
std::random_shuffle(prop_values.begin(), prop_values.end());
for (const auto &pair : prop_values) {
auto v = dba.InsertVertex();
v.PropsSet(p1, PropertyValue(pair.first));
v.PropsSet(p2, PropertyValue(pair.second));
ASSERT_TRUE(v.SetProperty(p1, PropertyValue(pair.first)).HasValue());
ASSERT_TRUE(v.SetProperty(p2, PropertyValue(pair.second)).HasValue());
}
dba.AdvanceCommand();
@ -226,8 +230,7 @@ TEST(QueryPlan, OrderByMultiple) {
auto n_p2_ne =
NEXPR("n.p2", n_p2)->MapTo(symbol_table.CreateSymbol("n.p2", true));
auto produce = MakeProduce(order_by, n_p1_ne, n_p2_ne);
query::DbAccessor execution_dba(&dba);
auto context = MakeContext(storage, symbol_table, &execution_dba);
auto context = MakeContext(storage, symbol_table, &dba);
auto results = CollectProduce(*produce, &context);
ASSERT_EQ(N * N, results.size());
for (int j = 0; j < N * N; ++j) {
@ -239,11 +242,12 @@ TEST(QueryPlan, OrderByMultiple) {
}
TEST(QueryPlan, OrderByExceptions) {
database::GraphDb db;
auto dba = db.Access();
storage::Storage db;
auto storage_dba = db.Access();
query::DbAccessor dba(&storage_dba);
AstStorage storage;
SymbolTable symbol_table;
auto prop = dba.Property("prop");
auto prop = dba.NameToProperty("prop");
// a vector of pairs of typed values that should result
// in an exception when trying to order on them
@ -263,17 +267,19 @@ TEST(QueryPlan, OrderByExceptions) {
for (const auto &pair : exception_pairs) {
// empty database
for (auto &vertex : dba.Vertices(false)) dba.DetachRemoveVertex(vertex);
for (auto vertex : dba.Vertices(storage::View::OLD))
dba.DetachRemoveVertex(&vertex);
dba.AdvanceCommand();
ASSERT_EQ(0, CountIterable(dba.Vertices(false)));
ASSERT_EQ(0, CountIterable(dba.Vertices(storage::View::OLD)));
// make two vertices, and set values
dba.InsertVertex().PropsSet(prop, pair.first);
dba.InsertVertex().PropsSet(prop, pair.second);
ASSERT_TRUE(dba.InsertVertex().SetProperty(prop, pair.first).HasValue());
ASSERT_TRUE(dba.InsertVertex().SetProperty(prop, pair.second).HasValue());
dba.AdvanceCommand();
ASSERT_EQ(2, CountIterable(dba.Vertices(false)));
for (const auto &va : dba.Vertices(false))
ASSERT_NE(va.PropsAt(prop).type(), PropertyValue::Type::Null);
ASSERT_EQ(2, CountIterable(dba.Vertices(storage::View::OLD)));
for (const auto &va : dba.Vertices(storage::View::OLD))
ASSERT_NE(va.GetProperty(storage::View::OLD, prop).GetValue().type(),
PropertyValue::Type::Null);
// order by and expect an exception
auto n = MakeScanAll(storage, symbol_table, "n");
@ -281,8 +287,7 @@ TEST(QueryPlan, OrderByExceptions) {
auto order_by = std::make_shared<plan::OrderBy>(
n.op_, std::vector<SortItem>{{Ordering::ASC, n_p}},
std::vector<Symbol>{});
query::DbAccessor execution_dba(&dba);
auto context = MakeContext(storage, symbol_table, &execution_dba);
auto context = MakeContext(storage, symbol_table, &dba);
EXPECT_THROW(PullAll(*order_by, &context), QueryRuntimeException);
}
}

View File

@ -10,6 +10,12 @@
#include "query/interpret/frame.hpp"
#include "query/plan/operator.hpp"
// TODO (mferencevic): Remove once all cpp tests are migrated to v2.
#ifdef MG_SINGLE_NODE_V2
#include "query/db_accessor.hpp"
#include "storage/v2/storage.hpp"
#endif
#include "query_common.hpp"
using namespace query;
@ -196,7 +202,28 @@ UnwindTuple MakeUnwind(SymbolTable &symbol_table,
return UnwindTuple{sym, op};
}
#ifdef MG_SINGLE_NODE_V2
template <typename TIterable>
auto CountIterable(TIterable &&iterable) {
uint64_t count = 0;
for (auto it = iterable.begin(); it != iterable.end(); ++it) {
++count;
}
return count;
}
inline uint64_t CountEdges(query::DbAccessor *dba, storage::View view) {
uint64_t count = 0;
for (auto vertex : dba->Vertices(view)) {
auto maybe_edges = vertex.OutEdges(view);
CHECK(maybe_edges.HasValue());
count += CountIterable(*maybe_edges);
}
return count;
}
#else
template <typename TIterable>
auto CountIterable(TIterable iterable) {
return std::distance(iterable.begin(), iterable.end());
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -86,12 +86,13 @@ void CheckPlansProduce(
}
TEST(TestVariableStartPlanner, MatchReturn) {
database::GraphDb db;
auto dba = db.Access();
storage::Storage db;
auto storage_dba = db.Access();
query::DbAccessor dba(&storage_dba);
// Make a graph (v1) -[:r]-> (v2)
auto v1 = dba.InsertVertex();
auto v2 = dba.InsertVertex();
dba.InsertEdge(v1, v2, dba.EdgeType("r"));
ASSERT_TRUE(dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("r")).HasValue());
dba.AdvanceCommand();
// Test MATCH (n) -[r]-> (m) RETURN n
AstStorage storage;
@ -99,24 +100,22 @@ TEST(TestVariableStartPlanner, MatchReturn) {
MATCH(PATTERN(NODE("n"), EDGE("r", Direction::OUT), NODE("m"))),
RETURN("n")));
// We have 2 nodes `n` and `m` from which we could start, so expect 2 plans.
query::DbAccessor execution_dba(&dba);
CheckPlansProduce(
2, query, storage, &execution_dba, [&](const auto &results) {
// We expect to produce only a single (v1) node.
AssertRows(results, {{TypedValue(query::VertexAccessor(v1))}},
execution_dba);
});
CheckPlansProduce(2, query, storage, &dba, [&](const auto &results) {
// We expect to produce only a single (v1) node.
AssertRows(results, {{TypedValue(query::VertexAccessor(v1))}}, dba);
});
}
TEST(TestVariableStartPlanner, MatchTripletPatternReturn) {
database::GraphDb db;
auto dba = db.Access();
storage::Storage db;
auto storage_dba = db.Access();
query::DbAccessor dba(&storage_dba);
// Make a graph (v1) -[:r]-> (v2) -[:r]-> (v3)
auto v1 = dba.InsertVertex();
auto v2 = dba.InsertVertex();
auto v3 = dba.InsertVertex();
dba.InsertEdge(v1, v2, dba.EdgeType("r"));
dba.InsertEdge(v2, v3, dba.EdgeType("r"));
ASSERT_TRUE(dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("r")).HasValue());
ASSERT_TRUE(dba.InsertEdge(&v2, &v3, dba.NameToEdgeType("r")).HasValue());
dba.AdvanceCommand();
{
// Test `MATCH (n) -[r]-> (m) -[e]-> (l) RETURN n`
@ -126,13 +125,10 @@ TEST(TestVariableStartPlanner, MatchTripletPatternReturn) {
EDGE("e", Direction::OUT), NODE("l"))),
RETURN("n")));
// We have 3 nodes: `n`, `m` and `l` from which we could start.
query::DbAccessor execution_dba(&dba);
CheckPlansProduce(
3, query, storage, &execution_dba, [&](const auto &results) {
// We expect to produce only a single (v1) node.
AssertRows(results, {{TypedValue(query::VertexAccessor(v1))}},
execution_dba);
});
CheckPlansProduce(3, query, storage, &dba, [&](const auto &results) {
// We expect to produce only a single (v1) node.
AssertRows(results, {{TypedValue(query::VertexAccessor(v1))}}, dba);
});
}
{
// Equivalent to `MATCH (n) -[r]-> (m), (m) -[e]-> (l) RETURN n`.
@ -141,24 +137,22 @@ TEST(TestVariableStartPlanner, MatchTripletPatternReturn) {
MATCH(PATTERN(NODE("n"), EDGE("r", Direction::OUT), NODE("m")),
PATTERN(NODE("m"), EDGE("e", Direction::OUT), NODE("l"))),
RETURN("n")));
query::DbAccessor execution_dba(&dba);
CheckPlansProduce(
3, query, storage, &execution_dba, [&](const auto &results) {
AssertRows(results, {{TypedValue(query::VertexAccessor(v1))}},
execution_dba);
});
CheckPlansProduce(3, query, storage, &dba, [&](const auto &results) {
AssertRows(results, {{TypedValue(query::VertexAccessor(v1))}}, dba);
});
}
}
TEST(TestVariableStartPlanner, MatchOptionalMatchReturn) {
database::GraphDb db;
auto dba = db.Access();
storage::Storage db;
auto storage_dba = db.Access();
query::DbAccessor dba(&storage_dba);
// Make a graph (v1) -[:r]-> (v2) -[:r]-> (v3)
auto v1 = dba.InsertVertex();
auto v2 = dba.InsertVertex();
auto v3 = dba.InsertVertex();
dba.InsertEdge(v1, v2, dba.EdgeType("r"));
dba.InsertEdge(v2, v3, dba.EdgeType("r"));
ASSERT_TRUE(dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("r")).HasValue());
ASSERT_TRUE(dba.InsertEdge(&v2, &v3, dba.NameToEdgeType("r")).HasValue());
dba.AdvanceCommand();
// Test MATCH (n) -[r]-> (m) OPTIONAL MATCH (m) -[e]-> (l) RETURN n, l
AstStorage storage;
@ -168,29 +162,28 @@ TEST(TestVariableStartPlanner, MatchOptionalMatchReturn) {
RETURN("n", "l")));
// We have 2 nodes `n` and `m` from which we could start the MATCH, and 2
// nodes for OPTIONAL MATCH. This should produce 2 * 2 plans.
query::DbAccessor execution_dba(&dba);
CheckPlansProduce(
4, query, storage, &execution_dba, [&](const auto &results) {
// We expect to produce 2 rows:
// * (v1), (v3)
// * (v2), null
AssertRows(results,
{{TypedValue(query::VertexAccessor(v1)),
TypedValue(query::VertexAccessor(v3))},
{TypedValue(query::VertexAccessor(v2)), TypedValue()}},
execution_dba);
});
CheckPlansProduce(4, query, storage, &dba, [&](const auto &results) {
// We expect to produce 2 rows:
// * (v1), (v3)
// * (v2), null
AssertRows(results,
{{TypedValue(query::VertexAccessor(v1)),
TypedValue(query::VertexAccessor(v3))},
{TypedValue(query::VertexAccessor(v2)), TypedValue()}},
dba);
});
}
TEST(TestVariableStartPlanner, MatchOptionalMatchMergeReturn) {
database::GraphDb db;
auto dba = db.Access();
storage::Storage db;
auto storage_dba = db.Access();
query::DbAccessor dba(&storage_dba);
// Graph (v1) -[:r]-> (v2)
query::VertexAccessor v1(dba.InsertVertex());
query::VertexAccessor v2(dba.InsertVertex());
auto r_type_name = "r";
auto r_type = dba.EdgeType(r_type_name);
dba.InsertEdge(v1.impl_, v2.impl_, r_type);
auto r_type = dba.NameToEdgeType(r_type_name);
ASSERT_TRUE(dba.InsertEdge(&v1, &v2, r_type).HasValue());
dba.AdvanceCommand();
// Test MATCH (n) -[r]-> (m) OPTIONAL MATCH (m) -[e]-> (l)
// MERGE (u) -[q:r]-> (v) RETURN n, m, l, u, v
@ -203,24 +196,23 @@ TEST(TestVariableStartPlanner, MatchOptionalMatchMergeReturn) {
RETURN("n", "m", "l", "u", "v")));
// Since MATCH, OPTIONAL MATCH and MERGE each have 2 nodes from which we can
// start, we generate 2 * 2 * 2 plans.
query::DbAccessor execution_dba(&dba);
CheckPlansProduce(8, query, storage, &execution_dba,
[&](const auto &results) {
// We expect to produce a single row: (v1), (v2), null, (v1), (v2)
AssertRows(results,
{{TypedValue(v1), TypedValue(v2), TypedValue(),
TypedValue(v1), TypedValue(v2)}},
execution_dba);
});
CheckPlansProduce(8, query, storage, &dba, [&](const auto &results) {
// We expect to produce a single row: (v1), (v2), null, (v1), (v2)
AssertRows(results,
{{TypedValue(v1), TypedValue(v2), TypedValue(), TypedValue(v1),
TypedValue(v2)}},
dba);
});
}
TEST(TestVariableStartPlanner, MatchWithMatchReturn) {
database::GraphDb db;
auto dba = db.Access();
storage::Storage db;
auto storage_dba = db.Access();
query::DbAccessor dba(&storage_dba);
// Graph (v1) -[:r]-> (v2)
query::VertexAccessor v1(dba.InsertVertex());
query::VertexAccessor v2(dba.InsertVertex());
dba.InsertEdge(v1.impl_, v2.impl_, dba.EdgeType("r"));
ASSERT_TRUE(dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("r")).HasValue());
dba.AdvanceCommand();
// Test MATCH (n) -[r]-> (m) WITH n MATCH (m) -[r]-> (l) RETURN n, m, l
AstStorage storage;
@ -231,24 +223,23 @@ TEST(TestVariableStartPlanner, MatchWithMatchReturn) {
RETURN("n", "m", "l")));
// We can start from 2 nodes in each match. Since WITH separates query parts,
// we expect to get 2 plans for each, which totals 2 * 2.
query::DbAccessor execution_dba(&dba);
CheckPlansProduce(
4, query, storage, &execution_dba, [&](const auto &results) {
// We expect to produce a single row: (v1), (v1), (v2)
AssertRows(results, {{TypedValue(v1), TypedValue(v1), TypedValue(v2)}},
execution_dba);
});
CheckPlansProduce(4, query, storage, &dba, [&](const auto &results) {
// We expect to produce a single row: (v1), (v1), (v2)
AssertRows(results, {{TypedValue(v1), TypedValue(v1), TypedValue(v2)}},
dba);
});
}
TEST(TestVariableStartPlanner, MatchVariableExpand) {
database::GraphDb db;
auto dba = db.Access();
storage::Storage db;
auto storage_dba = db.Access();
query::DbAccessor dba(&storage_dba);
// Graph (v1) -[:r1]-> (v2) -[:r2]-> (v3)
auto v1 = dba.InsertVertex();
auto v2 = dba.InsertVertex();
auto v3 = dba.InsertVertex();
query::EdgeAccessor r1(dba.InsertEdge(v1, v2, dba.EdgeType("r1")));
query::EdgeAccessor r2(dba.InsertEdge(v2, v3, dba.EdgeType("r2")));
auto r1 = *dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("r1"));
auto r2 = *dba.InsertEdge(&v2, &v3, dba.NameToEdgeType("r2"));
dba.AdvanceCommand();
// Test MATCH (n) -[r*]-> (m) RETURN r
AstStorage storage;
@ -261,27 +252,25 @@ TEST(TestVariableStartPlanner, MatchVariableExpand) {
// [r1, r2]
TypedValue r1_r2_list(
std::vector<TypedValue>{TypedValue(r1), TypedValue(r2)});
query::DbAccessor execution_dba(&dba);
CheckPlansProduce(2, query, storage, &execution_dba,
[&](const auto &results) {
AssertRows(results, {{r1_list}, {r2_list}, {r1_r2_list}},
execution_dba);
});
CheckPlansProduce(2, query, storage, &dba, [&](const auto &results) {
AssertRows(results, {{r1_list}, {r2_list}, {r1_r2_list}}, dba);
});
}
TEST(TestVariableStartPlanner, MatchVariableExpandReferenceNode) {
database::GraphDb db;
auto dba = db.Access();
auto id = dba.Property("id");
storage::Storage db;
auto storage_dba = db.Access();
query::DbAccessor dba(&storage_dba);
auto id = dba.NameToProperty("id");
// Graph (v1 {id:1}) -[:r1]-> (v2 {id: 2}) -[:r2]-> (v3 {id: 3})
auto v1 = dba.InsertVertex();
v1.PropsSet(id, PropertyValue(1));
ASSERT_TRUE(v1.SetProperty(id, PropertyValue(1)).HasValue());
auto v2 = dba.InsertVertex();
v2.PropsSet(id, PropertyValue(2));
ASSERT_TRUE(v2.SetProperty(id, PropertyValue(2)).HasValue());
auto v3 = dba.InsertVertex();
v3.PropsSet(id, PropertyValue(3));
query::EdgeAccessor r1(dba.InsertEdge(v1, v2, dba.EdgeType("r1")));
query::EdgeAccessor r2(dba.InsertEdge(v2, v3, dba.EdgeType("r2")));
ASSERT_TRUE(v3.SetProperty(id, PropertyValue(3)).HasValue());
auto r1 = *dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("r1"));
auto r2 = *dba.InsertEdge(&v2, &v3, dba.NameToEdgeType("r2"));
dba.AdvanceCommand();
// Test MATCH (n) -[r*..n.id]-> (m) RETURN r
AstStorage storage;
@ -294,24 +283,23 @@ TEST(TestVariableStartPlanner, MatchVariableExpandReferenceNode) {
TypedValue r1_list(std::vector<TypedValue>{TypedValue(r1)});
// [r2] (v2 -[*..2]-> v3)
TypedValue r2_list(std::vector<TypedValue>{TypedValue(r2)});
query::DbAccessor execution_dba(&dba);
CheckPlansProduce(
2, query, storage, &execution_dba, [&](const auto &results) {
AssertRows(results, {{r1_list}, {r2_list}}, execution_dba);
});
CheckPlansProduce(2, query, storage, &dba, [&](const auto &results) {
AssertRows(results, {{r1_list}, {r2_list}}, dba);
});
}
TEST(TestVariableStartPlanner, MatchVariableExpandBoth) {
database::GraphDb db;
auto dba = db.Access();
auto id = dba.Property("id");
storage::Storage db;
auto storage_dba = db.Access();
query::DbAccessor dba(&storage_dba);
auto id = dba.NameToProperty("id");
// Graph (v1 {id:1}) -[:r1]-> (v2) -[:r2]-> (v3)
auto v1 = dba.InsertVertex();
v1.PropsSet(id, PropertyValue(1));
ASSERT_TRUE(v1.SetProperty(id, PropertyValue(1)).HasValue());
auto v2 = dba.InsertVertex();
auto v3 = dba.InsertVertex();
query::EdgeAccessor r1(dba.InsertEdge(v1, v2, dba.EdgeType("r1")));
query::EdgeAccessor r2(dba.InsertEdge(v2, v3, dba.EdgeType("r2")));
auto r1 = *dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("r1"));
auto r2 = *dba.InsertEdge(&v2, &v3, dba.NameToEdgeType("r2"));
dba.AdvanceCommand();
// Test MATCH (n {id:1}) -[r*]- (m) RETURN r
AstStorage storage;
@ -325,26 +313,25 @@ TEST(TestVariableStartPlanner, MatchVariableExpandBoth) {
// [r1, r2]
TypedValue r1_r2_list(
std::vector<TypedValue>{TypedValue(r1), TypedValue(r2)});
query::DbAccessor execution_dba(&dba);
CheckPlansProduce(
2, query, storage, &execution_dba, [&](const auto &results) {
AssertRows(results, {{r1_list}, {r1_r2_list}}, execution_dba);
});
CheckPlansProduce(2, query, storage, &dba, [&](const auto &results) {
AssertRows(results, {{r1_list}, {r1_r2_list}}, dba);
});
}
TEST(TestVariableStartPlanner, MatchBfs) {
database::GraphDb db;
auto dba = db.Access();
auto id = dba.Property("id");
storage::Storage db;
auto storage_dba = db.Access();
query::DbAccessor dba(&storage_dba);
auto id = dba.NameToProperty("id");
// Graph (v1 {id:1}) -[:r1]-> (v2 {id: 2}) -[:r2]-> (v3 {id: 3})
auto v1 = dba.InsertVertex();
v1.PropsSet(id, PropertyValue(1));
ASSERT_TRUE(v1.SetProperty(id, PropertyValue(1)).HasValue());
auto v2 = dba.InsertVertex();
v2.PropsSet(id, PropertyValue(2));
ASSERT_TRUE(v2.SetProperty(id, PropertyValue(2)).HasValue());
auto v3 = dba.InsertVertex();
v3.PropsSet(id, PropertyValue(3));
query::EdgeAccessor r1(dba.InsertEdge(v1, v2, dba.EdgeType("r1")));
dba.InsertEdge(v2, v3, dba.EdgeType("r2"));
ASSERT_TRUE(v3.SetProperty(id, PropertyValue(3)).HasValue());
auto r1 = *dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("r1"));
ASSERT_TRUE(dba.InsertEdge(&v2, &v3, dba.NameToEdgeType("r2")).HasValue());
dba.AdvanceCommand();
// Test MATCH (n) -[r *bfs..10](r, n | n.id <> 3)]-> (m) RETURN r
AstStorage storage;
@ -359,11 +346,9 @@ TEST(TestVariableStartPlanner, MatchBfs) {
SINGLE_QUERY(MATCH(PATTERN(NODE("n"), bfs, NODE("m"))), RETURN("r")));
// We expect to get a single column with the following rows:
TypedValue r1_list(std::vector<TypedValue>{TypedValue(r1)}); // [r1]
query::DbAccessor execution_dba(&dba);
CheckPlansProduce(2, query, storage, &execution_dba,
[&](const auto &results) {
AssertRows(results, {{r1_list}}, execution_dba);
});
CheckPlansProduce(2, query, storage, &dba, [&](const auto &results) {
AssertRows(results, {{r1_list}}, dba);
});
}
} // namespace