diff --git a/src/query/frontend/ast/ast.hpp b/src/query/frontend/ast/ast.hpp index b98553051..b7105b9e3 100644 --- a/src/query/frontend/ast/ast.hpp +++ b/src/query/frontend/ast/ast.hpp @@ -427,12 +427,14 @@ class Function : public Expression { } } - std::function &)> function_; + std::function &, GraphDbAccessor &)> + function_; std::vector arguments_; protected: - Function(int uid, - std::function &)> function, + Function(int uid, std::function &, + GraphDbAccessor &)> + function, const std::vector &arguments) : Expression(uid), function_(function), arguments_(arguments) {} }; diff --git a/src/query/interpret/awesome_memgraph_functions.cpp b/src/query/interpret/awesome_memgraph_functions.cpp index 8021f089e..c744ffa30 100644 --- a/src/query/interpret/awesome_memgraph_functions.cpp +++ b/src/query/interpret/awesome_memgraph_functions.cpp @@ -8,7 +8,7 @@ namespace query { namespace { -TypedValue Abs(const std::vector &args) { +TypedValue Abs(const std::vector &args, GraphDbAccessor &) { if (args.size() != 1U) { throw QueryRuntimeException("ABS requires one argument"); } @@ -26,8 +26,8 @@ TypedValue Abs(const std::vector &args) { } } -std::function &)> NameToFunction( - const std::string &function_name) { +std::function &, GraphDbAccessor &)> +NameToFunction(const std::string &function_name) { if (function_name == "ABS") { return Abs; } diff --git a/src/query/interpret/awesome_memgraph_functions.hpp b/src/query/interpret/awesome_memgraph_functions.hpp index 7f5b28169..2744d16ec 100644 --- a/src/query/interpret/awesome_memgraph_functions.hpp +++ b/src/query/interpret/awesome_memgraph_functions.hpp @@ -2,10 +2,11 @@ #include +#include "database/graph_db_accessor.hpp" #include "query/typed_value.hpp" namespace query { -std::function &)> NameToFunction( - const std::string &function_name); +std::function &, GraphDbAccessor &)> +NameToFunction(const std::string &function_name); } diff --git a/src/query/interpret/eval.hpp b/src/query/interpret/eval.hpp index f06ee8617..3b305232f 100644 --- a/src/query/interpret/eval.hpp +++ b/src/query/interpret/eval.hpp @@ -3,6 +3,7 @@ #include #include +#include "database/graph_db_accessor.hpp" #include "query/frontend/ast/ast.hpp" #include "query/frontend/semantic/symbol_table.hpp" #include "query/interpret/frame.hpp" @@ -14,19 +15,22 @@ namespace query { class ExpressionEvaluator : public TreeVisitorBase { public: - ExpressionEvaluator(Frame &frame, const SymbolTable &symbol_table) - : frame_(frame), symbol_table_(symbol_table) {} + ExpressionEvaluator(Frame &frame, const SymbolTable &symbol_table, + GraphDbAccessor &db_accessor) + : frame_(frame), symbol_table_(symbol_table), db_accessor_(db_accessor) {} - /** When evaluting @c RecordAccessor, use @c SwitchNew to get the new data, as - * modified during the current command. + /** + * When evaluting @c RecordAccessor, use @c SwitchNew to get the new + * data, as modified during the current command. */ auto &SwitchNew() { use_new_ = true; return *this; }; - /** When evaluting @c RecordAccessor, use @c SwitchOld to get the old data, - * before the modification done by the current command. + /** + * When evaluting @c RecordAccessor, use @c SwitchOld to get the old + * data, before the modification done by the current command. */ auto &SwitchOld() { use_new_ = false; @@ -127,8 +131,8 @@ class ExpressionEvaluator : public TreeVisitorBase { } void Visit(Literal &literal) override { - // TODO: no need to evaluate constants, we can write it to frame in one of - // the previous phases. + // TODO: no need to evaluate constants, we can write it to frame in one + // of the previous phases. result_stack_.push_back(literal.value_); } @@ -148,7 +152,7 @@ class ExpressionEvaluator : public TreeVisitorBase { arguments.push_back(PopBack()); } reverse(arguments.begin(), arguments.end()); - result_stack_.emplace_back(function.function_(arguments)); + result_stack_.emplace_back(function.function_(arguments, db_accessor_)); } private: @@ -188,8 +192,10 @@ class ExpressionEvaluator : public TreeVisitorBase { Frame &frame_; const SymbolTable &symbol_table_; std::list result_stack_; - // If true, use SwitchNew on evaluated record accessors. This should be done - // only in expressions which may return one. E.g. identifier, list indexing. + // If true, use SwitchNew on evaluated record accessors. This should be + // done only in expressions which may return one. E.g. identifier, list + // indexing. bool use_new_ = false; + GraphDbAccessor &db_accessor_; }; } diff --git a/src/query/plan/operator.cpp b/src/query/plan/operator.cpp index 7d84dd601..0ee5a75e3 100644 --- a/src/query/plan/operator.cpp +++ b/src/query/plan/operator.cpp @@ -26,11 +26,11 @@ void Once::Accept(LogicalOperatorVisitor &visitor) { visitor.PostVisit(*this); } } -std::unique_ptr Once::MakeCursor(GraphDbAccessor &db) { +std::unique_ptr Once::MakeCursor(GraphDbAccessor &) { return std::make_unique(); } -bool Once::OnceCursor::Pull(Frame &frame, const SymbolTable &symbol_table) { +bool Once::OnceCursor::Pull(Frame &, const SymbolTable &) { if (!did_pull_) { did_pull_ = true; return true; @@ -70,7 +70,7 @@ void CreateNode::CreateNodeCursor::Create(Frame &frame, auto new_node = db_.insert_vertex(); for (auto label : self_.node_atom_->labels_) new_node.add_label(label); - ExpressionEvaluator evaluator(frame, symbol_table); + ExpressionEvaluator evaluator(frame, symbol_table, db_); // Evaluator should use the latest accessors, as modified in this query, when // setting properties on new nodes. evaluator.SwitchNew(); @@ -108,7 +108,7 @@ bool CreateExpand::CreateExpandCursor::Pull(Frame &frame, TypedValue &vertex_value = frame[self_.input_symbol_]; auto &v1 = vertex_value.Value(); - ExpressionEvaluator evaluator(frame, symbol_table); + ExpressionEvaluator evaluator(frame, symbol_table, db_); // Similarly to CreateNode, newly created edges and nodes should use the // latest accesors. // E.g. we pickup new properties: `CREATE (n {p: 42}) -[:r {ep: n.p}]-> ()` @@ -355,7 +355,7 @@ std::unique_ptr NodeFilter::MakeCursor(GraphDbAccessor &db) { NodeFilter::NodeFilterCursor::NodeFilterCursor(const NodeFilter &self, GraphDbAccessor &db) - : self_(self), input_cursor_(self_.input_->MakeCursor(db)) {} + : self_(self), db_(db), input_cursor_(self_.input_->MakeCursor(db)) {} bool NodeFilter::NodeFilterCursor::Pull(Frame &frame, const SymbolTable &symbol_table) { @@ -377,7 +377,7 @@ bool NodeFilter::NodeFilterCursor::VertexPasses( for (auto label : self_.node_atom_->labels_) if (!vertex.has_label(label)) return false; - ExpressionEvaluator expression_evaluator(frame, symbol_table); + ExpressionEvaluator expression_evaluator(frame, symbol_table, db_); // We don't want newly set properties to affect filtering. expression_evaluator.SwitchOld(); for (auto prop_pair : self_.node_atom_->properties_) { @@ -401,7 +401,7 @@ std::unique_ptr EdgeFilter::MakeCursor(GraphDbAccessor &db) { } EdgeFilter::EdgeFilterCursor::EdgeFilterCursor(const EdgeFilter &self, GraphDbAccessor &db) - : self_(self), input_cursor_(self_.input_->MakeCursor(db)) {} + : self_(self), db_(db), input_cursor_(self_.input_->MakeCursor(db)) {} bool EdgeFilter::EdgeFilterCursor::Pull(Frame &frame, const SymbolTable &symbol_table) { @@ -427,7 +427,7 @@ bool EdgeFilter::EdgeFilterCursor::EdgePasses(const EdgeAccessor &edge, [type](auto t) { return t == type; })) return false; - ExpressionEvaluator expression_evaluator(frame, symbol_table); + ExpressionEvaluator expression_evaluator(frame, symbol_table, db_); // We don't want newly set properties to affect filtering. expression_evaluator.SwitchOld(); for (auto prop_pair : self_.edge_atom_->properties_) { @@ -451,10 +451,10 @@ std::unique_ptr Filter::MakeCursor(GraphDbAccessor &db) { } Filter::FilterCursor::FilterCursor(const Filter &self, GraphDbAccessor &db) - : self_(self), input_cursor_(self_.input_->MakeCursor(db)) {} + : self_(self), db_(db), input_cursor_(self_.input_->MakeCursor(db)) {} bool Filter::FilterCursor::Pull(Frame &frame, const SymbolTable &symbol_table) { - ExpressionEvaluator evaluator(frame, symbol_table); + ExpressionEvaluator evaluator(frame, symbol_table, db_); // Like all filters, newly set values should not affect filtering of old nodes // and edges. evaluator.SwitchOld(); @@ -485,12 +485,12 @@ const std::vector &Produce::named_expressions() { } Produce::ProduceCursor::ProduceCursor(const Produce &self, GraphDbAccessor &db) - : self_(self), input_cursor_(self_.input_->MakeCursor(db)) {} + : self_(self), db_(db), input_cursor_(self_.input_->MakeCursor(db)) {} bool Produce::ProduceCursor::Pull(Frame &frame, const SymbolTable &symbol_table) { if (input_cursor_->Pull(frame, symbol_table)) { - ExpressionEvaluator evaluator(frame, symbol_table); + ExpressionEvaluator evaluator(frame, symbol_table, db_); // Produce should always yield the latest results. evaluator.SwitchNew(); for (auto named_expr : self_.named_expressions_) @@ -518,7 +518,7 @@ Delete::DeleteCursor::DeleteCursor(const Delete &self, GraphDbAccessor &db) bool Delete::DeleteCursor::Pull(Frame &frame, const SymbolTable &symbol_table) { if (!input_cursor_->Pull(frame, symbol_table)) return false; - ExpressionEvaluator evaluator(frame, symbol_table); + ExpressionEvaluator evaluator(frame, symbol_table, db_); // Delete should get the latest information, this way it is also possible to // delete newly added nodes and edges. evaluator.SwitchNew(); @@ -576,13 +576,13 @@ std::unique_ptr SetProperty::MakeCursor(GraphDbAccessor &db) { SetProperty::SetPropertyCursor::SetPropertyCursor(const SetProperty &self, GraphDbAccessor &db) - : self_(self), input_cursor_(self.input_->MakeCursor(db)) {} + : self_(self), db_(db), input_cursor_(self.input_->MakeCursor(db)) {} bool SetProperty::SetPropertyCursor::Pull(Frame &frame, const SymbolTable &symbol_table) { if (!input_cursor_->Pull(frame, symbol_table)) return false; - ExpressionEvaluator evaluator(frame, symbol_table); + ExpressionEvaluator evaluator(frame, symbol_table, db_); // Set, just like Create needs to see the latest changes. evaluator.SwitchNew(); self_.lhs_->expression_->Accept(evaluator); @@ -631,7 +631,7 @@ bool SetProperties::SetPropertiesCursor::Pull(Frame &frame, TypedValue &lhs = frame[self_.input_symbol_]; - ExpressionEvaluator evaluator(frame, symbol_table); + ExpressionEvaluator evaluator(frame, symbol_table, db_); // Set, just like Create needs to see the latest changes. evaluator.SwitchNew(); self_.rhs_->Accept(evaluator); @@ -732,13 +732,13 @@ std::unique_ptr RemoveProperty::MakeCursor(GraphDbAccessor &db) { RemoveProperty::RemovePropertyCursor::RemovePropertyCursor( const RemoveProperty &self, GraphDbAccessor &db) - : self_(self), input_cursor_(self.input_->MakeCursor(db)) {} + : self_(self), db_(db), input_cursor_(self.input_->MakeCursor(db)) {} bool RemoveProperty::RemovePropertyCursor::Pull( Frame &frame, const SymbolTable &symbol_table) { if (!input_cursor_->Pull(frame, symbol_table)) return false; - ExpressionEvaluator evaluator(frame, symbol_table); + ExpressionEvaluator evaluator(frame, symbol_table, db_); // Remove, just like Delete needs to see the latest changes. evaluator.SwitchNew(); self_.lhs_->expression_->Accept(evaluator); @@ -944,7 +944,7 @@ std::unique_ptr Aggregate::MakeCursor(GraphDbAccessor &db) { Aggregate::AggregateCursor::AggregateCursor(Aggregate &self, GraphDbAccessor &db) - : self_(self), input_cursor_(self_.input_->MakeCursor(db)) {} + : self_(self), db_(db), input_cursor_(self_.input_->MakeCursor(db)) {} bool Aggregate::AggregateCursor::Pull(Frame &frame, const SymbolTable &symbol_table) { @@ -972,7 +972,7 @@ bool Aggregate::AggregateCursor::Pull(Frame &frame, void Aggregate::AggregateCursor::ProcessAll(Frame &frame, const SymbolTable &symbol_table) { - ExpressionEvaluator evaluator(frame, symbol_table); + ExpressionEvaluator evaluator(frame, symbol_table, db_); evaluator.SwitchNew(); while (input_cursor_->Pull(frame, symbol_table)) ProcessOne(frame, symbol_table, evaluator); @@ -1149,14 +1149,14 @@ std::unique_ptr Skip::MakeCursor(GraphDbAccessor &db) { } Skip::SkipCursor::SkipCursor(Skip &self, GraphDbAccessor &db) - : self_(self), input_cursor_(self_.input_->MakeCursor(db)) {} + : self_(self), db_(db), input_cursor_(self_.input_->MakeCursor(db)) {} bool Skip::SkipCursor::Pull(Frame &frame, const SymbolTable &symbol_table) { while (input_cursor_->Pull(frame, symbol_table)) { if (to_skip_ == -1) { // first successful pull from the input // evaluate the skip expression - ExpressionEvaluator evaluator(frame, symbol_table); + ExpressionEvaluator evaluator(frame, symbol_table, db_); self_.expression_->Accept(evaluator); TypedValue to_skip = evaluator.PopBack(); if (to_skip.type() != TypedValue::Type::Int) @@ -1191,7 +1191,7 @@ std::unique_ptr Limit::MakeCursor(GraphDbAccessor &db) { } Limit::LimitCursor::LimitCursor(Limit &self, GraphDbAccessor &db) - : self_(self), input_cursor_(self_.input_->MakeCursor(db)) {} + : self_(self), db_(db), input_cursor_(self_.input_->MakeCursor(db)) {} bool Limit::LimitCursor::Pull(Frame &frame, const SymbolTable &symbol_table) { // we need to evaluate the limit expression before the first input Pull @@ -1199,7 +1199,7 @@ bool Limit::LimitCursor::Pull(Frame &frame, const SymbolTable &symbol_table) { // we can do this before Pulling from the input because the limit expression // is not allowed to contain any identifiers if (limit_ == -1) { - ExpressionEvaluator evaluator(frame, symbol_table); + ExpressionEvaluator evaluator(frame, symbol_table, db_); self_.expression_->Accept(evaluator); TypedValue limit = evaluator.PopBack(); if (limit.type() != TypedValue::Type::Int) @@ -1245,12 +1245,12 @@ std::unique_ptr OrderBy::MakeCursor(GraphDbAccessor &db) { } OrderBy::OrderByCursor::OrderByCursor(OrderBy &self, GraphDbAccessor &db) - : self_(self), input_cursor_(self_.input_->MakeCursor(db)) {} + : self_(self), db_(db), input_cursor_(self_.input_->MakeCursor(db)) {} bool OrderBy::OrderByCursor::Pull(Frame &frame, const SymbolTable &symbol_table) { if (!did_pull_all_) { - ExpressionEvaluator evaluator(frame, symbol_table); + ExpressionEvaluator evaluator(frame, symbol_table, db_); while (input_cursor_->Pull(frame, symbol_table)) { // collect the order_by elements std::list order_by; diff --git a/src/query/plan/operator.hpp b/src/query/plan/operator.hpp index eaa1effc0..b7df641d3 100644 --- a/src/query/plan/operator.hpp +++ b/src/query/plan/operator.hpp @@ -420,6 +420,7 @@ class NodeFilter : public LogicalOperator { private: const NodeFilter &self_; + GraphDbAccessor &db_; const std::unique_ptr input_cursor_; /** Helper function for checking if the given vertex @@ -460,6 +461,7 @@ class EdgeFilter : public LogicalOperator { private: const EdgeFilter &self_; + GraphDbAccessor &db_; const std::unique_ptr input_cursor_; /** Helper function for checking if the given edge satisfied @@ -495,6 +497,7 @@ class Filter : public LogicalOperator { private: const Filter &self_; + GraphDbAccessor &db_; const std::unique_ptr input_cursor_; }; }; @@ -530,6 +533,7 @@ class Produce : public LogicalOperator { private: const Produce &self_; + GraphDbAccessor &db_; const std::unique_ptr input_cursor_; }; }; @@ -594,6 +598,7 @@ class SetProperty : public LogicalOperator { private: const SetProperty &self_; + GraphDbAccessor &db_; const std::unique_ptr input_cursor_; }; }; @@ -704,6 +709,7 @@ class RemoveProperty : public LogicalOperator { private: const RemoveProperty &self_; + GraphDbAccessor &db_; const std::unique_ptr input_cursor_; }; }; @@ -909,6 +915,7 @@ class Aggregate : public LogicalOperator { }; const Aggregate &self_; + GraphDbAccessor &db_; const std::unique_ptr input_cursor_; // storage for aggregated data // map key is the list of group-by values @@ -994,6 +1001,7 @@ class Skip : public LogicalOperator { private: const Skip &self_; + GraphDbAccessor &db_; const std::unique_ptr input_cursor_; // init to_skip_ to -1, indicating // that it's still unknown (input has not been Pulled yet) @@ -1035,6 +1043,7 @@ class Limit : public LogicalOperator { private: Limit &self_; + GraphDbAccessor &db_; std::unique_ptr input_cursor_; // init limit_ to -1, indicating // that it's still unknown (Cursor has not been Pulled yet) @@ -1099,6 +1108,7 @@ class OrderBy : public LogicalOperator { private: const OrderBy &self_; + GraphDbAccessor &db_; const std::unique_ptr input_cursor_; bool did_pull_all_{false}; // a cache of elements pulled from the input diff --git a/tests/unit/cypher_main_visitor.cpp b/tests/unit/cypher_main_visitor.cpp index 7e97a2ae3..a32eb5a29 100644 --- a/tests/unit/cypher_main_visitor.cpp +++ b/tests/unit/cypher_main_visitor.cpp @@ -424,9 +424,6 @@ TEST(CypherMainVisitorTest, Function) { return_clause->body_.named_expressions[0]->expression_); ASSERT_TRUE(function); ASSERT_TRUE(function->function_); - // Check if function is abs. - ASSERT_EQ(function->function_({-2}).Value(), 2); - ASSERT_EQ(function->arguments_.size(), 2); } TEST(CypherMainVisitorTest, StringLiteralDoubleQuotes) { diff --git a/tests/unit/query_expression_evaluator.cpp b/tests/unit/query_expression_evaluator.cpp index ba8888c2c..e83990ef9 100644 --- a/tests/unit/query_expression_evaluator.cpp +++ b/tests/unit/query_expression_evaluator.cpp @@ -10,6 +10,8 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "database/graph_db_accessor.hpp" +#include "dbms/dbms.hpp" #include "query/frontend/ast/ast.hpp" #include "query/frontend/opencypher/parser.hpp" #include "query/interpret/awesome_memgraph_functions.hpp" @@ -21,7 +23,9 @@ struct NoContextExpressionEvaluator { NoContextExpressionEvaluator() {} Frame frame{0}; SymbolTable symbol_table; - ExpressionEvaluator eval{frame, symbol_table}; + Dbms dbms; + std::unique_ptr dba = dbms.active(); + ExpressionEvaluator eval{frame, symbol_table, *dba}; }; TEST(ExpressionEvaluator, OrOperator) { @@ -290,7 +294,9 @@ TEST(ExpressionEvaluator, Aggregation) { symbol_table[*aggr] = aggr_sym; Frame frame{symbol_table.max_position()}; frame[aggr_sym] = TypedValue(1); - ExpressionEvaluator eval{frame, symbol_table}; + Dbms dbms; + auto dba = dbms.active(); + ExpressionEvaluator eval{frame, symbol_table, *dba}; aggr->Accept(eval); EXPECT_EQ(eval.PopBack().Value(), 1); }