diff --git a/src/query/plan/operator.cpp b/src/query/plan/operator.cpp index 5a2b69356..1ffe0f363 100644 --- a/src/query/plan/operator.cpp +++ b/src/query/plan/operator.cpp @@ -246,12 +246,14 @@ std::unique_ptr<Cursor> ScanAllByLabel::MakeCursor(GraphDbAccessor &db) { output_symbol_, input_->MakeCursor(db), std::move(vertices)); } -Expand::Expand(const NodeAtom *node_atom, const EdgeAtom *edge_atom, +Expand::Expand(Symbol node_symbol, Symbol edge_symbol, + EdgeAtom::Direction direction, const std::shared_ptr<LogicalOperator> &input, Symbol input_symbol, bool existing_node, bool existing_edge, GraphView graph_view) - : node_atom_(node_atom), - edge_atom_(edge_atom), + : node_symbol_(node_symbol), + edge_symbol_(edge_symbol), + direction_(direction), input_(input ? input : std::make_shared<Once>()), input_symbol_(input_symbol), existing_node_(existing_node), @@ -285,8 +287,7 @@ bool Expand::ExpandCursor::Pull(Frame &frame, const SymbolTable &symbol_table) { // when expanding in EdgeAtom::Direction::BOTH directions // we should do only one expansion for cycles, and it was // already done in the block above - if (self_.edge_atom_->direction_ == EdgeAtom::Direction::BOTH && - edge.is_cycle()) + if (self_.direction_ == EdgeAtom::Direction::BOTH && edge.is_cycle()) continue; if (HandleExistingEdge(edge, frame, symbol_table) && PullNode(edge, EdgeAtom::Direction::RIGHT, frame, symbol_table)) @@ -334,7 +335,7 @@ bool Expand::ExpandCursor::InitEdges(Frame &frame, break; } - auto direction = self_.edge_atom_->direction_; + auto direction = self_.direction_; if (direction == EdgeAtom::Direction::LEFT || direction == EdgeAtom::Direction::BOTH) { in_edges_ = std::make_unique<InEdgeT>(vertex.in()); @@ -359,14 +360,13 @@ bool Expand::ExpandCursor::HandleExistingEdge(const EdgeAccessor &new_edge, Frame &frame, const SymbolTable &symbol_table) { if (self_.existing_edge_) { - TypedValue &old_edge_value = - frame[symbol_table.at(*self_.edge_atom_->identifier_)]; + TypedValue &old_edge_value = frame[self_.edge_symbol_]; // old_edge_value may be Null when using optional matching return !old_edge_value.IsNull() && old_edge_value.Value<EdgeAccessor>() == new_edge; } else { // not matching existing, so put the new_edge into the frame and return true - frame[symbol_table.at(*self_.edge_atom_->identifier_)] = new_edge; + frame[self_.edge_symbol_] = new_edge; return true; } } @@ -388,14 +388,13 @@ bool Expand::ExpandCursor::HandleExistingNode(const VertexAccessor new_node, Frame &frame, const SymbolTable &symbol_table) { if (self_.existing_node_) { - TypedValue &old_node_value = - frame[symbol_table.at(*self_.node_atom_->identifier_)]; + TypedValue &old_node_value = frame[self_.node_symbol_]; // old_node_value may be Null when using optional matching return !old_node_value.IsNull() && old_node_value.Value<VertexAccessor>() == new_node; } else { - // not matching existing, so put the new_edge into the frame and return true - frame[symbol_table.at(*self_.node_atom_->identifier_)] = new_node; + // not matching existing, so put the new_node into the frame and return true + frame[self_.node_symbol_] = new_node; return true; } } diff --git a/src/query/plan/operator.hpp b/src/query/plan/operator.hpp index 70010420b..7445bb3ed 100644 --- a/src/query/plan/operator.hpp +++ b/src/query/plan/operator.hpp @@ -358,18 +358,21 @@ class Expand : public LogicalOperator { * the expansion originates from. This is controlled with a * constructor argument. * - * @param node_atom Describes the node to be expanded. Only the - * identifier is used, labels and properties are ignored. - * @param edge_atom Describes the edge to be expanded. Identifier - * and direction are used, edge type and properties are ignored. + * @param node_symbol Symbol pointing to the node to be expanded. This is + * where the new node will be stored. + * @param edge_symbol Symbol for the edge to be expanded. This is where the + * edge value will be stored. + * @param direction EdgeAtom::Direction determining the direction of edge + * expansion. The direction is relative to the starting vertex (pointed by + * `input_symbol`). * @param input Optional LogicalOperator that preceeds this one. - * @param input_symbol Symbol that points to a VertexAccessor - * in the Frame that expansion should emanate from. - * @param existing_node If or not the node to be expanded is already - * present in the Frame and should just be checked for equality. - * @param existing_edge Same like 'existing_node', but for edges. + * @param input_symbol Symbol that points to a VertexAccessor in the Frame + * that expansion should emanate from. + * @param existing_node If or not the node to be expanded is already present + * in the Frame and should just be checked for equality. + * @param existing_edge Same like `existing_node`, but for edges. */ - Expand(const NodeAtom *node_atom, const EdgeAtom *edge_atom, + Expand(Symbol node_symbol, Symbol edge_symbol, EdgeAtom::Direction direction, const std::shared_ptr<LogicalOperator> &input, Symbol input_symbol, bool existing_node, bool existing_edge, GraphView graph_view = GraphView::AS_IS); @@ -378,8 +381,9 @@ class Expand : public LogicalOperator { private: // info on what's getting expanded - const NodeAtom *node_atom_; - const EdgeAtom *edge_atom_; + const Symbol node_symbol_; + const Symbol edge_symbol_; + const EdgeAtom::Direction direction_; // the input op and the symbol under which the op's result // can be found in the frame diff --git a/src/query/plan/planner.cpp b/src/query/plan/planner.cpp index bc744a24f..cb673f934 100644 --- a/src/query/plan/planner.cpp +++ b/src/query/plan/planner.cpp @@ -793,7 +793,7 @@ LogicalOperator *PlanMatching(const Matching &matching, context.new_symbols.emplace_back(edge_symbol); } last_op = - new Expand(expansion.node2, expansion.edge, + new Expand(node_symbol, edge_symbol, expansion.edge->direction_, std::shared_ptr<LogicalOperator>(last_op), node1_symbol, existing_node, existing_edge, context.graph_view); if (!existing_edge) { diff --git a/tests/unit/query_plan_common.hpp b/tests/unit/query_plan_common.hpp index fa6bcfa22..e333cd15c 100644 --- a/tests/unit/query_plan_common.hpp +++ b/tests/unit/query_plan_common.hpp @@ -139,8 +139,9 @@ ExpandTuple MakeExpand(AstTreeStorage &storage, SymbolTable &symbol_table, auto node_sym = symbol_table.CreateSymbol(node_identifier, true); symbol_table[*node->identifier_] = node_sym; - auto op = std::make_shared<Expand>(node, edge, input, input_symbol, - existing_node, existing_edge, graph_view); + auto op = std::make_shared<Expand>(node_sym, edge_sym, direction, input, + input_symbol, existing_node, existing_edge, + graph_view); return ExpandTuple{edge, edge_sym, node, node_sym, op}; } diff --git a/tests/unit/query_plan_match_filter_return.cpp b/tests/unit/query_plan_match_filter_return.cpp index da1400c56..9f14bea86 100644 --- a/tests/unit/query_plan_match_filter_return.cpp +++ b/tests/unit/query_plan_match_filter_return.cpp @@ -409,12 +409,14 @@ TEST(QueryPlan, OptionalMatchThenExpandToMissingNode) { auto with = MakeProduce(optional, n_ne); // MATCH (m) -[r]-> (n) auto m = MakeScanAll(storage, symbol_table, "m", with); - auto edge = EDGE("r", EdgeAtom::Direction::RIGHT); - symbol_table[*edge->identifier_] = symbol_table.CreateSymbol("r", true); + auto edge_direction = EdgeAtom::Direction::RIGHT; + auto edge = EDGE("r", edge_direction); + auto edge_sym = symbol_table.CreateSymbol("r", true); + symbol_table[*edge->identifier_] = edge_sym; auto node = NODE("n"); symbol_table[*node->identifier_] = with_n_sym; - auto expand = - std::make_shared<plan::Expand>(node, edge, m.op_, m.sym_, true, false); + auto expand = std::make_shared<plan::Expand>( + with_n_sym, edge_sym, edge_direction, m.op_, m.sym_, true, false); // RETURN m auto m_ne = NEXPR("m", IDENT("m")); symbol_table[*m_ne->expression_] = m.sym_; @@ -452,17 +454,19 @@ TEST(QueryPlan, OptionalMatchThenExpandToMissingEdge) { // WITH r auto r_ne = NEXPR("r", IDENT("r")); symbol_table[*r_ne->expression_] = r_m.edge_sym_; - auto with_n_sym = symbol_table.CreateSymbol("r", true); - symbol_table[*r_ne] = with_n_sym; + auto with_r_sym = symbol_table.CreateSymbol("r", true); + symbol_table[*r_ne] = with_r_sym; auto with = MakeProduce(optional, r_ne); // MATCH (a) -[r]- (b) auto a = MakeScanAll(storage, symbol_table, "a", with); - auto edge = EDGE("r", EdgeAtom::Direction::BOTH); - symbol_table[*edge->identifier_] = r_m.edge_sym_; + auto edge_direction = EdgeAtom::Direction::BOTH; + auto edge = EDGE("r", edge_direction); + symbol_table[*edge->identifier_] = with_r_sym; auto node = NODE("n"); - symbol_table[*node->identifier_] = symbol_table.CreateSymbol("b", true); - auto expand = - std::make_shared<plan::Expand>(node, edge, a.op_, a.sym_, false, true); + auto node_sym = symbol_table.CreateSymbol("b", true); + symbol_table[*node->identifier_] = node_sym; + auto expand = std::make_shared<plan::Expand>( + node_sym, with_r_sym, edge_direction, a.op_, a.sym_, false, true); // RETURN a auto a_ne = NEXPR("a", IDENT("a")); symbol_table[*a_ne->expression_] = a.sym_; @@ -494,8 +498,9 @@ TEST(QueryPlan, ExpandExistingNode) { MakeExpand(storage, symbol_table, n.op_, n.sym_, "r", EdgeAtom::Direction::RIGHT, false, "n", with_existing); if (with_existing) - symbol_table[*r_n.node_->identifier_] = - symbol_table[*n.node_->identifier_]; + r_n.op_ = + std::make_shared<Expand>(n.sym_, r_n.edge_sym_, r_n.edge_->direction_, + n.op_, n.sym_, with_existing, false); // make a named expression and a produce auto output = NEXPR("n", IDENT("n")); @@ -538,8 +543,9 @@ TEST(QueryPlan, ExpandExistingEdge) { auto r_k = MakeExpand(storage, symbol_table, r_j.op_, r_j.node_sym_, "r", EdgeAtom::Direction::BOTH, with_existing, "k", false); if (with_existing) - symbol_table[*r_k.edge_->identifier_] = - symbol_table[*r_j.edge_->identifier_]; + r_k.op_ = std::make_shared<Expand>(r_k.node_sym_, r_j.edge_sym_, + r_k.edge_->direction_, r_j.op_, + r_j.node_sym_, false, with_existing); // make a named expression and a produce auto output = NEXPR("r", IDENT("r"));