Add db_accessor to ExpressionEvaluator

Summary: Add db_accessor to ExpressionEvaluator

Reviewers: florijan, teon.banek

Reviewed By: teon.banek

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D310
This commit is contained in:
Mislav Bradac 2017-04-24 14:37:18 +02:00
parent d29a1f5353
commit fe36835519
8 changed files with 72 additions and 50 deletions

View File

@ -427,12 +427,14 @@ class Function : public Expression {
}
}
std::function<TypedValue(const std::vector<TypedValue> &)> function_;
std::function<TypedValue(const std::vector<TypedValue> &, GraphDbAccessor &)>
function_;
std::vector<Expression *> arguments_;
protected:
Function(int uid,
std::function<TypedValue(const std::vector<TypedValue> &)> function,
Function(int uid, std::function<TypedValue(const std::vector<TypedValue> &,
GraphDbAccessor &)>
function,
const std::vector<Expression *> &arguments)
: Expression(uid), function_(function), arguments_(arguments) {}
};

View File

@ -8,7 +8,7 @@
namespace query {
namespace {
TypedValue Abs(const std::vector<TypedValue> &args) {
TypedValue Abs(const std::vector<TypedValue> &args, GraphDbAccessor &) {
if (args.size() != 1U) {
throw QueryRuntimeException("ABS requires one argument");
}
@ -26,8 +26,8 @@ TypedValue Abs(const std::vector<TypedValue> &args) {
}
}
std::function<TypedValue(const std::vector<TypedValue> &)> NameToFunction(
const std::string &function_name) {
std::function<TypedValue(const std::vector<TypedValue> &, GraphDbAccessor &)>
NameToFunction(const std::string &function_name) {
if (function_name == "ABS") {
return Abs;
}

View File

@ -2,10 +2,11 @@
#include <vector>
#include "database/graph_db_accessor.hpp"
#include "query/typed_value.hpp"
namespace query {
std::function<TypedValue(const std::vector<TypedValue> &)> NameToFunction(
const std::string &function_name);
std::function<TypedValue(const std::vector<TypedValue> &, GraphDbAccessor &)>
NameToFunction(const std::string &function_name);
}

View File

@ -3,6 +3,7 @@
#include <map>
#include <vector>
#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<TypedValue> 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_;
};
}

View File

@ -26,11 +26,11 @@ void Once::Accept(LogicalOperatorVisitor &visitor) {
visitor.PostVisit(*this);
}
}
std::unique_ptr<Cursor> Once::MakeCursor(GraphDbAccessor &db) {
std::unique_ptr<Cursor> Once::MakeCursor(GraphDbAccessor &) {
return std::make_unique<OnceCursor>();
}
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<VertexAccessor>();
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<Cursor> 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<Cursor> 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<Cursor> 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<NamedExpression *> &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<Cursor> 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<Cursor> 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<Cursor> 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<Cursor> 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<Cursor> 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<Cursor> 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<TypedValue> order_by;

View File

@ -420,6 +420,7 @@ class NodeFilter : public LogicalOperator {
private:
const NodeFilter &self_;
GraphDbAccessor &db_;
const std::unique_ptr<Cursor> 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<Cursor> 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<Cursor> input_cursor_;
};
};
@ -530,6 +533,7 @@ class Produce : public LogicalOperator {
private:
const Produce &self_;
GraphDbAccessor &db_;
const std::unique_ptr<Cursor> input_cursor_;
};
};
@ -594,6 +598,7 @@ class SetProperty : public LogicalOperator {
private:
const SetProperty &self_;
GraphDbAccessor &db_;
const std::unique_ptr<Cursor> input_cursor_;
};
};
@ -704,6 +709,7 @@ class RemoveProperty : public LogicalOperator {
private:
const RemoveProperty &self_;
GraphDbAccessor &db_;
const std::unique_ptr<Cursor> input_cursor_;
};
};
@ -909,6 +915,7 @@ class Aggregate : public LogicalOperator {
};
const Aggregate &self_;
GraphDbAccessor &db_;
const std::unique_ptr<Cursor> 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<Cursor> 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<Cursor> 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<Cursor> input_cursor_;
bool did_pull_all_{false};
// a cache of elements pulled from the input

View File

@ -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<int64_t>(), 2);
ASSERT_EQ(function->arguments_.size(), 2);
}
TEST(CypherMainVisitorTest, StringLiteralDoubleQuotes) {

View File

@ -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<GraphDbAccessor> 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<int64_t>(), 1);
}