Make ExpressionEvaluator take only EvaluationContext

Reviewers: teon.banek

Reviewed By: teon.banek

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D1590
This commit is contained in:
Marin Tomic 2018-09-04 18:02:30 +02:00
parent ba3837e942
commit e5a7f51740
11 changed files with 911 additions and 937 deletions

View File

@ -21,7 +21,7 @@ ProduceRpcServer::OngoingProduce::OngoingProduce(
cursor_(op->MakeCursor(*dba_)) {
context_.symbol_table_ = std::move(symbol_table);
context_.parameters_ = std::move(parameters);
context_.timestamp_ = timestamp;
context_.evaluation_context_.timestamp = timestamp;
}
std::pair<std::vector<query::TypedValue>, PullState>

View File

@ -15,6 +15,10 @@ class Streams;
namespace query {
struct EvaluationContext {
int64_t timestamp{-1};
};
class Context {
public:
// Since we also return some information from context (is_index_created_) we
@ -27,11 +31,11 @@ class Context {
explicit Context(database::GraphDbAccessor &db_accessor)
: db_accessor_(db_accessor) {}
database::GraphDbAccessor &db_accessor_;
SymbolTable symbol_table_;
Parameters parameters_;
bool in_explicit_transaction_ = false;
bool is_index_created_ = false;
int64_t timestamp_{-1};
SymbolTable symbol_table_;
Parameters parameters_;
EvaluationContext evaluation_context_;
auth::Auth *auth_ = nullptr;
integrations::kafka::Streams *kafka_streams_ = nullptr;

View File

@ -1013,7 +1013,9 @@ class Function : public Expression {
private:
std::string function_name_;
std::function<TypedValue(TypedValue *, int64_t, Context *)> function_;
std::function<TypedValue(TypedValue *, int64_t, const EvaluationContext &,
database::GraphDbAccessor *)>
function_;
};
class Aggregation : public BinaryOperator {

View File

@ -32,7 +32,8 @@ namespace {
// TODO: Implement degrees, haversin, radians
// TODO: Implement spatial functions
TypedValue Coalesce(TypedValue *args, int64_t nargs, Context *) {
TypedValue Coalesce(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *) {
// TODO: Perhaps this function should be done by the evaluator itself, so as
// to avoid evaluating all the arguments.
if (nargs == 0) {
@ -46,7 +47,8 @@ TypedValue Coalesce(TypedValue *args, int64_t nargs, Context *) {
return TypedValue::Null;
}
TypedValue EndNode(TypedValue *args, int64_t nargs, Context *) {
TypedValue EndNode(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *) {
if (nargs != 1) {
throw QueryRuntimeException("'endNode' requires exactly one argument.");
}
@ -60,7 +62,8 @@ TypedValue EndNode(TypedValue *args, int64_t nargs, Context *) {
}
}
TypedValue Head(TypedValue *args, int64_t nargs, Context *) {
TypedValue Head(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *) {
if (nargs != 1) {
throw QueryRuntimeException("'head' requires exactly one argument.");
}
@ -77,7 +80,8 @@ TypedValue Head(TypedValue *args, int64_t nargs, Context *) {
}
}
TypedValue Last(TypedValue *args, int64_t nargs, Context *) {
TypedValue Last(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *) {
if (nargs != 1) {
throw QueryRuntimeException("'last' requires exactly one argument.");
}
@ -94,15 +98,16 @@ TypedValue Last(TypedValue *args, int64_t nargs, Context *) {
}
}
TypedValue Properties(TypedValue *args, int64_t nargs, Context *ctx) {
TypedValue Properties(TypedValue *args, int64_t nargs,
const EvaluationContext &,
database::GraphDbAccessor *dba) {
if (nargs != 1) {
throw QueryRuntimeException("'properties' requires exactly one argument.");
}
auto get_properties = [&](const auto &record_accessor) {
std::map<std::string, TypedValue> properties;
for (const auto &property : record_accessor.Properties()) {
properties[ctx->db_accessor_.PropertyName(property.first)] =
property.second;
properties[dba->PropertyName(property.first)] = property.second;
}
return properties;
};
@ -119,7 +124,8 @@ TypedValue Properties(TypedValue *args, int64_t nargs, Context *ctx) {
}
}
TypedValue Size(TypedValue *args, int64_t nargs, Context *) {
TypedValue Size(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *) {
if (nargs != 1) {
throw QueryRuntimeException("'size' requires exactly one argument.");
}
@ -144,7 +150,8 @@ TypedValue Size(TypedValue *args, int64_t nargs, Context *) {
}
}
TypedValue StartNode(TypedValue *args, int64_t nargs, Context *) {
TypedValue StartNode(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *) {
if (nargs != 1) {
throw QueryRuntimeException("'startNode' requires exactly one argument.");
}
@ -158,7 +165,8 @@ TypedValue StartNode(TypedValue *args, int64_t nargs, Context *) {
}
}
TypedValue Degree(TypedValue *args, int64_t nargs, Context *) {
TypedValue Degree(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *) {
if (nargs != 1) {
throw QueryRuntimeException("'degree' requires exactly one argument.");
}
@ -174,7 +182,8 @@ TypedValue Degree(TypedValue *args, int64_t nargs, Context *) {
}
}
TypedValue ToBoolean(TypedValue *args, int64_t nargs, Context *) {
TypedValue ToBoolean(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *) {
if (nargs != 1) {
throw QueryRuntimeException("'toBoolean' requires exactly one argument.");
}
@ -199,7 +208,8 @@ TypedValue ToBoolean(TypedValue *args, int64_t nargs, Context *) {
}
}
TypedValue ToFloat(TypedValue *args, int64_t nargs, Context *) {
TypedValue ToFloat(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *) {
if (nargs != 1) {
throw QueryRuntimeException("'toFloat' requires exactly one argument.");
}
@ -222,7 +232,8 @@ TypedValue ToFloat(TypedValue *args, int64_t nargs, Context *) {
}
}
TypedValue ToInteger(TypedValue *args, int64_t nargs, Context *) {
TypedValue ToInteger(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *) {
if (nargs != 1) {
throw QueryRuntimeException("'toInteger' requires exactly one argument'");
}
@ -250,7 +261,8 @@ TypedValue ToInteger(TypedValue *args, int64_t nargs, Context *) {
}
}
TypedValue Type(TypedValue *args, int64_t nargs, Context *ctx) {
TypedValue Type(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *dba) {
if (nargs != 1) {
throw QueryRuntimeException("'type' requires exactly one argument.");
}
@ -258,21 +270,21 @@ TypedValue Type(TypedValue *args, int64_t nargs, Context *ctx) {
case TypedValue::Type::Null:
return TypedValue::Null;
case TypedValue::Type::Edge:
return ctx->db_accessor_.EdgeTypeName(
args[0].Value<EdgeAccessor>().EdgeType());
return dba->EdgeTypeName(args[0].Value<EdgeAccessor>().EdgeType());
default:
throw QueryRuntimeException("'type' argument must be an edge.");
}
}
TypedValue Keys(TypedValue *args, int64_t nargs, Context *ctx) {
TypedValue Keys(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *dba) {
if (nargs != 1) {
throw QueryRuntimeException("'keys' requires exactly one argument.");
}
auto get_keys = [&](const auto &record_accessor) {
std::vector<TypedValue> keys;
for (const auto &property : record_accessor.Properties()) {
keys.push_back(ctx->db_accessor_.PropertyName(property.first));
keys.push_back(dba->PropertyName(property.first));
}
return keys;
};
@ -288,7 +300,8 @@ TypedValue Keys(TypedValue *args, int64_t nargs, Context *ctx) {
}
}
TypedValue Labels(TypedValue *args, int64_t nargs, Context *ctx) {
TypedValue Labels(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *dba) {
if (nargs != 1) {
throw QueryRuntimeException("'labels' requires exactly one argument.");
}
@ -298,7 +311,7 @@ TypedValue Labels(TypedValue *args, int64_t nargs, Context *ctx) {
case TypedValue::Type::Vertex: {
std::vector<TypedValue> labels;
for (const auto &label : args[0].Value<VertexAccessor>().labels()) {
labels.push_back(ctx->db_accessor_.LabelName(label));
labels.push_back(dba->LabelName(label));
}
return labels;
}
@ -307,7 +320,8 @@ TypedValue Labels(TypedValue *args, int64_t nargs, Context *ctx) {
}
}
TypedValue Nodes(TypedValue *args, int64_t nargs, Context *) {
TypedValue Nodes(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *) {
if (nargs != 1) {
throw QueryRuntimeException("'nodes' requires exactly one argument.");
}
@ -319,7 +333,9 @@ TypedValue Nodes(TypedValue *args, int64_t nargs, Context *) {
return std::vector<TypedValue>(vertices.begin(), vertices.end());
}
TypedValue Relationships(TypedValue *args, int64_t nargs, Context *) {
TypedValue Relationships(TypedValue *args, int64_t nargs,
const EvaluationContext &,
database::GraphDbAccessor *) {
if (nargs != 1) {
throw QueryRuntimeException(
"'relationships' requires exactly one argument.");
@ -332,7 +348,8 @@ TypedValue Relationships(TypedValue *args, int64_t nargs, Context *) {
return std::vector<TypedValue>(edges.begin(), edges.end());
}
TypedValue Range(TypedValue *args, int64_t nargs, Context *) {
TypedValue Range(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *) {
if (nargs != 2 && nargs != 3) {
throw QueryRuntimeException("'range' requires two or three arguments.");
}
@ -365,7 +382,8 @@ TypedValue Range(TypedValue *args, int64_t nargs, Context *) {
return list;
}
TypedValue Tail(TypedValue *args, int64_t nargs, Context *) {
TypedValue Tail(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *) {
if (nargs != 1) {
throw QueryRuntimeException("'tail' requires exactly one argument.");
}
@ -383,7 +401,8 @@ TypedValue Tail(TypedValue *args, int64_t nargs, Context *) {
}
}
TypedValue Abs(TypedValue *args, int64_t nargs, Context *) {
TypedValue Abs(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *) {
if (nargs != 1) {
throw QueryRuntimeException("'abs' requires exactly one argument.");
}
@ -400,23 +419,24 @@ TypedValue Abs(TypedValue *args, int64_t nargs, Context *) {
}
}
#define WRAP_CMATH_FLOAT_FUNCTION(name, lowercased_name) \
TypedValue name(TypedValue *args, int64_t nargs, Context *) { \
if (nargs != 1) { \
throw QueryRuntimeException("'" #lowercased_name \
"' requires exactly one argument."); \
} \
switch (args[0].type()) { \
case TypedValue::Type::Null: \
return TypedValue::Null; \
case TypedValue::Type::Int: \
return lowercased_name(args[0].Value<int64_t>()); \
case TypedValue::Type::Double: \
return lowercased_name(args[0].Value<double>()); \
default: \
throw QueryRuntimeException(#lowercased_name \
" argument must be a number."); \
} \
#define WRAP_CMATH_FLOAT_FUNCTION(name, lowercased_name) \
TypedValue name(TypedValue *args, int64_t nargs, const EvaluationContext &, \
database::GraphDbAccessor *) { \
if (nargs != 1) { \
throw QueryRuntimeException("'" #lowercased_name \
"' requires exactly one argument."); \
} \
switch (args[0].type()) { \
case TypedValue::Type::Null: \
return TypedValue::Null; \
case TypedValue::Type::Int: \
return lowercased_name(args[0].Value<int64_t>()); \
case TypedValue::Type::Double: \
return lowercased_name(args[0].Value<double>()); \
default: \
throw QueryRuntimeException(#lowercased_name \
" argument must be a number."); \
} \
}
WRAP_CMATH_FLOAT_FUNCTION(Ceil, ceil)
@ -437,7 +457,8 @@ WRAP_CMATH_FLOAT_FUNCTION(Tan, tan)
#undef WRAP_CMATH_FLOAT_FUNCTION
TypedValue Atan2(TypedValue *args, int64_t nargs, Context *) {
TypedValue Atan2(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *) {
if (nargs != 2) {
throw QueryRuntimeException("'atan2' requires two arguments.");
}
@ -458,7 +479,8 @@ TypedValue Atan2(TypedValue *args, int64_t nargs, Context *) {
return atan2(y, x);
}
TypedValue Sign(TypedValue *args, int64_t nargs, Context *) {
TypedValue Sign(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *) {
if (nargs != 1) {
throw QueryRuntimeException("'sign' requires exactly one argument.");
}
@ -475,21 +497,24 @@ TypedValue Sign(TypedValue *args, int64_t nargs, Context *) {
}
}
TypedValue E(TypedValue *, int64_t nargs, Context *) {
TypedValue E(TypedValue *, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *) {
if (nargs != 0) {
throw QueryRuntimeException("'e' requires no arguments.");
}
return M_E;
}
TypedValue Pi(TypedValue *, int64_t nargs, Context *) {
TypedValue Pi(TypedValue *, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *) {
if (nargs != 0) {
throw QueryRuntimeException("'pi' requires no arguments.");
}
return M_PI;
}
TypedValue Rand(TypedValue *, int64_t nargs, Context *) {
TypedValue Rand(TypedValue *, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *) {
static thread_local std::mt19937 pseudo_rand_gen_{std::random_device{}()};
static thread_local std::uniform_real_distribution<> rand_dist_{0, 1};
if (nargs != 0) {
@ -499,7 +524,9 @@ TypedValue Rand(TypedValue *, int64_t nargs, Context *) {
}
template <bool (*Predicate)(const std::string &s1, const std::string &s2)>
TypedValue StringMatchOperator(TypedValue *args, int64_t nargs, Context *) {
TypedValue StringMatchOperator(TypedValue *args, int64_t nargs,
const EvaluationContext &,
database::GraphDbAccessor *) {
if (nargs != 2) {
throw QueryRuntimeException(
"'startsWith' and 'endsWith' require two arguments.");
@ -542,7 +569,8 @@ bool ContainsPredicate(const std::string &s1, const std::string &s2) {
}
auto Contains = StringMatchOperator<ContainsPredicate>;
TypedValue Assert(TypedValue *args, int64_t nargs, Context *) {
TypedValue Assert(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *) {
if (nargs < 1 || nargs > 2) {
throw QueryRuntimeException("'assert' requires one or two arguments");
}
@ -561,17 +589,20 @@ TypedValue Assert(TypedValue *args, int64_t nargs, Context *) {
return args[0];
}
TypedValue Counter(TypedValue *args, int64_t nargs, Context *ctx) {
TypedValue Counter(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *dba) {
if (nargs != 1) {
throw QueryRuntimeException("'counter' requires exactly one argument.");
}
if (!args[0].IsString())
throw QueryRuntimeException("'counter' argument must be a string.");
return ctx->db_accessor_.Counter(args[0].ValueString());
return dba->Counter(args[0].ValueString());
}
TypedValue CounterSet(TypedValue *args, int64_t nargs, Context *ctx) {
TypedValue CounterSet(TypedValue *args, int64_t nargs,
const EvaluationContext &,
database::GraphDbAccessor *dba) {
if (nargs != 2) {
throw QueryRuntimeException("'counterSet' requires two arguments.");
}
@ -581,19 +612,21 @@ TypedValue CounterSet(TypedValue *args, int64_t nargs, Context *ctx) {
if (!args[1].IsInt())
throw QueryRuntimeException(
"Second argument of 'counterSet' must be an integer.");
ctx->db_accessor_.CounterSet(args[0].ValueString(), args[1].ValueInt());
dba->CounterSet(args[0].ValueString(), args[1].ValueInt());
return TypedValue::Null;
}
TypedValue IndexInfo(TypedValue *, int64_t nargs, Context *ctx) {
TypedValue IndexInfo(TypedValue *, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *dba) {
if (nargs != 0)
throw QueryRuntimeException("'indexInfo' requires no arguments.");
auto info = ctx->db_accessor_.IndexInfo();
auto info = dba->IndexInfo();
return std::vector<TypedValue>(info.begin(), info.end());
}
TypedValue WorkerId(TypedValue *args, int64_t nargs, Context *) {
TypedValue WorkerId(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *) {
if (nargs != 1) {
throw QueryRuntimeException("'workerId' requires exactly one argument.");
}
@ -609,7 +642,8 @@ TypedValue WorkerId(TypedValue *args, int64_t nargs, Context *) {
}
}
TypedValue Id(TypedValue *args, int64_t nargs, Context *ctx) {
TypedValue Id(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *dba) {
if (nargs != 1) {
throw QueryRuntimeException("'id' requires exactly one argument.");
}
@ -626,7 +660,8 @@ TypedValue Id(TypedValue *args, int64_t nargs, Context *ctx) {
}
}
TypedValue ToString(TypedValue *args, int64_t nargs, Context *) {
TypedValue ToString(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *) {
if (nargs != 1) {
throw QueryRuntimeException("'toString' requires exactly one argument.");
}
@ -648,14 +683,16 @@ TypedValue ToString(TypedValue *args, int64_t nargs, Context *) {
}
}
TypedValue Timestamp(TypedValue *, int64_t nargs, Context *ctx) {
TypedValue Timestamp(TypedValue *, int64_t nargs, const EvaluationContext &ctx,
database::GraphDbAccessor *) {
if (nargs != 0) {
throw QueryRuntimeException("'timestamp' requires no arguments.");
}
return ctx->timestamp_;
return ctx.timestamp;
}
TypedValue Left(TypedValue *args, int64_t nargs, Context *ctx) {
TypedValue Left(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *dba) {
if (nargs != 2) {
throw QueryRuntimeException("'left' requires two arguments.");
}
@ -677,7 +714,8 @@ TypedValue Left(TypedValue *args, int64_t nargs, Context *ctx) {
}
}
TypedValue Right(TypedValue *args, int64_t nargs, Context *ctx) {
TypedValue Right(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *dba) {
if (nargs != 2) {
throw QueryRuntimeException("'right' requires two arguments.");
}
@ -703,21 +741,22 @@ TypedValue Right(TypedValue *args, int64_t nargs, Context *ctx) {
}
}
#define WRAP_STRING_FUNCTION(name, lowercased_name, function) \
TypedValue name(TypedValue *args, int64_t nargs, Context *) { \
if (nargs != 1) { \
throw QueryRuntimeException("'" #lowercased_name \
"' requires exactly one argument."); \
} \
switch (args[0].type()) { \
case TypedValue::Type::Null: \
return TypedValue::Null; \
case TypedValue::Type::String: \
return function(args[0].ValueString()); \
default: \
throw QueryRuntimeException("'" #lowercased_name \
"' argument should be a string."); \
} \
#define WRAP_STRING_FUNCTION(name, lowercased_name, function) \
TypedValue name(TypedValue *args, int64_t nargs, const EvaluationContext &, \
database::GraphDbAccessor *) { \
if (nargs != 1) { \
throw QueryRuntimeException("'" #lowercased_name \
"' requires exactly one argument."); \
} \
switch (args[0].type()) { \
case TypedValue::Type::Null: \
return TypedValue::Null; \
case TypedValue::Type::String: \
return function(args[0].ValueString()); \
default: \
throw QueryRuntimeException("'" #lowercased_name \
"' argument should be a string."); \
} \
}
WRAP_STRING_FUNCTION(LTrim, lTrim, utils::LTrim);
@ -727,7 +766,8 @@ WRAP_STRING_FUNCTION(Reverse, reverse, utils::Reversed);
WRAP_STRING_FUNCTION(ToLower, toLower, utils::ToLowerCase);
WRAP_STRING_FUNCTION(ToUpper, toUpper, utils::ToUpperCase);
TypedValue Replace(TypedValue *args, int64_t nargs, Context *ctx) {
TypedValue Replace(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *dba) {
if (nargs != 3) {
throw QueryRuntimeException("'replace' requires three arguments.");
}
@ -750,7 +790,8 @@ TypedValue Replace(TypedValue *args, int64_t nargs, Context *ctx) {
args[2].ValueString());
}
TypedValue Split(TypedValue *args, int64_t nargs, Context *ctx) {
TypedValue Split(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *dba) {
if (nargs != 2) {
throw QueryRuntimeException("'split' requires two arguments.");
}
@ -773,7 +814,8 @@ TypedValue Split(TypedValue *args, int64_t nargs, Context *ctx) {
return result;
}
TypedValue Substring(TypedValue *args, int64_t nargs, Context *) {
TypedValue Substring(TypedValue *args, int64_t nargs, const EvaluationContext &,
database::GraphDbAccessor *) {
if (nargs != 2 && nargs != 3) {
throw QueryRuntimeException("'substring' requires two or three arguments.");
}
@ -803,7 +845,8 @@ TypedValue Substring(TypedValue *args, int64_t nargs, Context *) {
} // namespace
std::function<TypedValue(TypedValue *, int64_t, Context *)>
std::function<TypedValue(TypedValue *, int64_t, const EvaluationContext &,
database::GraphDbAccessor *)>
NameToFunction(const std::string &function_name) {
// Scalar functions
if (function_name == "COALESCE") return Coalesce;

View File

@ -7,7 +7,7 @@
namespace query {
class Context;
struct EvaluationContext;
namespace {
const char kStartsWith[] = "STARTSWITH";
@ -22,7 +22,8 @@ const char kContains[] = "CONTAINS";
/// contiguous in memory. Since most functions don't take many arguments, it's
/// convenient to have them stored in the calling stack frame.
std::function<TypedValue(TypedValue *arguments, int64_t num_arguments,
Context *context)>
const EvaluationContext &context,
database::GraphDbAccessor *)>
NameToFunction(const std::string &function_name);
} // namespace query

View File

@ -21,8 +21,16 @@ namespace query {
class ExpressionEvaluator : public TreeVisitor<TypedValue> {
public:
ExpressionEvaluator(Frame &frame, Context *context, GraphView graph_view)
: frame_(frame), context_(context), graph_view_(graph_view) {}
ExpressionEvaluator(Frame *frame, const SymbolTable &symbol_table,
const Parameters &parameters,
const EvaluationContext &ctx,
database::GraphDbAccessor *dba, GraphView graph_view)
: frame_(frame),
symbol_table_(&symbol_table),
parameters_(&parameters),
ctx_(&ctx),
dba_(dba),
graph_view_(graph_view) {}
using TreeVisitor<TypedValue>::Visit;
@ -62,14 +70,14 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
#undef BLOCK_VISIT
TypedValue Visit(NamedExpression &named_expression) override {
const auto &symbol = context_->symbol_table_.at(named_expression);
const auto &symbol = symbol_table_->at(named_expression);
auto value = named_expression.expression_->Accept(*this);
frame_[symbol] = value;
frame_->at(symbol) = value;
return value;
}
TypedValue Visit(Identifier &ident) override {
auto value = frame_[context_->symbol_table_.at(ident)];
auto value = frame_->at(symbol_table_->at(ident));
SwitchAccessors(value);
return value;
}
@ -223,7 +231,7 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
throw QueryRuntimeException(
"Expected a string as a property name, got {}.", index.type());
return lhs.Value<VertexAccessor>().PropsAt(
context_->db_accessor_.Property(index.Value<std::string>()));
dba_->Property(index.Value<std::string>()));
}
if (lhs.IsEdge()) {
@ -231,7 +239,7 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
throw QueryRuntimeException(
"Expected a string as a property name, got {}.", index.type());
return lhs.Value<EdgeAccessor>().PropsAt(
context_->db_accessor_.Property(index.Value<std::string>()));
dba_->Property(index.Value<std::string>()));
}
// lhs is Null
@ -358,7 +366,7 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
}
TypedValue Visit(Aggregation &aggregation) override {
auto value = frame_[context_->symbol_table_.at(aggregation)];
auto value = frame_->at(symbol_table_->at(aggregation));
// Aggregation is probably always simple type, but let's switch accessor
// just to be sure.
SwitchAccessors(value);
@ -372,15 +380,16 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
for (size_t i = 0; i < function.arguments_.size(); ++i) {
arguments[i] = function.arguments_[i]->Accept(*this);
}
return function.function()(arguments, function.arguments_.size(),
context_);
return function.function()(arguments, function.arguments_.size(), *ctx_,
dba_);
} else {
std::vector<TypedValue> arguments;
arguments.reserve(function.arguments_.size());
for (const auto &argument : function.arguments_) {
arguments.emplace_back(argument->Accept(*this));
}
return function.function()(arguments.data(), arguments.size(), context_);
return function.function()(arguments.data(), arguments.size(), *ctx_,
dba_);
}
}
@ -394,14 +403,12 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
list_value.type());
}
const auto &list = list_value.Value<std::vector<TypedValue>>();
const auto &element_symbol =
context_->symbol_table_.at(*reduce.identifier_);
const auto &accumulator_symbol =
context_->symbol_table_.at(*reduce.accumulator_);
const auto &element_symbol = symbol_table_->at(*reduce.identifier_);
const auto &accumulator_symbol = symbol_table_->at(*reduce.accumulator_);
auto accumulator = reduce.initializer_->Accept(*this);
for (const auto &element : list) {
frame_[accumulator_symbol] = accumulator;
frame_[element_symbol] = element;
frame_->at(accumulator_symbol) = accumulator;
frame_->at(element_symbol) = element;
accumulator = reduce.expression_->Accept(*this);
}
return accumulator;
@ -417,15 +424,14 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
list_value.type());
}
const auto &list = list_value.Value<std::vector<TypedValue>>();
const auto &element_symbol =
context_->symbol_table_.at(*extract.identifier_);
const auto &element_symbol = symbol_table_->at(*extract.identifier_);
std::vector<TypedValue> result;
result.reserve(list.size());
for (const auto &element : list) {
if (element.IsNull()) {
result.push_back(TypedValue::Null);
} else {
frame_[element_symbol] = element;
frame_->at(element_symbol) = element;
result.emplace_back(extract.expression_->Accept(*this));
}
}
@ -442,9 +448,9 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
list_value.type());
}
const auto &list = list_value.Value<std::vector<TypedValue>>();
const auto &symbol = context_->symbol_table_.at(*all.identifier_);
const auto &symbol = symbol_table_->at(*all.identifier_);
for (const auto &element : list) {
frame_[symbol] = element;
frame_->at(symbol) = element;
auto result = all.where_->expression_->Accept(*this);
if (!result.IsNull() && result.type() != TypedValue::Type::Bool) {
throw QueryRuntimeException(
@ -468,10 +474,10 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
list_value.type());
}
const auto &list = list_value.Value<std::vector<TypedValue>>();
const auto &symbol = context_->symbol_table_.at(*single.identifier_);
const auto &symbol = symbol_table_->at(*single.identifier_);
bool predicate_satisfied = false;
for (const auto &element : list) {
frame_[symbol] = element;
frame_->at(symbol) = element;
auto result = single.where_->expression_->Accept(*this);
if (!result.IsNull() && result.type() != TypedValue::Type::Bool) {
throw QueryRuntimeException(
@ -492,7 +498,7 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
}
TypedValue Visit(ParameterLookup &param_lookup) override {
return context_->parameters_.AtTokenPosition(param_lookup.token_position_);
return parameters_->AtTokenPosition(param_lookup.token_position_);
}
private:
@ -558,8 +564,11 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
}
}
Frame &frame_;
Context *context_;
Frame *frame_;
const SymbolTable *symbol_table_;
const Parameters *parameters_;
const EvaluationContext *ctx_;
database::GraphDbAccessor *dba_;
// which switching approach should be used when evaluating
const GraphView graph_view_;
};

View File

@ -28,13 +28,18 @@ Interpreter::Results Interpreter::operator()(
const std::map<std::string, TypedValue> &params,
bool in_explicit_transaction) {
utils::Timer frontend_timer;
EvaluationContext evaluation_context;
evaluation_context.timestamp =
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count();
Context ctx(db_accessor);
ctx.in_explicit_transaction_ = in_explicit_transaction;
ctx.timestamp_ = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count();
ctx.auth_ = auth_;
ctx.kafka_streams_ = kafka_streams_;
ctx.evaluation_context_ = evaluation_context;
// query -> stripped query
StrippedQuery stripped(query);

View File

@ -342,7 +342,7 @@ class RemotePuller {
void UpdatePullForWorker(int worker_id, Context &context) {
remote_pulls_[worker_id] = pull_clients_->Pull(
&db_, worker_id, plan_id_, command_id_, context.parameters_, symbols_,
context.timestamp_, false);
context.evaluation_context_.timestamp, false);
}
};
@ -530,7 +530,7 @@ class SynchronizeCursor : public Cursor {
worker_accumulations.emplace_back(pull_clients_->Pull(
&context.db_accessor_, worker_id, self_.pull_remote()->plan_id(),
command_id_, context.parameters_, self_.pull_remote()->symbols(),
context.timestamp_, true, 0));
context.evaluation_context_.timestamp, true, 0));
}
}
@ -627,7 +627,9 @@ class PullRemoteOrderByCursor : public Cursor {
bool Pull(Frame &frame, Context &context) {
if (context.db_accessor_.should_abort()) throw HintedAbortError();
ExpressionEvaluator evaluator(frame, &context, GraphView::OLD);
ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_, GraphView::OLD);
auto evaluate_result = [this, &evaluator]() {
std::vector<TypedValue> order_by;
@ -1005,7 +1007,9 @@ class DistributedExpandBfsCursor : public query::plan::Cursor {
}
// Evaluator for the filtering condition and expansion depth.
ExpressionEvaluator evaluator(frame, &context, self_.graph_view());
ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_, self_.graph_view());
while (true) {
TypedValue last_vertex;
@ -1181,7 +1185,9 @@ VertexAccessor &CreateVertexOnWorker(int worker_id, NodeAtom *node_atom,
// Evaluator should use the latest accessors, as modified in this query, when
// setting properties on new nodes.
ExpressionEvaluator evaluator(frame, &context, GraphView::NEW);
ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_, GraphView::NEW);
for (auto &kv : node_atom->properties_) {
auto value = kv.second->Accept(evaluator);
if (!value.IsPropertyValue()) {
@ -1253,7 +1259,9 @@ class DistributedCreateExpandCursor : public query::plan::Cursor {
// Similarly to CreateNode, newly created edges and nodes should use the
// latest accesors.
ExpressionEvaluator evaluator(frame, &context, GraphView::NEW);
ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_, GraphView::NEW);
// E.g. we pickup new properties: `CREATE (n {p: 42}) -[:r {ep: n.p}]-> ()`
v1.SwitchNew();

View File

@ -101,7 +101,9 @@ VertexAccessor &CreateLocalVertex(NodeAtom *node_atom, Frame &frame,
// Evaluator should use the latest accessors, as modified in this query, when
// setting properties on new nodes.
ExpressionEvaluator evaluator(frame, &context, GraphView::NEW);
ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_, GraphView::NEW);
for (auto &kv : node_atom->properties_)
PropsSetChecked(&new_node, kv.first.second, kv.second->Accept(evaluator));
frame[context.symbol_table_.at(*node_atom->identifier_)] = new_node;
@ -176,7 +178,9 @@ bool CreateExpand::CreateExpandCursor::Pull(Frame &frame, Context &context) {
// Similarly to CreateNode, newly created edges and nodes should use the
// latest accesors.
ExpressionEvaluator evaluator(frame, &context, GraphView::NEW);
ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_, GraphView::NEW);
// E.g. we pickup new properties: `CREATE (n {p: 42}) -[:r {ep: n.p}]-> ()`
v1.SwitchNew();
@ -339,7 +343,9 @@ std::unique_ptr<Cursor> ScanAllByLabelPropertyRange::MakeCursor(
-> std::experimental::optional<decltype(
db.Vertices(label_, property_, std::experimental::nullopt,
std::experimental::nullopt, false))> {
ExpressionEvaluator evaluator(frame, &context, graph_view_);
ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_, graph_view_);
auto convert = [&evaluator](const auto &bound)
-> std::experimental::optional<utils::Bound<PropertyValue>> {
if (!bound) return std::experimental::nullopt;
@ -386,7 +392,9 @@ std::unique_ptr<Cursor> ScanAllByLabelPropertyValue::MakeCursor(
auto vertices = [this, &db](Frame &frame, Context &context)
-> std::experimental::optional<decltype(
db.Vertices(label_, property_, TypedValue::Null, false))> {
ExpressionEvaluator evaluator(frame, &context, graph_view_);
ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_, graph_view_);
auto value = expression_->Accept(evaluator);
if (value.IsNull()) return std::experimental::nullopt;
try {
@ -651,7 +659,9 @@ class ExpandVariableCursor : public Cursor {
: self_(self), input_cursor_(self.input_->MakeCursor(db)) {}
bool Pull(Frame &frame, Context &context) override {
ExpressionEvaluator evaluator(frame, &context, self_.graph_view_);
ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_, self_.graph_view_);
while (true) {
if (Expand(frame, context)) return true;
@ -723,7 +733,10 @@ class ExpandVariableCursor : public Cursor {
SwitchAccessor(vertex, self_.graph_view_);
// Evaluate the upper and lower bounds.
ExpressionEvaluator evaluator(frame, &context, self_.graph_view_);
ExpressionEvaluator evaluator(&frame, context.symbol_table_,
context.parameters_,
context.evaluation_context_,
&context.db_accessor_, self_.graph_view_);
auto calc_bound = [&evaluator](auto &bound) {
auto value = EvaluateInt(&evaluator, bound, "Variable expansion bound");
if (value < 0)
@ -782,7 +795,9 @@ class ExpandVariableCursor : public Cursor {
* vertex and another Pull from the input cursor should be performed.
*/
bool Expand(Frame &frame, Context &context) {
ExpressionEvaluator evaluator(frame, &context, self_.graph_view_);
ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_, self_.graph_view_);
// Some expansions might not be valid due to edge uniqueness and
// existing_node criterions, so expand in a loop until either the input
// vertex is exhausted or a valid variable-length expansion is available.
@ -875,7 +890,9 @@ class STShortestPathCursor : public query::plan::Cursor {
}
bool Pull(Frame &frame, Context &context) override {
ExpressionEvaluator evaluator(frame, &context, GraphView::OLD);
ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_, GraphView::OLD);
while (input_cursor_->Pull(frame, context)) {
auto source_tv = frame[self_.input_symbol()];
auto sink_tv = frame[self_.node_symbol()];
@ -1102,7 +1119,9 @@ class SingleSourceShortestPathCursor : public query::plan::Cursor {
}
bool Pull(Frame &frame, Context &context) override {
ExpressionEvaluator evaluator(frame, &context, GraphView::OLD);
ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_, GraphView::OLD);
// for the given (edge, vertex) pair checks if they satisfy the
// "where" condition. if so, places them in the to_visit_ structure.
@ -1247,7 +1266,9 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor {
: self_(self), input_cursor_(self_.input_->MakeCursor(db)) {}
bool Pull(Frame &frame, Context &context) override {
ExpressionEvaluator evaluator(frame, &context, self_.graph_view_);
ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_, self_.graph_view_);
auto create_state = [this](VertexAccessor vertex, int depth) {
return std::make_pair(vertex, upper_bound_set_ ? depth : 0);
};
@ -1610,7 +1631,9 @@ Filter::FilterCursor::FilterCursor(const Filter &self,
bool Filter::FilterCursor::Pull(Frame &frame, Context &context) {
// Like all filters, newly set values should not affect filtering of old
// nodes and edges.
ExpressionEvaluator evaluator(frame, &context, GraphView::OLD);
ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_, GraphView::OLD);
while (input_cursor_->Pull(frame, context)) {
if (EvaluateFilter(evaluator, self_.expression_)) return true;
}
@ -1651,7 +1674,9 @@ Produce::ProduceCursor::ProduceCursor(const Produce &self,
bool Produce::ProduceCursor::Pull(Frame &frame, Context &context) {
if (input_cursor_->Pull(frame, context)) {
// Produce should always yield the latest results.
ExpressionEvaluator evaluator(frame, &context, GraphView::NEW);
ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_, GraphView::NEW);
for (auto named_expr : self_.named_expressions_)
named_expr->Accept(evaluator);
return true;
@ -1686,7 +1711,9 @@ bool Delete::DeleteCursor::Pull(Frame &frame, Context &context) {
// Delete should get the latest information, this way it is also possible
// to
// delete newly added nodes and edges.
ExpressionEvaluator evaluator(frame, &context, GraphView::NEW);
ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_, GraphView::NEW);
// collect expressions results so edges can get deleted before vertices
// this is necessary because an edge that gets deleted could block vertex
// deletion
@ -1754,7 +1781,9 @@ bool SetProperty::SetPropertyCursor::Pull(Frame &frame, Context &context) {
if (!input_cursor_->Pull(frame, context)) return false;
// Set, just like Create needs to see the latest changes.
ExpressionEvaluator evaluator(frame, &context, GraphView::NEW);
ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_, GraphView::NEW);
TypedValue lhs = self_.lhs_->expression_->Accept(evaluator);
TypedValue rhs = self_.rhs_->Accept(evaluator);
@ -1810,7 +1839,9 @@ bool SetProperties::SetPropertiesCursor::Pull(Frame &frame, Context &context) {
TypedValue &lhs = frame[self_.input_symbol_];
// Set, just like Create needs to see the latest changes.
ExpressionEvaluator evaluator(frame, &context, GraphView::NEW);
ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_, GraphView::NEW);
TypedValue rhs = self_.rhs_->Accept(evaluator);
switch (lhs.type()) {
@ -1945,7 +1976,9 @@ bool RemoveProperty::RemovePropertyCursor::Pull(Frame &frame,
if (!input_cursor_->Pull(frame, context)) return false;
// Remove, just like Delete needs to see the latest changes.
ExpressionEvaluator evaluator(frame, &context, GraphView::NEW);
ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_, GraphView::NEW);
TypedValue lhs = self_.lhs_->expression_->Accept(evaluator);
switch (lhs.type()) {
@ -2243,7 +2276,9 @@ bool Aggregate::AggregateCursor::Pull(Frame &frame, Context &context) {
}
void Aggregate::AggregateCursor::ProcessAll(Frame &frame, Context &context) {
ExpressionEvaluator evaluator(frame, &context, GraphView::NEW);
ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_, GraphView::NEW);
while (input_cursor_->Pull(frame, context))
ProcessOne(frame, context.symbol_table_, evaluator);
@ -2470,7 +2505,9 @@ bool Skip::SkipCursor::Pull(Frame &frame, Context &context) {
// First successful pull from the input, evaluate the skip expression.
// The skip expression doesn't contain identifiers so graph view
// parameter is not important.
ExpressionEvaluator evaluator(frame, &context, GraphView::OLD);
ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_, GraphView::OLD);
TypedValue to_skip = self_.expression_->Accept(evaluator);
if (to_skip.type() != TypedValue::Type::Int)
throw QueryRuntimeException(
@ -2526,7 +2563,9 @@ bool Limit::LimitCursor::Pull(Frame &frame, Context &context) {
if (limit_ == -1) {
// Limit expression doesn't contain identifiers so graph view is not
// important.
ExpressionEvaluator evaluator(frame, &context, GraphView::OLD);
ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_, GraphView::OLD);
TypedValue limit = self_.expression_->Accept(evaluator);
if (limit.type() != TypedValue::Type::Int)
throw QueryRuntimeException(
@ -2588,7 +2627,9 @@ OrderBy::OrderByCursor::OrderByCursor(const OrderBy &self,
bool OrderBy::OrderByCursor::Pull(Frame &frame, Context &context) {
if (!did_pull_all_) {
ExpressionEvaluator evaluator(frame, &context, GraphView::OLD);
ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_, GraphView::OLD);
while (input_cursor_->Pull(frame, context)) {
// collect the order_by elements
std::vector<TypedValue> order_by;
@ -2817,7 +2858,9 @@ bool Unwind::UnwindCursor::Pull(Frame &frame, Context &context) {
if (!input_cursor_->Pull(frame, context)) return false;
// successful pull from input, initialize value and iterator
ExpressionEvaluator evaluator(frame, &context, GraphView::OLD);
ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_, GraphView::OLD);
TypedValue input_value = self_.input_expression_->Accept(evaluator);
if (input_value.type() != TypedValue::Type::List)
throw QueryRuntimeException(
@ -3216,7 +3259,9 @@ class AuthHandlerCursor : public Cursor {
throw UserModificationInMulticommandTxException();
}
ExpressionEvaluator evaluator(frame, &ctx, GraphView::OLD);
ExpressionEvaluator evaluator(&frame, ctx.symbol_table_, ctx.parameters_,
ctx.evaluation_context_, &ctx.db_accessor_,
GraphView::OLD);
std::experimental::optional<std::string> password;
if (self_.password()) {
auto password_tv = self_.password()->Accept(evaluator);
@ -3508,7 +3553,9 @@ class CreateStreamCursor : public Cursor {
if (ctx.in_explicit_transaction_) {
throw StreamClauseInMulticommandTxException();
}
ExpressionEvaluator evaluator(frame, &ctx, GraphView::OLD);
ExpressionEvaluator evaluator(&frame, ctx.symbol_table_, ctx.parameters_,
ctx.evaluation_context_, &ctx.db_accessor_,
GraphView::OLD);
TypedValue stream_uri = self_.stream_uri()->Accept(evaluator);
TypedValue stream_topic = self_.stream_topic()->Accept(evaluator);
@ -3666,7 +3713,9 @@ class StartStopStreamCursor : public Cursor {
throw StreamClauseInMulticommandTxException();
}
ExpressionEvaluator evaluator(frame, &ctx, GraphView::OLD);
ExpressionEvaluator evaluator(&frame, ctx.symbol_table_, ctx.parameters_,
ctx.evaluation_context_, &ctx.db_accessor_,
GraphView::OLD);
std::experimental::optional<int64_t> limit_batches;
if (self_.limit_batches()) {
@ -3762,7 +3811,9 @@ class TestStreamCursor : public Cursor {
}
if (!is_initialized_) {
ExpressionEvaluator evaluator(frame, &ctx, GraphView::OLD);
ExpressionEvaluator evaluator(&frame, ctx.symbol_table_, ctx.parameters_,
ctx.evaluation_context_, &ctx.db_accessor_,
GraphView::OLD);
std::experimental::optional<int64_t> limit_batches;
if (self_.limit_batches()) {

View File

@ -16,7 +16,10 @@ static void BenchmarkCoalesceCallWithNulls(benchmark::State &state) {
query::Frame frame(0);
database::GraphDbAccessor *dba = nullptr;
query::Context context(*dba);
query::ExpressionEvaluator evaluator(frame, &context, query::GraphView::OLD);
query::ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_,
query::GraphView::OLD);
while (state.KeepRunning()) {
function->Accept(evaluator);
}
@ -35,7 +38,10 @@ static void BenchmarkCoalesceCallWithStrings(benchmark::State &state) {
query::Frame frame(0);
database::GraphDbAccessor *dba = nullptr;
query::Context context(*dba);
query::ExpressionEvaluator evaluator(frame, &context, query::GraphView::OLD);
query::ExpressionEvaluator evaluator(
&frame, context.symbol_table_, context.parameters_,
context.evaluation_context_, &context.db_accessor_,
query::GraphView::OLD);
while (state.KeepRunning()) {
function->Accept(evaluator);
}

File diff suppressed because it is too large Load Diff