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:
parent
ba3837e942
commit
e5a7f51740
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 ¶meters,
|
||||
const EvaluationContext &ctx,
|
||||
database::GraphDbAccessor *dba, GraphView graph_view)
|
||||
: frame_(frame),
|
||||
symbol_table_(&symbol_table),
|
||||
parameters_(¶meters),
|
||||
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 ¶m_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_;
|
||||
};
|
||||
|
@ -28,13 +28,18 @@ Interpreter::Results Interpreter::operator()(
|
||||
const std::map<std::string, TypedValue> ¶ms,
|
||||
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);
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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()) {
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user