From 7a114622633909dc0af5daf36e03ae056fcf1bbb Mon Sep 17 00:00:00 2001 From: "kyle.cao" Date: Thu, 22 Sep 2022 14:14:18 +0800 Subject: [PATCH] fix optional match --- src/graph/planner/match/MatchPlanner.cpp | 27 ++++++++++++++++--- .../match/MultiLineMultiQueryParts.feature | 7 +++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/graph/planner/match/MatchPlanner.cpp b/src/graph/planner/match/MatchPlanner.cpp index 026c35428ba..4f234b5c891 100644 --- a/src/graph/planner/match/MatchPlanner.cpp +++ b/src/graph/planner/match/MatchPlanner.cpp @@ -15,6 +15,7 @@ #include "graph/planner/plan/Algo.h" #include "graph/planner/plan/Logic.h" #include "graph/planner/plan/Query.h" +#include "graph/util/ExpressionUtils.h" namespace nebula { namespace graph { @@ -76,8 +77,28 @@ Status MatchPlanner::connectMatchPlan(SubPlan& queryPlan, MatchClauseContext* ma if (!intersectedAliases.empty()) { if (matchCtx->isOptional) { // connect LeftJoin match filter - if (matchCtx->where != nullptr) { - matchCtx->where->inputColNames = matchPlan.root->colNames(); + auto& whereCtx = matchCtx->where; + if (whereCtx.get() != nullptr) { + auto exprs = + ExpressionUtils::collectAll(whereCtx->filter, {Expression::Kind::kLabelTagProperty}); + + // Check if all aliases in where clause are generated by the current match statement pattern + std::vector aliases; + for (const auto* expr : exprs) { + DCHECK_EQ(expr->kind(), Expression::Kind::kLabelTagProperty); + auto* labelExpr = static_cast(expr)->label(); + DCHECK_EQ(labelExpr->kind(), Expression::Kind::kVarProperty); + aliases.emplace_back(static_cast(labelExpr)->prop()); + } + auto aliasesGenerated = matchCtx->aliasesGenerated; + if (!std::all_of(aliases.begin(), aliases.end(), [&aliasesGenerated](std::string& alias) { + return aliasesGenerated.find(alias) != aliasesGenerated.end(); + })) { + return Status::SemanticError( + "The where clause of optional match statement that reference variables defined by " + "other statements is not supported yet."); + } + whereCtx->inputColNames = matchPlan.root->colNames(); auto wherePlanStatus = std::make_unique()->transform(matchCtx->where.get()); NG_RETURN_IF_ERROR(wherePlanStatus); @@ -102,7 +123,7 @@ Status MatchPlanner::genQueryPartPlan(QueryContext* qctx, const QueryPart& queryPart) { // generate plan for matchs for (auto& match : queryPart.matchs) { - connectMatchPlan(queryPlan, match.get()); + NG_RETURN_IF_ERROR(connectMatchPlan(queryPlan, match.get())); // connect match filter if (match->where != nullptr && !match->isOptional) { match->where->inputColNames = queryPlan.root->colNames(); diff --git a/tests/tck/features/match/MultiLineMultiQueryParts.feature b/tests/tck/features/match/MultiLineMultiQueryParts.feature index ab0979380e2..05bc40e0429 100644 --- a/tests/tck/features/match/MultiLineMultiQueryParts.feature +++ b/tests/tck/features/match/MultiLineMultiQueryParts.feature @@ -354,3 +354,10 @@ Feature: Multi Line Multi Query Parts RETURN m """ Then a SemanticError should be raised at runtime: Alias used but not defined: `m' + When executing query: + """ + MATCH (m)-[]-(n) WHERE id(m)=="Tim Duncan" + OPTIONAL MATCH (n)-->(v) WHERE v.player.age < m.player.age + RETURN n,v + """ + Then a SemanticError should be raised at runtime: The where clause of optional match statement that reference variables defined by other statements is not supported yet.