Add missing license
This commit is contained in:
parent
a65ea4fe01
commit
22e3164e60
@ -93,6 +93,9 @@ target_link_libraries(${test_prefix}query_expression_evaluator mg-query)
|
||||
add_unit_test(query_plan.cpp)
|
||||
target_link_libraries(${test_prefix}query_plan mg-query)
|
||||
|
||||
add_unit_test(query_plan_v2.cpp)
|
||||
target_link_libraries(${test_prefix}query_plan_v2 mg-query-v2)
|
||||
|
||||
add_unit_test(query_plan_accumulate_aggregate.cpp)
|
||||
target_link_libraries(${test_prefix}query_plan_accumulate_aggregate mg-query)
|
||||
|
||||
|
@ -46,6 +46,8 @@
|
||||
#include "storage/v2/id_types.hpp"
|
||||
#include "utils/string.hpp"
|
||||
|
||||
#include "query/v2/frontend/ast/ast.hpp"
|
||||
|
||||
namespace memgraph::query {
|
||||
|
||||
namespace test_common {
|
||||
@ -81,12 +83,39 @@ std::string ToString(NamedExpression *expr) {
|
||||
struct OrderBy {
|
||||
std::vector<SortItem> expressions;
|
||||
};
|
||||
|
||||
// new stuff begin
|
||||
|
||||
struct OrderByv2 {
|
||||
std::vector<query::v2::SortItem> expressions;
|
||||
};
|
||||
|
||||
// new stuff end
|
||||
|
||||
struct Skip {
|
||||
Expression *expression = nullptr;
|
||||
};
|
||||
|
||||
// new stuff begin
|
||||
|
||||
struct Skipv2 {
|
||||
query::v2::Expression *expression = nullptr;
|
||||
};
|
||||
|
||||
// new stuff end
|
||||
|
||||
struct Limit {
|
||||
Expression *expression = nullptr;
|
||||
};
|
||||
|
||||
// new stuff begin
|
||||
|
||||
struct Limitv2 {
|
||||
query::v2::Expression *expression = nullptr;
|
||||
};
|
||||
|
||||
// new stuff end
|
||||
|
||||
struct OnMatch {
|
||||
std::vector<Clause *> set;
|
||||
};
|
||||
@ -153,6 +182,42 @@ auto GetPropertyLookup(AstStorage &storage, TDbAccessor &, Expression *expr,
|
||||
return storage.Create<PropertyLookup>(expr, storage.GetPropertyIx(prop_pair.first));
|
||||
}
|
||||
|
||||
// new stuff begin
|
||||
|
||||
template <class TDbAccessor>
|
||||
auto GetPropertyLookup(memgraph::query::v2::AstStorage &storage, TDbAccessor &dba, const std::string &name,
|
||||
memgraph::storage::v3::PropertyId property) {
|
||||
return storage.Create<query::v2::PropertyLookup>(storage.Create<query::v2::Identifier>(name),
|
||||
storage.GetPropertyIx(dba.PropertyToName(property)));
|
||||
}
|
||||
|
||||
template <class TDbAccessor>
|
||||
auto GetPropertyLookup(memgraph::query::v2::AstStorage &storage, TDbAccessor &dba,
|
||||
memgraph::query::v2::Expression *expr, memgraph::storage::v3::PropertyId property) {
|
||||
return storage.Create<query::v2::PropertyLookup>(expr, storage.GetPropertyIx(dba.PropertyToName(property)));
|
||||
}
|
||||
|
||||
template <class TDbAccessor>
|
||||
auto GetPropertyLookup(memgraph::query::v2::AstStorage &storage, TDbAccessor &dba,
|
||||
memgraph::query::v2::Expression *expr, const std::string &property) {
|
||||
return storage.Create<query::v2::PropertyLookup>(expr, storage.GetPropertyIx(property));
|
||||
}
|
||||
|
||||
template <class TDbAccessor>
|
||||
auto GetPropertyLookup(memgraph::query::v2::AstStorage &storage, TDbAccessor &, const std::string &name,
|
||||
const std::pair<std::string, memgraph::storage::v3::PropertyId> &prop_pair) {
|
||||
return storage.Create<query::v2::PropertyLookup>(storage.Create<query::v2::Identifier>(name),
|
||||
storage.GetPropertyIx(prop_pair.first));
|
||||
}
|
||||
|
||||
template <class TDbAccessor>
|
||||
auto GetPropertyLookup(memgraph::query::v2::AstStorage &storage, TDbAccessor &, memgraph::query::v2::Expression *expr,
|
||||
const std::pair<std::string, memgraph::storage::v3::PropertyId> &prop_pair) {
|
||||
return storage.Create<query::v2::PropertyLookup>(expr, storage.GetPropertyIx(prop_pair.first));
|
||||
}
|
||||
|
||||
// new stuff end
|
||||
|
||||
/// Create an EdgeAtom with given name, direction and edge_type.
|
||||
///
|
||||
/// Name is used to create the Identifier which is assigned to the edge.
|
||||
@ -211,6 +276,15 @@ auto GetNode(AstStorage &storage, const std::string &name, std::optional<std::st
|
||||
return node;
|
||||
}
|
||||
|
||||
// new stuff begin
|
||||
auto GetNode(memgraph::query::v2::AstStorage &storage, const std::string &name,
|
||||
std::optional<std::string> label = std::nullopt) {
|
||||
auto node = storage.Create<query::v2::NodeAtom>(storage.Create<query::v2::Identifier>(name));
|
||||
if (label) node->labels_.emplace_back(storage.GetLabelIx(*label));
|
||||
return node;
|
||||
}
|
||||
// new stuff end
|
||||
|
||||
/// Create a Pattern with given atoms.
|
||||
auto GetPattern(AstStorage &storage, std::vector<PatternAtom *> atoms) {
|
||||
auto pattern = storage.Create<Pattern>();
|
||||
@ -227,6 +301,26 @@ auto GetPattern(AstStorage &storage, const std::string &name, std::vector<Patter
|
||||
return pattern;
|
||||
}
|
||||
|
||||
// new stuff begin
|
||||
|
||||
auto GetPattern(memgraph::query::v2::AstStorage &storage, std::vector<query::v2::PatternAtom *> atoms) {
|
||||
auto pattern = storage.Create<query::v2::Pattern>();
|
||||
pattern->identifier_ = storage.Create<query::v2::Identifier>(memgraph::utils::RandomString(20), false);
|
||||
pattern->atoms_.insert(pattern->atoms_.begin(), atoms.begin(), atoms.end());
|
||||
return pattern;
|
||||
}
|
||||
|
||||
/// Create a Pattern with given name and atoms.
|
||||
auto GetPattern(memgraph::query::v2::AstStorage &storage, const std::string &name,
|
||||
std::vector<query::v2::PatternAtom *> atoms) {
|
||||
auto pattern = storage.Create<query::v2::Pattern>();
|
||||
pattern->identifier_ = storage.Create<query::v2::Identifier>(name, true);
|
||||
pattern->atoms_.insert(pattern->atoms_.begin(), atoms.begin(), atoms.end());
|
||||
return pattern;
|
||||
}
|
||||
|
||||
// new stuff end
|
||||
|
||||
/// This function fills an AST node which with given patterns.
|
||||
///
|
||||
/// The function is most commonly used to create Match and Create clauses.
|
||||
@ -236,6 +330,16 @@ auto GetWithPatterns(TWithPatterns *with_patterns, std::vector<Pattern *> patter
|
||||
return with_patterns;
|
||||
}
|
||||
|
||||
// new stuff begin
|
||||
|
||||
template <class TWithPatterns>
|
||||
auto GetWithPatterns(TWithPatterns *with_patterns, std::vector<query::v2::Pattern *> patterns) {
|
||||
with_patterns->patterns_.insert(with_patterns->patterns_.begin(), patterns.begin(), patterns.end());
|
||||
return with_patterns;
|
||||
}
|
||||
|
||||
// new stuff end
|
||||
|
||||
/// Create a query with given clauses.
|
||||
|
||||
auto GetSingleQuery(SingleQuery *single_query, Clause *clause) {
|
||||
@ -271,6 +375,45 @@ auto GetSingleQuery(SingleQuery *single_query, Clause *clause, T *...clauses) {
|
||||
return GetSingleQuery(single_query, clauses...);
|
||||
}
|
||||
|
||||
// new stuff begin
|
||||
|
||||
auto GetSingleQuery(query::v2::SingleQuery *single_query, query::v2::Clause *clause) {
|
||||
single_query->clauses_.emplace_back(clause);
|
||||
return single_query;
|
||||
}
|
||||
auto GetSingleQuery(query::v2::SingleQuery *single_query, query::v2::Match *match, query::v2::Where *where) {
|
||||
match->where_ = where;
|
||||
single_query->clauses_.emplace_back(match);
|
||||
return single_query;
|
||||
}
|
||||
auto GetSingleQuery(query::v2::SingleQuery *single_query, query::v2::With *with, query::v2::Where *where) {
|
||||
with->where_ = where;
|
||||
single_query->clauses_.emplace_back(with);
|
||||
return single_query;
|
||||
}
|
||||
template <class... T>
|
||||
auto GetSingleQuery(query::v2::SingleQuery *single_query, query::v2::Match *match, query::v2::Where *where,
|
||||
T *...clauses) {
|
||||
match->where_ = where;
|
||||
single_query->clauses_.emplace_back(match);
|
||||
return GetSingleQuery(single_query, clauses...);
|
||||
}
|
||||
template <class... T>
|
||||
auto GetSingleQuery(query::v2::SingleQuery *single_query, query::v2::With *with, query::v2::Where *where,
|
||||
T *...clauses) {
|
||||
with->where_ = where;
|
||||
single_query->clauses_.emplace_back(with);
|
||||
return GetSingleQuery(single_query, clauses...);
|
||||
}
|
||||
|
||||
template <class... T>
|
||||
auto GetSingleQuery(query::v2::SingleQuery *single_query, query::v2::Clause *clause, T *...clauses) {
|
||||
single_query->clauses_.emplace_back(clause);
|
||||
return GetSingleQuery(single_query, clauses...);
|
||||
}
|
||||
|
||||
// new stuff end
|
||||
|
||||
auto GetCypherUnion(CypherUnion *cypher_union, SingleQuery *single_query) {
|
||||
cypher_union->single_query_ = single_query;
|
||||
return cypher_union;
|
||||
@ -290,6 +433,24 @@ auto GetQuery(AstStorage &storage, SingleQuery *single_query, T *...cypher_union
|
||||
return query;
|
||||
}
|
||||
|
||||
// new stuff begin
|
||||
|
||||
auto GetQuery(query::v2::AstStorage &storage, query::v2::SingleQuery *single_query) {
|
||||
auto *query = storage.Create<query::v2::CypherQuery>();
|
||||
query->single_query_ = single_query;
|
||||
return query;
|
||||
}
|
||||
|
||||
template <class... T>
|
||||
auto GetQuery(query::v2::AstStorage &storage, query::v2::SingleQuery *single_query, T *...cypher_unions) {
|
||||
auto *query = storage.Create<query::v2::CypherQuery>();
|
||||
query->single_query_ = single_query;
|
||||
query->cypher_unions_ = std::vector<query::v2::CypherUnion *>{cypher_unions...};
|
||||
return query;
|
||||
}
|
||||
|
||||
// new stuff end
|
||||
|
||||
// Helper functions for constructing RETURN and WITH clauses.
|
||||
void FillReturnBody(AstStorage &, ReturnBody &body, NamedExpression *named_expr) {
|
||||
body.named_expressions.emplace_back(named_expr);
|
||||
@ -353,6 +514,80 @@ void FillReturnBody(AstStorage &storage, ReturnBody &body, const std::string &na
|
||||
FillReturnBody(storage, body, rest...);
|
||||
}
|
||||
|
||||
// new stuff begin
|
||||
|
||||
void FillReturnBody(query::v2::AstStorage &, query::v2::ReturnBody &body, query::v2::NamedExpression *named_expr) {
|
||||
body.named_expressions.emplace_back(named_expr);
|
||||
}
|
||||
void FillReturnBody(query::v2::AstStorage &storage, query::v2::ReturnBody &body, const std::string &name) {
|
||||
if (name == "*") {
|
||||
body.all_identifiers = true;
|
||||
} else {
|
||||
auto *ident = storage.Create<memgraph::query::v2::Identifier>(name);
|
||||
auto *named_expr = storage.Create<memgraph::query::v2::NamedExpression>(name, ident);
|
||||
body.named_expressions.emplace_back(named_expr);
|
||||
}
|
||||
}
|
||||
void FillReturnBody(query::v2::AstStorage &, query::v2::ReturnBody &body, Limitv2 limit) {
|
||||
body.limit = limit.expression;
|
||||
}
|
||||
void FillReturnBody(query::v2::AstStorage &, query::v2::ReturnBody &body, Skipv2 skip, Limitv2 limit = Limitv2{}) {
|
||||
body.skip = skip.expression;
|
||||
body.limit = limit.expression;
|
||||
}
|
||||
void FillReturnBody(query::v2::AstStorage &, query::v2::ReturnBody &body, OrderByv2 order_by,
|
||||
Limitv2 limit = Limitv2{}) {
|
||||
body.order_by = order_by.expressions;
|
||||
body.limit = limit.expression;
|
||||
}
|
||||
void FillReturnBody(query::v2::AstStorage &, query::v2::ReturnBody &body, OrderByv2 order_by, Skipv2 skip,
|
||||
Limitv2 limit = Limitv2{}) {
|
||||
body.order_by = order_by.expressions;
|
||||
body.skip = skip.expression;
|
||||
body.limit = limit.expression;
|
||||
}
|
||||
void FillReturnBody(query::v2::AstStorage &, query::v2::ReturnBody &body, query::v2::Expression *expr,
|
||||
query::v2::NamedExpression *named_expr) {
|
||||
// This overload supports `RETURN(expr, AS(name))` construct, since
|
||||
// NamedExpression does not inherit Expression.
|
||||
named_expr->expression_ = expr;
|
||||
body.named_expressions.emplace_back(named_expr);
|
||||
}
|
||||
void FillReturnBody(query::v2::AstStorage &storage, query::v2::ReturnBody &body, const std::string &name,
|
||||
query::v2::NamedExpression *named_expr) {
|
||||
named_expr->expression_ = storage.Create<memgraph::query::v2::Identifier>(name);
|
||||
body.named_expressions.emplace_back(named_expr);
|
||||
}
|
||||
template <class... T>
|
||||
void FillReturnBody(query::v2::AstStorage &storage, query::v2::ReturnBody &body, query::v2::Expression *expr,
|
||||
query::v2::NamedExpression *named_expr, T... rest) {
|
||||
named_expr->expression_ = expr;
|
||||
body.named_expressions.emplace_back(named_expr);
|
||||
FillReturnBody(storage, body, rest...);
|
||||
}
|
||||
template <class... T>
|
||||
void FillReturnBody(query::v2::AstStorage &storage, query::v2::ReturnBody &body, query::v2::NamedExpression *named_expr,
|
||||
T... rest) {
|
||||
body.named_expressions.emplace_back(named_expr);
|
||||
FillReturnBody(storage, body, rest...);
|
||||
}
|
||||
template <class... T>
|
||||
void FillReturnBody(query::v2::AstStorage &storage, query::v2::ReturnBody &body, const std::string &name,
|
||||
query::v2::NamedExpression *named_expr, T... rest) {
|
||||
named_expr->expression_ = storage.Create<memgraph::query::v2::Identifier>(name);
|
||||
body.named_expressions.emplace_back(named_expr);
|
||||
FillReturnBody(storage, body, rest...);
|
||||
}
|
||||
template <class... T>
|
||||
void FillReturnBody(query::v2::AstStorage &storage, query::v2::ReturnBody &body, const std::string &name, T... rest) {
|
||||
auto *ident = storage.Create<memgraph::query::v2::Identifier>(name);
|
||||
auto *named_expr = storage.Create<memgraph::query::v2::NamedExpression>(name, ident);
|
||||
body.named_expressions.emplace_back(named_expr);
|
||||
FillReturnBody(storage, body, rest...);
|
||||
}
|
||||
|
||||
// new stuff end
|
||||
|
||||
/// Create the return clause with given expressions.
|
||||
///
|
||||
/// The supported expression combination of arguments is:
|
||||
@ -374,6 +609,18 @@ auto GetReturn(AstStorage &storage, bool distinct, T... exprs) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// new stuff begin
|
||||
|
||||
template <class... T>
|
||||
auto GetReturn(query::v2::AstStorage &storage, bool distinct, T... exprs) {
|
||||
auto ret = storage.Create<query::v2::Return>();
|
||||
ret->body_.distinct = distinct;
|
||||
FillReturnBody(storage, ret->body_, exprs...);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// new stuff end
|
||||
|
||||
/// Create the with clause with given expressions.
|
||||
///
|
||||
/// The supported expression combination is the same as for @c GetReturn.
|
||||
@ -486,12 +733,16 @@ auto GetForeach(AstStorage &storage, NamedExpression *named_expr, const std::vec
|
||||
#define EDGE(...) memgraph::query::test_common::GetEdge(storage, __VA_ARGS__)
|
||||
#define EDGE_VARIABLE(...) memgraph::query::test_common::GetEdgeVariable(storage, __VA_ARGS__)
|
||||
#define PATTERN(...) memgraph::query::test_common::GetPattern(storage, {__VA_ARGS__})
|
||||
#define PATTERN(...) memgraph::query::test_common::GetPattern(storage, {__VA_ARGS__})
|
||||
#define NAMED_PATTERN(name, ...) memgraph::query::test_common::GetPattern(storage, name, {__VA_ARGS__})
|
||||
#define OPTIONAL_MATCH(...) \
|
||||
memgraph::query::test_common::GetWithPatterns(storage.Create<memgraph::query::Match>(true), {__VA_ARGS__})
|
||||
#define MATCH(...) \
|
||||
memgraph::query::test_common::GetWithPatterns(storage.Create<memgraph::query::Match>(), {__VA_ARGS__})
|
||||
#define MATCH_V2(...) \
|
||||
memgraph::query::test_common::GetWithPatterns(storage.Create<memgraph::query::v2::Match>(), {__VA_ARGS__})
|
||||
#define WHERE(expr) storage.Create<memgraph::query::Where>((expr))
|
||||
#define WHERE_V2(expr) storage.Create<memgraph::query::v2::Where>((expr))
|
||||
#define CREATE(...) \
|
||||
memgraph::query::test_common::GetWithPatterns(storage.Create<memgraph::query::Create>(), {__VA_ARGS__})
|
||||
#define IDENT(...) storage.Create<memgraph::query::Identifier>(__VA_ARGS__)
|
||||
@ -501,6 +752,8 @@ auto GetForeach(AstStorage &storage, NamedExpression *named_expr, const std::vec
|
||||
storage.Create<memgraph::query::MapLiteral>( \
|
||||
std::unordered_map<memgraph::query::PropertyIx, memgraph::query::Expression *>{__VA_ARGS__})
|
||||
#define PROPERTY_PAIR(property_name) std::make_pair(property_name, dba.NameToProperty(property_name))
|
||||
#define PRIMARY_PROPERTY_PAIR(property_name) std::make_pair(property_name, dba.NameToPrimaryProperty(property_name))
|
||||
#define SECONDARY_PROPERTY_PAIR(property_name) std::make_pair(property_name, dba.NameToSecondaryProperty(property_name))
|
||||
#define PROPERTY_LOOKUP(...) memgraph::query::test_common::GetPropertyLookup(storage, dba, __VA_ARGS__)
|
||||
#define PARAMETER_LOOKUP(token_position) storage.Create<memgraph::query::ParameterLookup>((token_position))
|
||||
#define NEXPR(name, expr) storage.Create<memgraph::query::NamedExpression>((name), (expr))
|
||||
@ -536,6 +789,8 @@ auto GetForeach(AstStorage &storage, NamedExpression *named_expr, const std::vec
|
||||
std::vector<memgraph::query::PropertyIx>{(property)})
|
||||
#define QUERY(...) memgraph::query::test_common::GetQuery(storage, __VA_ARGS__)
|
||||
#define SINGLE_QUERY(...) memgraph::query::test_common::GetSingleQuery(storage.Create<SingleQuery>(), __VA_ARGS__)
|
||||
#define SINGLE_QUERY_V2(...) \
|
||||
memgraph::query::test_common::GetSingleQuery(storage.Create<memgraph::query::v2::SingleQuery>(), __VA_ARGS__)
|
||||
#define UNION(...) memgraph::query::test_common::GetCypherUnion(storage.Create<CypherUnion>(true), __VA_ARGS__)
|
||||
#define UNION_ALL(...) memgraph::query::test_common::GetCypherUnion(storage.Create<CypherUnion>(false), __VA_ARGS__)
|
||||
#define FOREACH(...) memgraph::query::test_common::GetForeach(storage, __VA_ARGS__)
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "query/plan/operator.hpp"
|
||||
#include "query/plan/planner.hpp"
|
||||
#include "query/plan/preprocess.hpp"
|
||||
#include "query/v2/plan/operator.hpp"
|
||||
|
||||
namespace memgraph::query::plan {
|
||||
|
||||
@ -90,7 +91,7 @@ class PlanChecker : public virtual HierarchicalLogicalOperatorVisitor {
|
||||
}
|
||||
PRE_VISIT(Unwind);
|
||||
PRE_VISIT(Distinct);
|
||||
|
||||
|
||||
bool PreVisit(Foreach &op) override {
|
||||
CheckOp(op);
|
||||
return false;
|
||||
@ -336,6 +337,39 @@ class ExpectScanAllByLabelProperty : public OpChecker<ScanAllByLabelProperty> {
|
||||
memgraph::storage::PropertyId property_;
|
||||
};
|
||||
|
||||
class ExpectScanAllByPrimaryKey : public OpChecker<v2::plan::ScanAllByPrimaryKey> {
|
||||
public:
|
||||
ExpectScanAllByPrimaryKey(memgraph::storage::v3::LabelId label, const std::vector<Expression *> &properties)
|
||||
: label_(label), properties_(properties) {}
|
||||
|
||||
void ExpectOp(v2::plan::ScanAllByPrimaryKey &scan_all, const SymbolTable &) override {
|
||||
EXPECT_EQ(scan_all.label_, label_);
|
||||
// EXPECT_EQ(scan_all.property_, property_);
|
||||
|
||||
// TODO(gvolfing) maybe assert the size of the 2 vectors.
|
||||
// TODO(gvolfing) maybe use some std alg if Expression lets us.
|
||||
|
||||
bool primary_property_match = true;
|
||||
for (const auto &expected_prop : properties_) {
|
||||
bool has_match = false;
|
||||
for (const auto &prop : scan_all.primary_key_) {
|
||||
if (typeid(prop).hash_code() == typeid(expected_prop).hash_code()) {
|
||||
has_match = true;
|
||||
}
|
||||
}
|
||||
if (!has_match) {
|
||||
primary_property_match = false;
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_TRUE(primary_property_match);
|
||||
}
|
||||
|
||||
private:
|
||||
memgraph::storage::v3::LabelId label_;
|
||||
std::vector<Expression *> properties_;
|
||||
};
|
||||
|
||||
class ExpectCartesian : public OpChecker<Cartesian> {
|
||||
public:
|
||||
ExpectCartesian(const std::list<std::unique_ptr<BaseOpChecker>> &left,
|
||||
@ -486,4 +520,108 @@ class FakeDbAccessor {
|
||||
std::vector<std::tuple<memgraph::storage::LabelId, memgraph::storage::PropertyId, int64_t>> label_property_index_;
|
||||
};
|
||||
|
||||
// class FakeDistributedDbAccessor {
|
||||
// public:
|
||||
// int64_t VerticesCount(memgraph::storage::v3::LabelId label) const {
|
||||
// auto found = label_index_.find(label);
|
||||
// if (found != label_index_.end()) return found->second;
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// int64_t VerticesCount(memgraph::storage::v3::LabelId label, memgraph::storage::PropertyId property) const {
|
||||
// for (auto &index : label_property_index_) {
|
||||
// if (std::get<0>(index) == label && std::get<1>(index) == property) {
|
||||
// return std::get<2>(index);
|
||||
// }
|
||||
// }
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// bool LabelIndexExists(memgraph::storage::v3::LabelId label) const {
|
||||
// return label_index_.find(label) != label_index_.end();
|
||||
// }
|
||||
|
||||
// bool LabelPropertyIndexExists(memgraph::storage::v3::LabelId label, memgraph::storage::PropertyId property) const {
|
||||
// for (auto &index : label_property_index_) {
|
||||
// if (std::get<0>(index) == label && std::get<1>(index) == property) {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// void SetIndexCount(memgraph::storage::v3::LabelId label, int64_t count) { label_index_[label] = count; }
|
||||
|
||||
// void SetIndexCount(memgraph::storage::v3::LabelId label, memgraph::storage::PropertyId property, int64_t count) {
|
||||
// for (auto &index : label_property_index_) {
|
||||
// if (std::get<0>(index) == label && std::get<1>(index) == property) {
|
||||
// std::get<2>(index) = count;
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// label_property_index_.emplace_back(label, property, count);
|
||||
// }
|
||||
|
||||
// memgraph::storage::v3::LabelId NameToLabel(const std::string &name) {
|
||||
// auto found = primary_labels_.find(name);
|
||||
// if (found != primary_labels_.end()) return found->second;
|
||||
// return primary_labels_.emplace(name,
|
||||
// memgraph::storage::v3::LabelId::FromUint(primary_labels_.size())).first->second;
|
||||
// }
|
||||
|
||||
// memgraph::storage::v3::LabelId Label(const std::string &name) { return NameToLabel(name); }
|
||||
|
||||
// memgraph::storage::EdgeTypeId NameToEdgeType(const std::string &name) {
|
||||
// auto found = edge_types_.find(name);
|
||||
// if (found != edge_types_.end()) return found->second;
|
||||
// return edge_types_.emplace(name, memgraph::storage::EdgeTypeId::FromUint(edge_types_.size())).first->second;
|
||||
// }
|
||||
|
||||
// memgraph::storage::PropertyId NameToPrimaryProperty(const std::string &name) {
|
||||
// auto found = primary_properties_.find(name);
|
||||
// if (found != primary_properties_.end()) return found->second;
|
||||
// return primary_properties_.emplace(name,
|
||||
// memgraph::storage::PropertyId::FromUint(primary_properties_.size())).first->second;
|
||||
// }
|
||||
|
||||
// memgraph::storage::PropertyId NameToSecondaryProperty(const std::string &name) {
|
||||
// auto found = secondary_properties_.find(name);
|
||||
// if (found != secondary_properties_.end()) return found->second;
|
||||
// return secondary_properties_.emplace(name,
|
||||
// memgraph::storage::PropertyId::FromUint(secondary_properties_.size())).first->second;
|
||||
// }
|
||||
|
||||
// memgraph::storage::PropertyId PrimaryProperty(const std::string &name) { return NameToPrimaryProperty(name); }
|
||||
// memgraph::storage::PropertyId SecondaryProperty(const std::string &name) { return NameToSecondaryProperty(name); }
|
||||
|
||||
// std::string PrimaryPropertyToName(memgraph::storage::PropertyId property) const {
|
||||
// for (const auto &kv : primary_properties_) {
|
||||
// if (kv.second == property) return kv.first;
|
||||
// }
|
||||
// LOG_FATAL("Unable to find primary property name");
|
||||
// }
|
||||
|
||||
// std::string SecondaryPropertyToName(memgraph::storage::PropertyId property) const {
|
||||
// for (const auto &kv : secondary_properties_) {
|
||||
// if (kv.second == property) return kv.first;
|
||||
// }
|
||||
// LOG_FATAL("Unable to find secondary property name");
|
||||
// }
|
||||
|
||||
// std::string PrimaryPropertyName(memgraph::storage::PropertyId property) const { return
|
||||
// PrimaryPropertyToName(property); } std::string SecondaryPropertyName(memgraph::storage::PropertyId property) const
|
||||
// { return SecondaryPropertyToName(property); }
|
||||
|
||||
// private:
|
||||
// std::unordered_map<std::string, memgraph::storage::v3::LabelId> primary_labels_;
|
||||
// std::unordered_map<std::string, memgraph::storage::v3::LabelId> secondary_labels_;
|
||||
// std::unordered_map<std::string, memgraph::storage::EdgeTypeId> edge_types_;
|
||||
// std::unordered_map<std::string, memgraph::storage::PropertyId> primary_properties_;
|
||||
// std::unordered_map<std::string, memgraph::storage::PropertyId> secondary_properties_;
|
||||
|
||||
// std::unordered_map<memgraph::storage::v3::LabelId, int64_t> label_index_;
|
||||
// std::vector<std::tuple<memgraph::storage::v3::LabelId, memgraph::storage::PropertyId, int64_t>>
|
||||
// label_property_index_;
|
||||
// };
|
||||
|
||||
} // namespace memgraph::query::plan
|
||||
|
559
tests/unit/query_plan_checker_v2.hpp
Normal file
559
tests/unit/query_plan_checker_v2.hpp
Normal file
@ -0,0 +1,559 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
// License, and you may not use this file except in compliance with the Business Source License.
|
||||
//
|
||||
// As of the Change Date specified in that file, in accordance with
|
||||
// the Business Source License, use of this software will be governed
|
||||
// by the Apache License, Version 2.0, included in the file
|
||||
// licenses/APL.txt.
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "query/frontend/semantic/symbol_generator.hpp"
|
||||
#include "query/frontend/semantic/symbol_table.hpp"
|
||||
#include "query/v2/plan/operator.hpp"
|
||||
#include "query/v2/plan/planner.hpp"
|
||||
#include "query/v2/plan/preprocess.hpp"
|
||||
|
||||
namespace memgraph::query::v2::plan {
|
||||
|
||||
class BaseOpChecker {
|
||||
public:
|
||||
virtual ~BaseOpChecker() {}
|
||||
|
||||
virtual void CheckOp(LogicalOperator &, const SymbolTable &) = 0;
|
||||
};
|
||||
|
||||
class PlanChecker : public virtual HierarchicalLogicalOperatorVisitor {
|
||||
public:
|
||||
using HierarchicalLogicalOperatorVisitor::PostVisit;
|
||||
using HierarchicalLogicalOperatorVisitor::PreVisit;
|
||||
using HierarchicalLogicalOperatorVisitor::Visit;
|
||||
|
||||
PlanChecker(const std::list<std::unique_ptr<BaseOpChecker>> &checkers, const SymbolTable &symbol_table)
|
||||
: symbol_table_(symbol_table) {
|
||||
for (const auto &checker : checkers) checkers_.emplace_back(checker.get());
|
||||
}
|
||||
|
||||
PlanChecker(const std::list<BaseOpChecker *> &checkers, const SymbolTable &symbol_table)
|
||||
: checkers_(checkers), symbol_table_(symbol_table) {}
|
||||
|
||||
#define PRE_VISIT(TOp) \
|
||||
bool PreVisit(TOp &op) override { \
|
||||
CheckOp(op); \
|
||||
return true; \
|
||||
}
|
||||
|
||||
#define VISIT(TOp) \
|
||||
bool Visit(TOp &op) override { \
|
||||
CheckOp(op); \
|
||||
return true; \
|
||||
}
|
||||
|
||||
PRE_VISIT(CreateNode);
|
||||
PRE_VISIT(CreateExpand);
|
||||
PRE_VISIT(Delete);
|
||||
PRE_VISIT(ScanAll);
|
||||
PRE_VISIT(ScanAllByLabel);
|
||||
PRE_VISIT(ScanAllByLabelPropertyValue);
|
||||
PRE_VISIT(ScanAllByLabelPropertyRange);
|
||||
PRE_VISIT(ScanAllByLabelProperty);
|
||||
PRE_VISIT(Expand);
|
||||
PRE_VISIT(ExpandVariable);
|
||||
PRE_VISIT(Filter);
|
||||
PRE_VISIT(ConstructNamedPath);
|
||||
PRE_VISIT(Produce);
|
||||
PRE_VISIT(SetProperty);
|
||||
PRE_VISIT(SetProperties);
|
||||
PRE_VISIT(SetLabels);
|
||||
PRE_VISIT(RemoveProperty);
|
||||
PRE_VISIT(RemoveLabels);
|
||||
PRE_VISIT(EdgeUniquenessFilter);
|
||||
PRE_VISIT(Accumulate);
|
||||
PRE_VISIT(Aggregate);
|
||||
PRE_VISIT(Skip);
|
||||
PRE_VISIT(Limit);
|
||||
PRE_VISIT(OrderBy);
|
||||
bool PreVisit(Merge &op) override {
|
||||
CheckOp(op);
|
||||
op.input()->Accept(*this);
|
||||
return false;
|
||||
}
|
||||
bool PreVisit(Optional &op) override {
|
||||
CheckOp(op);
|
||||
op.input()->Accept(*this);
|
||||
return false;
|
||||
}
|
||||
PRE_VISIT(Unwind);
|
||||
PRE_VISIT(Distinct);
|
||||
|
||||
bool PreVisit(Foreach &op) override {
|
||||
CheckOp(op);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Visit(Once &) override {
|
||||
// Ignore checking Once, it is implicitly at the end.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PreVisit(Cartesian &op) override {
|
||||
CheckOp(op);
|
||||
return false;
|
||||
}
|
||||
|
||||
PRE_VISIT(CallProcedure);
|
||||
|
||||
#undef PRE_VISIT
|
||||
#undef VISIT
|
||||
|
||||
void CheckOp(LogicalOperator &op) {
|
||||
ASSERT_FALSE(checkers_.empty());
|
||||
checkers_.back()->CheckOp(op, symbol_table_);
|
||||
checkers_.pop_back();
|
||||
}
|
||||
|
||||
std::list<BaseOpChecker *> checkers_;
|
||||
const SymbolTable &symbol_table_;
|
||||
};
|
||||
|
||||
template <class TOp>
|
||||
class OpChecker : public BaseOpChecker {
|
||||
public:
|
||||
void CheckOp(LogicalOperator &op, const SymbolTable &symbol_table) override {
|
||||
auto *expected_op = dynamic_cast<TOp *>(&op);
|
||||
ASSERT_TRUE(expected_op) << "op is '" << op.GetTypeInfo().name << "' expected '" << TOp::kType.name << "'!";
|
||||
ExpectOp(*expected_op, symbol_table);
|
||||
}
|
||||
|
||||
virtual void ExpectOp(TOp &, const SymbolTable &) {}
|
||||
};
|
||||
|
||||
// using ExpectScanAllByPrimaryKey = OpChecker<ScanAllByPrimaryKey>;
|
||||
|
||||
using ExpectCreateNode = OpChecker<CreateNode>;
|
||||
using ExpectCreateExpand = OpChecker<CreateExpand>;
|
||||
using ExpectDelete = OpChecker<Delete>;
|
||||
using ExpectScanAll = OpChecker<ScanAll>;
|
||||
using ExpectScanAllByLabel = OpChecker<ScanAllByLabel>;
|
||||
// using ExpectScanAllById = OpChecker<ScanAllById>;
|
||||
using ExpectExpand = OpChecker<Expand>;
|
||||
using ExpectFilter = OpChecker<Filter>;
|
||||
using ExpectConstructNamedPath = OpChecker<ConstructNamedPath>;
|
||||
using ExpectProduce = OpChecker<Produce>;
|
||||
using ExpectSetProperty = OpChecker<SetProperty>;
|
||||
using ExpectSetProperties = OpChecker<SetProperties>;
|
||||
using ExpectSetLabels = OpChecker<SetLabels>;
|
||||
using ExpectRemoveProperty = OpChecker<RemoveProperty>;
|
||||
using ExpectRemoveLabels = OpChecker<RemoveLabels>;
|
||||
using ExpectEdgeUniquenessFilter = OpChecker<EdgeUniquenessFilter>;
|
||||
using ExpectSkip = OpChecker<Skip>;
|
||||
using ExpectLimit = OpChecker<Limit>;
|
||||
using ExpectOrderBy = OpChecker<OrderBy>;
|
||||
using ExpectUnwind = OpChecker<Unwind>;
|
||||
using ExpectDistinct = OpChecker<Distinct>;
|
||||
|
||||
// class ExpectForeach : public OpChecker<Foreach> {
|
||||
// public:
|
||||
// ExpectForeach(const std::list<BaseOpChecker *> &input, const std::list<BaseOpChecker *> &updates)
|
||||
// : input_(input), updates_(updates) {}
|
||||
|
||||
// void ExpectOp(Foreach &foreach, const SymbolTable &symbol_table) override {
|
||||
// PlanChecker check_input(input_, symbol_table);
|
||||
// foreach
|
||||
// .input_->Accept(check_input);
|
||||
// PlanChecker check_updates(updates_, symbol_table);
|
||||
// foreach
|
||||
// .update_clauses_->Accept(check_updates);
|
||||
// }
|
||||
|
||||
// private:
|
||||
// std::list<BaseOpChecker *> input_;
|
||||
// std::list<BaseOpChecker *> updates_;
|
||||
// };
|
||||
|
||||
// class ExpectExpandVariable : public OpChecker<ExpandVariable> {
|
||||
// public:
|
||||
// void ExpectOp(ExpandVariable &op, const SymbolTable &) override {
|
||||
// EXPECT_EQ(op.type_, memgraph::query::EdgeAtom::Type::DEPTH_FIRST);
|
||||
// }
|
||||
// };
|
||||
|
||||
// class ExpectExpandBfs : public OpChecker<ExpandVariable> {
|
||||
// public:
|
||||
// void ExpectOp(ExpandVariable &op, const SymbolTable &) override {
|
||||
// EXPECT_EQ(op.type_, memgraph::query::EdgeAtom::Type::BREADTH_FIRST);
|
||||
// }
|
||||
// };
|
||||
|
||||
// class ExpectAccumulate : public OpChecker<Accumulate> {
|
||||
// public:
|
||||
// explicit ExpectAccumulate(const std::unordered_set<Symbol> &symbols) : symbols_(symbols) {}
|
||||
|
||||
// void ExpectOp(Accumulate &op, const SymbolTable &) override {
|
||||
// std::unordered_set<Symbol> got_symbols(op.symbols_.begin(), op.symbols_.end());
|
||||
// EXPECT_EQ(symbols_, got_symbols);
|
||||
// }
|
||||
|
||||
// private:
|
||||
// const std::unordered_set<Symbol> symbols_;
|
||||
// };
|
||||
|
||||
// class ExpectAggregate : public OpChecker<Aggregate> {
|
||||
// public:
|
||||
// ExpectAggregate(const std::vector<memgraph::query::Aggregation *> &aggregations,
|
||||
// const std::unordered_set<memgraph::query::Expression *> &group_by)
|
||||
// : aggregations_(aggregations), group_by_(group_by) {}
|
||||
|
||||
// void ExpectOp(Aggregate &op, const SymbolTable &symbol_table) override {
|
||||
// auto aggr_it = aggregations_.begin();
|
||||
// for (const auto &aggr_elem : op.aggregations_) {
|
||||
// ASSERT_NE(aggr_it, aggregations_.end());
|
||||
// auto aggr = *aggr_it++;
|
||||
// // TODO: Proper expression equality
|
||||
// EXPECT_EQ(typeid(aggr_elem.value).hash_code(), typeid(aggr->expression1_).hash_code());
|
||||
// EXPECT_EQ(typeid(aggr_elem.key).hash_code(), typeid(aggr->expression2_).hash_code());
|
||||
// EXPECT_EQ(aggr_elem.op, aggr->op_);
|
||||
// EXPECT_EQ(aggr_elem.output_sym, symbol_table.at(*aggr));
|
||||
// }
|
||||
// EXPECT_EQ(aggr_it, aggregations_.end());
|
||||
// // TODO: Proper group by expression equality
|
||||
// std::unordered_set<size_t> got_group_by;
|
||||
// for (auto *expr : op.group_by_) got_group_by.insert(typeid(*expr).hash_code());
|
||||
// std::unordered_set<size_t> expected_group_by;
|
||||
// for (auto *expr : group_by_) expected_group_by.insert(typeid(*expr).hash_code());
|
||||
// EXPECT_EQ(got_group_by, expected_group_by);
|
||||
// }
|
||||
|
||||
// private:
|
||||
// std::vector<memgraph::query::Aggregation *> aggregations_;
|
||||
// std::unordered_set<memgraph::query::Expression *> group_by_;
|
||||
// };
|
||||
|
||||
// class ExpectMerge : public OpChecker<Merge> {
|
||||
// public:
|
||||
// ExpectMerge(const std::list<BaseOpChecker *> &on_match, const std::list<BaseOpChecker *> &on_create)
|
||||
// : on_match_(on_match), on_create_(on_create) {}
|
||||
|
||||
// void ExpectOp(Merge &merge, const SymbolTable &symbol_table) override {
|
||||
// PlanChecker check_match(on_match_, symbol_table);
|
||||
// merge.merge_match_->Accept(check_match);
|
||||
// PlanChecker check_create(on_create_, symbol_table);
|
||||
// merge.merge_create_->Accept(check_create);
|
||||
// }
|
||||
|
||||
// private:
|
||||
// const std::list<BaseOpChecker *> &on_match_;
|
||||
// const std::list<BaseOpChecker *> &on_create_;
|
||||
// };
|
||||
|
||||
// class ExpectOptional : public OpChecker<Optional> {
|
||||
// public:
|
||||
// explicit ExpectOptional(const std::list<BaseOpChecker *> &optional) : optional_(optional) {}
|
||||
|
||||
// ExpectOptional(const std::vector<Symbol> &optional_symbols, const std::list<BaseOpChecker *> &optional)
|
||||
// : optional_symbols_(optional_symbols), optional_(optional) {}
|
||||
|
||||
// void ExpectOp(Optional &optional, const SymbolTable &symbol_table) override {
|
||||
// if (!optional_symbols_.empty()) {
|
||||
// EXPECT_THAT(optional.optional_symbols_, testing::UnorderedElementsAreArray(optional_symbols_));
|
||||
// }
|
||||
// PlanChecker check_optional(optional_, symbol_table);
|
||||
// optional.optional_->Accept(check_optional);
|
||||
// }
|
||||
|
||||
// private:
|
||||
// std::vector<Symbol> optional_symbols_;
|
||||
// const std::list<BaseOpChecker *> &optional_;
|
||||
// };
|
||||
|
||||
// class ExpectScanAllByLabelPropertyValue : public OpChecker<ScanAllByLabelPropertyValue> {
|
||||
// public:
|
||||
// ExpectScanAllByLabelPropertyValue(memgraph::storage::LabelId label,
|
||||
// const std::pair<std::string, memgraph::storage::PropertyId> &prop_pair,
|
||||
// memgraph::query::Expression *expression)
|
||||
// : label_(label), property_(prop_pair.second), expression_(expression) {}
|
||||
|
||||
// void ExpectOp(ScanAllByLabelPropertyValue &scan_all, const SymbolTable &) override {
|
||||
// EXPECT_EQ(scan_all.label_, label_);
|
||||
// EXPECT_EQ(scan_all.property_, property_);
|
||||
// // TODO: Proper expression equality
|
||||
// EXPECT_EQ(typeid(scan_all.expression_).hash_code(), typeid(expression_).hash_code());
|
||||
// }
|
||||
|
||||
// private:
|
||||
// memgraph::storage::LabelId label_;
|
||||
// memgraph::storage::PropertyId property_;
|
||||
// memgraph::query::Expression *expression_;
|
||||
// };
|
||||
|
||||
// class ExpectScanAllByLabelPropertyRange : public OpChecker<ScanAllByLabelPropertyRange> {
|
||||
// public:
|
||||
// ExpectScanAllByLabelPropertyRange(memgraph::storage::LabelId label, memgraph::storage::PropertyId property,
|
||||
// std::optional<ScanAllByLabelPropertyRange::Bound> lower_bound,
|
||||
// std::optional<ScanAllByLabelPropertyRange::Bound> upper_bound)
|
||||
// : label_(label), property_(property), lower_bound_(lower_bound), upper_bound_(upper_bound) {}
|
||||
|
||||
// void ExpectOp(ScanAllByLabelPropertyRange &scan_all, const SymbolTable &) override {
|
||||
// EXPECT_EQ(scan_all.label_, label_);
|
||||
// EXPECT_EQ(scan_all.property_, property_);
|
||||
// if (lower_bound_) {
|
||||
// ASSERT_TRUE(scan_all.lower_bound_);
|
||||
// // TODO: Proper expression equality
|
||||
// EXPECT_EQ(typeid(scan_all.lower_bound_->value()).hash_code(), typeid(lower_bound_->value()).hash_code());
|
||||
// EXPECT_EQ(scan_all.lower_bound_->type(), lower_bound_->type());
|
||||
// }
|
||||
// if (upper_bound_) {
|
||||
// ASSERT_TRUE(scan_all.upper_bound_);
|
||||
// // TODO: Proper expression equality
|
||||
// EXPECT_EQ(typeid(scan_all.upper_bound_->value()).hash_code(), typeid(upper_bound_->value()).hash_code());
|
||||
// EXPECT_EQ(scan_all.upper_bound_->type(), upper_bound_->type());
|
||||
// }
|
||||
// }
|
||||
|
||||
// private:
|
||||
// memgraph::storage::LabelId label_;
|
||||
// memgraph::storage::PropertyId property_;
|
||||
// std::optional<ScanAllByLabelPropertyRange::Bound> lower_bound_;
|
||||
// std::optional<ScanAllByLabelPropertyRange::Bound> upper_bound_;
|
||||
// };
|
||||
|
||||
// class ExpectScanAllByLabelProperty : public OpChecker<ScanAllByLabelProperty> {
|
||||
// public:
|
||||
// ExpectScanAllByLabelProperty(memgraph::storage::LabelId label,
|
||||
// const std::pair<std::string, memgraph::storage::PropertyId> &prop_pair)
|
||||
// : label_(label), property_(prop_pair.second) {}
|
||||
|
||||
// void ExpectOp(ScanAllByLabelProperty &scan_all, const SymbolTable &) override {
|
||||
// EXPECT_EQ(scan_all.label_, label_);
|
||||
// EXPECT_EQ(scan_all.property_, property_);
|
||||
// }
|
||||
|
||||
// private:
|
||||
// memgraph::storage::LabelId label_;
|
||||
// memgraph::storage::PropertyId property_;
|
||||
// };
|
||||
|
||||
class ExpectScanAllByPrimaryKey : public OpChecker<v2::plan::ScanAllByPrimaryKey> {
|
||||
public:
|
||||
ExpectScanAllByPrimaryKey(memgraph::storage::v3::LabelId label, const std::vector<Expression *> &properties)
|
||||
: label_(label), properties_(properties) {}
|
||||
|
||||
void ExpectOp(v2::plan::ScanAllByPrimaryKey &scan_all, const SymbolTable &) override {
|
||||
EXPECT_EQ(scan_all.label_, label_);
|
||||
// EXPECT_EQ(scan_all.property_, property_);
|
||||
|
||||
// TODO(gvolfing) maybe assert the size of the 2 vectors.
|
||||
// TODO(gvolfing) maybe use some std alg if Expression lets us.
|
||||
|
||||
bool primary_property_match = true;
|
||||
for (const auto &expected_prop : properties_) {
|
||||
bool has_match = false;
|
||||
for (const auto &prop : scan_all.primary_key_) {
|
||||
if (typeid(prop).hash_code() == typeid(expected_prop).hash_code()) {
|
||||
has_match = true;
|
||||
}
|
||||
}
|
||||
if (!has_match) {
|
||||
primary_property_match = false;
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_TRUE(primary_property_match);
|
||||
}
|
||||
|
||||
private:
|
||||
memgraph::storage::v3::LabelId label_;
|
||||
std::vector<Expression *> properties_;
|
||||
};
|
||||
|
||||
class ExpectCartesian : public OpChecker<Cartesian> {
|
||||
public:
|
||||
ExpectCartesian(const std::list<std::unique_ptr<BaseOpChecker>> &left,
|
||||
const std::list<std::unique_ptr<BaseOpChecker>> &right)
|
||||
: left_(left), right_(right) {}
|
||||
|
||||
void ExpectOp(Cartesian &op, const SymbolTable &symbol_table) override {
|
||||
ASSERT_TRUE(op.left_op_);
|
||||
PlanChecker left_checker(left_, symbol_table);
|
||||
op.left_op_->Accept(left_checker);
|
||||
ASSERT_TRUE(op.right_op_);
|
||||
PlanChecker right_checker(right_, symbol_table);
|
||||
op.right_op_->Accept(right_checker);
|
||||
}
|
||||
|
||||
private:
|
||||
const std::list<std::unique_ptr<BaseOpChecker>> &left_;
|
||||
const std::list<std::unique_ptr<BaseOpChecker>> &right_;
|
||||
};
|
||||
|
||||
class ExpectCallProcedure : public OpChecker<CallProcedure> {
|
||||
public:
|
||||
ExpectCallProcedure(const std::string &name, const std::vector<memgraph::query::Expression *> &args,
|
||||
const std::vector<std::string> &fields, const std::vector<Symbol> &result_syms)
|
||||
: name_(name), args_(args), fields_(fields), result_syms_(result_syms) {}
|
||||
|
||||
void ExpectOp(CallProcedure &op, const SymbolTable &symbol_table) override {
|
||||
EXPECT_EQ(op.procedure_name_, name_);
|
||||
EXPECT_EQ(op.arguments_.size(), args_.size());
|
||||
for (size_t i = 0; i < args_.size(); ++i) {
|
||||
const auto *op_arg = op.arguments_[i];
|
||||
const auto *expected_arg = args_[i];
|
||||
// TODO: Proper expression equality
|
||||
EXPECT_EQ(op_arg->GetTypeInfo(), expected_arg->GetTypeInfo());
|
||||
}
|
||||
EXPECT_EQ(op.result_fields_, fields_);
|
||||
EXPECT_EQ(op.result_symbols_, result_syms_);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::vector<memgraph::query::Expression *> args_;
|
||||
std::vector<std::string> fields_;
|
||||
std::vector<Symbol> result_syms_;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
std::list<std::unique_ptr<BaseOpChecker>> MakeCheckers(T arg) {
|
||||
std::list<std::unique_ptr<BaseOpChecker>> l;
|
||||
l.emplace_back(std::make_unique<T>(arg));
|
||||
return l;
|
||||
}
|
||||
|
||||
template <class T, class... Rest>
|
||||
std::list<std::unique_ptr<BaseOpChecker>> MakeCheckers(T arg, Rest &&...rest) {
|
||||
auto l = MakeCheckers(std::forward<Rest>(rest)...);
|
||||
l.emplace_front(std::make_unique<T>(arg));
|
||||
return std::move(l);
|
||||
}
|
||||
|
||||
template <class TPlanner, class TDbAccessor>
|
||||
TPlanner MakePlanner(TDbAccessor *dba, AstStorage &storage, SymbolTable &symbol_table, CypherQuery *query) {
|
||||
auto planning_context = MakePlanningContext(&storage, &symbol_table, query, dba);
|
||||
auto query_parts = CollectQueryParts(symbol_table, storage, query);
|
||||
auto single_query_parts = query_parts.query_parts.at(0).single_query_parts;
|
||||
return TPlanner(single_query_parts, planning_context);
|
||||
}
|
||||
|
||||
class FakeDistributedDbAccessor {
|
||||
public:
|
||||
int64_t VerticesCount(memgraph::storage::v3::LabelId label) const {
|
||||
auto found = label_index_.find(label);
|
||||
if (found != label_index_.end()) return found->second;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t VerticesCount(memgraph::storage::v3::LabelId label, memgraph::storage::v3::PropertyId property) const {
|
||||
for (auto &index : label_property_index_) {
|
||||
if (std::get<0>(index) == label && std::get<1>(index) == property) {
|
||||
return std::get<2>(index);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool LabelIndexExists(memgraph::storage::v3::LabelId label) const {
|
||||
return label_index_.find(label) != label_index_.end();
|
||||
}
|
||||
|
||||
bool LabelPropertyIndexExists(memgraph::storage::v3::LabelId label,
|
||||
memgraph::storage::v3::PropertyId property) const {
|
||||
for (auto &index : label_property_index_) {
|
||||
if (std::get<0>(index) == label && std::get<1>(index) == property) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SetIndexCount(memgraph::storage::v3::LabelId label, int64_t count) { label_index_[label] = count; }
|
||||
|
||||
void SetIndexCount(memgraph::storage::v3::LabelId label, memgraph::storage::v3::PropertyId property, int64_t count) {
|
||||
for (auto &index : label_property_index_) {
|
||||
if (std::get<0>(index) == label && std::get<1>(index) == property) {
|
||||
std::get<2>(index) = count;
|
||||
return;
|
||||
}
|
||||
}
|
||||
label_property_index_.emplace_back(label, property, count);
|
||||
}
|
||||
|
||||
memgraph::storage::v3::LabelId NameToLabel(const std::string &name) {
|
||||
auto found = primary_labels_.find(name);
|
||||
if (found != primary_labels_.end()) return found->second;
|
||||
return primary_labels_.emplace(name, memgraph::storage::v3::LabelId::FromUint(primary_labels_.size()))
|
||||
.first->second;
|
||||
}
|
||||
|
||||
memgraph::storage::v3::LabelId Label(const std::string &name) { return NameToLabel(name); }
|
||||
|
||||
memgraph::storage::v3::EdgeTypeId NameToEdgeType(const std::string &name) {
|
||||
auto found = edge_types_.find(name);
|
||||
if (found != edge_types_.end()) return found->second;
|
||||
return edge_types_.emplace(name, memgraph::storage::v3::EdgeTypeId::FromUint(edge_types_.size())).first->second;
|
||||
}
|
||||
|
||||
memgraph::storage::v3::PropertyId NameToPrimaryProperty(const std::string &name) {
|
||||
auto found = primary_properties_.find(name);
|
||||
if (found != primary_properties_.end()) return found->second;
|
||||
return primary_properties_.emplace(name, memgraph::storage::v3::PropertyId::FromUint(primary_properties_.size()))
|
||||
.first->second;
|
||||
}
|
||||
|
||||
memgraph::storage::v3::PropertyId NameToSecondaryProperty(const std::string &name) {
|
||||
auto found = secondary_properties_.find(name);
|
||||
if (found != secondary_properties_.end()) return found->second;
|
||||
return secondary_properties_
|
||||
.emplace(name, memgraph::storage::v3::PropertyId::FromUint(secondary_properties_.size()))
|
||||
.first->second;
|
||||
}
|
||||
|
||||
memgraph::storage::v3::PropertyId PrimaryProperty(const std::string &name) { return NameToPrimaryProperty(name); }
|
||||
memgraph::storage::v3::PropertyId SecondaryProperty(const std::string &name) { return NameToSecondaryProperty(name); }
|
||||
|
||||
std::string PrimaryPropertyToName(memgraph::storage::v3::PropertyId property) const {
|
||||
for (const auto &kv : primary_properties_) {
|
||||
if (kv.second == property) return kv.first;
|
||||
}
|
||||
LOG_FATAL("Unable to find primary property name");
|
||||
}
|
||||
|
||||
std::string SecondaryPropertyToName(memgraph::storage::v3::PropertyId property) const {
|
||||
for (const auto &kv : secondary_properties_) {
|
||||
if (kv.second == property) return kv.first;
|
||||
}
|
||||
LOG_FATAL("Unable to find secondary property name");
|
||||
}
|
||||
|
||||
std::string PrimaryPropertyName(memgraph::storage::v3::PropertyId property) const {
|
||||
return PrimaryPropertyToName(property);
|
||||
}
|
||||
std::string SecondaryPropertyName(memgraph::storage::v3::PropertyId property) const {
|
||||
return SecondaryPropertyToName(property);
|
||||
}
|
||||
|
||||
memgraph::storage::v3::PropertyId NameToProperty(const std::string &name) {
|
||||
return storage::v3::PropertyId::FromUint(0);
|
||||
}
|
||||
|
||||
std::vector<query::v2::Expression *> ExtractPrimaryKey(storage::v3::LabelId label,
|
||||
std::vector<query::v2::plan::FilterInfo> property_filters) {
|
||||
return std::vector<query::v2::Expression *>{};
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, memgraph::storage::v3::LabelId> primary_labels_;
|
||||
std::unordered_map<std::string, memgraph::storage::v3::LabelId> secondary_labels_;
|
||||
std::unordered_map<std::string, memgraph::storage::v3::EdgeTypeId> edge_types_;
|
||||
std::unordered_map<std::string, memgraph::storage::v3::PropertyId> primary_properties_;
|
||||
std::unordered_map<std::string, memgraph::storage::v3::PropertyId> secondary_properties_;
|
||||
|
||||
std::unordered_map<memgraph::storage::v3::LabelId, int64_t> label_index_;
|
||||
std::vector<std::tuple<memgraph::storage::v3::LabelId, memgraph::storage::v3::PropertyId, int64_t>>
|
||||
label_property_index_;
|
||||
};
|
||||
|
||||
} // namespace memgraph::query::v2::plan
|
1664
tests/unit/query_plan_v2.cpp
Normal file
1664
tests/unit/query_plan_v2.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user