Fix bug in query plan to use indexes on optional match and foreach (#736)
* Add fix in query plan to use indexes on optional match and foreach
This commit is contained in:
parent
1cd1da84fd
commit
8cf51d9f68
@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 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
|
||||
@ -444,6 +444,8 @@ class IndexLookupRewriter final : public HierarchicalLogicalOperatorVisitor {
|
||||
|
||||
bool PreVisit(Foreach &op) override {
|
||||
prev_ops_.push_back(&op);
|
||||
op.input()->Accept(*this);
|
||||
RewriteBranch(&op.update_clauses_);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 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
|
||||
@ -174,7 +174,11 @@ class RuleBasedPlanner {
|
||||
input_op = PlanMatching(match_ctx, std::move(input_op));
|
||||
for (const auto &matching : query_part.optional_matching) {
|
||||
MatchContext opt_ctx{matching, *context.symbol_table, context.bound_symbols};
|
||||
auto match_op = PlanMatching(opt_ctx, nullptr);
|
||||
|
||||
std::vector<Symbol> bound_symbols(context_->bound_symbols.begin(), context_->bound_symbols.end());
|
||||
auto once_with_symbols = std::make_unique<Once>(bound_symbols);
|
||||
|
||||
auto match_op = PlanMatching(opt_ctx, std::move(once_with_symbols));
|
||||
if (match_op) {
|
||||
input_op = std::make_unique<Optional>(std::move(input_op), std::move(match_op), opt_ctx.new_symbols);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 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
|
||||
@ -662,6 +662,30 @@ TYPED_TEST(TestPlanner, MatchOptionalMatchWhereReturn) {
|
||||
DeleteListContent(&optional);
|
||||
}
|
||||
|
||||
TYPED_TEST(TestPlanner, MatchOptionalMatchNodePropertyWithIndex) {
|
||||
// Test MATCH (n:Label) OPTIONAL MATCH (m:Label) WHERE n.prop = m.prop RETURN n
|
||||
AstStorage storage;
|
||||
FakeDbAccessor dba;
|
||||
|
||||
const auto label_name = "label";
|
||||
const auto label = dba.Label(label_name);
|
||||
const auto property = PROPERTY_PAIR("prop");
|
||||
dba.SetIndexCount(label, property.second, 0);
|
||||
|
||||
auto *query = QUERY(SINGLE_QUERY(
|
||||
MATCH(PATTERN(NODE("n", label_name))), OPTIONAL_MATCH(PATTERN(NODE("m", label_name))),
|
||||
WHERE(EQ(PROPERTY_LOOKUP("n", property.second), PROPERTY_LOOKUP("m", property.second))), RETURN("n")));
|
||||
|
||||
auto symbol_table = memgraph::query::MakeSymbolTable(query);
|
||||
auto planner = MakePlanner<TypeParam>(&dba, storage, symbol_table, query);
|
||||
|
||||
auto m_prop = PROPERTY_LOOKUP("m", property);
|
||||
std::list<BaseOpChecker *> optional{new ExpectScanAllByLabelPropertyValue(label, property, m_prop)};
|
||||
|
||||
CheckPlan(planner.plan(), symbol_table, ExpectScanAll(), ExpectFilter(), ExpectOptional(optional), ExpectProduce());
|
||||
DeleteListContent(&optional);
|
||||
}
|
||||
|
||||
TYPED_TEST(TestPlanner, MatchUnwindReturn) {
|
||||
// Test MATCH (n) UNWIND [1,2,3] AS x RETURN n, x
|
||||
AstStorage storage;
|
||||
@ -1685,5 +1709,30 @@ TYPED_TEST(TestPlanner, Foreach) {
|
||||
QUERY(SINGLE_QUERY(FOREACH(i, {CREATE(PATTERN(NODE("n")))}), FOREACH(j, {CREATE(PATTERN(NODE("n")))})));
|
||||
CheckPlan<TypeParam>(query, storage, ExpectForeach(input, updates), ExpectEmptyResult());
|
||||
}
|
||||
|
||||
{
|
||||
// FOREACH with index
|
||||
// FOREACH (n in [...] | MERGE (v:Label));
|
||||
const auto label_name = "label";
|
||||
const auto label = dba.Label(label_name);
|
||||
dba.SetIndexCount(label, 0);
|
||||
|
||||
auto *n = NEXPR("n", IDENT("n"));
|
||||
auto *query = QUERY(SINGLE_QUERY(FOREACH(n, {MERGE(PATTERN(NODE("v", label_name)))})));
|
||||
|
||||
auto symbol_table = memgraph::query::MakeSymbolTable(query);
|
||||
auto planner = MakePlanner<TypeParam>(&dba, storage, symbol_table, query);
|
||||
|
||||
std::list<BaseOpChecker *> on_match{new ExpectScanAllByLabel()};
|
||||
std::list<BaseOpChecker *> on_create{new ExpectCreateNode()};
|
||||
|
||||
auto create = ExpectMerge(on_match, on_create);
|
||||
std::list<BaseOpChecker *> updates{&create};
|
||||
std::list<BaseOpChecker *> input;
|
||||
CheckPlan(planner.plan(), symbol_table, ExpectForeach(input, updates), ExpectEmptyResult());
|
||||
|
||||
DeleteListContent(&on_match);
|
||||
DeleteListContent(&on_create);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
Loading…
Reference in New Issue
Block a user