Add FunctionContext to simplify awesome function signature

Reviewers: ipaljak, mferencevic

Reviewed By: mferencevic

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D2327
This commit is contained in:
Teon Banek 2019-08-26 15:50:26 +02:00
parent 023538c19c
commit a878a11e70
4 changed files with 123 additions and 127 deletions

View File

@ -12,10 +12,6 @@
#include "storage/common/types/property_value.hpp" #include "storage/common/types/property_value.hpp"
#include "utils/typeinfo.hpp" #include "utils/typeinfo.hpp"
namespace database {
class GraphDbAccessor;
}
cpp<# cpp<#
(lcp:namespace query) (lcp:namespace query)
@ -788,7 +784,8 @@ cpp<#
:slk-save #'slk-save-ast-vector :slk-save #'slk-save-ast-vector
:slk-load (slk-load-ast-vector "Expression")) :slk-load (slk-load-ast-vector "Expression"))
(function-name "std::string" :scope :public) (function-name "std::string" :scope :public)
(function "std::function<TypedValue(TypedValue *, int64_t, const EvaluationContext &, database::GraphDbAccessor *)>" (function "std::function<TypedValue(const TypedValue *, int64_t,
const FunctionContext &)>"
:scope :public :scope :public
:dont-save t :dont-save t
:clone :copy :clone :copy

View File

@ -7,9 +7,9 @@
#include <functional> #include <functional>
#include <random> #include <random>
#include "database/single_node/dump.hpp" #include "database/graph_db_accessor.hpp"
#include "query/context.hpp"
#include "query/exceptions.hpp" #include "query/exceptions.hpp"
#include "query/typed_value.hpp"
#include "utils/string.hpp" #include "utils/string.hpp"
namespace query { namespace query {
@ -332,21 +332,15 @@ void FType(const char *name, const TypedValue *args, int64_t nargs,
// TODO: Implement degrees, haversin, radians // TODO: Implement degrees, haversin, radians
// TODO: Implement spatial functions // TODO: Implement spatial functions
/////////////////////////// IMPORTANT NOTE! //////////////////////////////////// TypedValue EndNode(const TypedValue *args, int64_t nargs,
// All of the functions take mutable `TypedValue *` to arguments, but none of const FunctionContext &ctx) {
// the functions should ever need to actually modify the arguments! Let's try to
// keep our sanity in a good state by treating the arguments as immutable.
////////////////////////////////////////////////////////////////////////////////
TypedValue EndNode(TypedValue *args, int64_t nargs,
const EvaluationContext &ctx, database::GraphDbAccessor *) {
FType<Or<Null, Edge>>("endNode", args, nargs); FType<Or<Null, Edge>>("endNode", args, nargs);
if (args[0].IsNull()) return TypedValue(ctx.memory); if (args[0].IsNull()) return TypedValue(ctx.memory);
return TypedValue(args[0].ValueEdge().to(), ctx.memory); return TypedValue(args[0].ValueEdge().to(), ctx.memory);
} }
TypedValue Head(TypedValue *args, int64_t nargs, const EvaluationContext &ctx, TypedValue Head(const TypedValue *args, int64_t nargs,
database::GraphDbAccessor *) { const FunctionContext &ctx) {
FType<Or<Null, List>>("head", args, nargs); FType<Or<Null, List>>("head", args, nargs);
if (args[0].IsNull()) return TypedValue(ctx.memory); if (args[0].IsNull()) return TypedValue(ctx.memory);
const auto &list = args[0].ValueList(); const auto &list = args[0].ValueList();
@ -354,8 +348,8 @@ TypedValue Head(TypedValue *args, int64_t nargs, const EvaluationContext &ctx,
return TypedValue(list[0], ctx.memory); return TypedValue(list[0], ctx.memory);
} }
TypedValue Last(TypedValue *args, int64_t nargs, const EvaluationContext &ctx, TypedValue Last(const TypedValue *args, int64_t nargs,
database::GraphDbAccessor *) { const FunctionContext &ctx) {
FType<Or<Null, List>>("last", args, nargs); FType<Or<Null, List>>("last", args, nargs);
if (args[0].IsNull()) return TypedValue(ctx.memory); if (args[0].IsNull()) return TypedValue(ctx.memory);
const auto &list = args[0].ValueList(); const auto &list = args[0].ValueList();
@ -363,10 +357,10 @@ TypedValue Last(TypedValue *args, int64_t nargs, const EvaluationContext &ctx,
return TypedValue(list.back(), ctx.memory); return TypedValue(list.back(), ctx.memory);
} }
TypedValue Properties(TypedValue *args, int64_t nargs, TypedValue Properties(const TypedValue *args, int64_t nargs,
const EvaluationContext &ctx, const FunctionContext &ctx) {
database::GraphDbAccessor *dba) {
FType<Or<Null, Vertex, Edge>>("properties", args, nargs); FType<Or<Null, Vertex, Edge>>("properties", args, nargs);
auto *dba = ctx.db_accessor;
auto get_properties = [&](const auto &record_accessor) { auto get_properties = [&](const auto &record_accessor) {
TypedValue::TMap properties(ctx.memory); TypedValue::TMap properties(ctx.memory);
for (const auto &property : record_accessor.Properties()) { for (const auto &property : record_accessor.Properties()) {
@ -387,8 +381,8 @@ TypedValue Properties(TypedValue *args, int64_t nargs,
} }
} }
TypedValue Size(TypedValue *args, int64_t nargs, const EvaluationContext &ctx, TypedValue Size(const TypedValue *args, int64_t nargs,
database::GraphDbAccessor *) { const FunctionContext &ctx) {
FType<Or<Null, List, String, Map, Path>>("size", args, nargs); FType<Or<Null, List, String, Map, Path>>("size", args, nargs);
switch (args[0].type()) { switch (args[0].type()) {
case TypedValue::Type::Null: case TypedValue::Type::Null:
@ -413,16 +407,15 @@ TypedValue Size(TypedValue *args, int64_t nargs, const EvaluationContext &ctx,
} }
} }
TypedValue StartNode(TypedValue *args, int64_t nargs, TypedValue StartNode(const TypedValue *args, int64_t nargs,
const EvaluationContext &ctx, const FunctionContext &ctx) {
database::GraphDbAccessor *) {
FType<Or<Null, Edge>>("startNode", args, nargs); FType<Or<Null, Edge>>("startNode", args, nargs);
if (args[0].IsNull()) return TypedValue(ctx.memory); if (args[0].IsNull()) return TypedValue(ctx.memory);
return TypedValue(args[0].ValueEdge().from(), ctx.memory); return TypedValue(args[0].ValueEdge().from(), ctx.memory);
} }
TypedValue Degree(TypedValue *args, int64_t nargs, const EvaluationContext &ctx, TypedValue Degree(const TypedValue *args, int64_t nargs,
database::GraphDbAccessor *) { const FunctionContext &ctx) {
FType<Or<Null, Vertex>>("degree", args, nargs); FType<Or<Null, Vertex>>("degree", args, nargs);
if (args[0].IsNull()) return TypedValue(ctx.memory); if (args[0].IsNull()) return TypedValue(ctx.memory);
const auto &vertex = args[0].ValueVertex(); const auto &vertex = args[0].ValueVertex();
@ -431,26 +424,24 @@ TypedValue Degree(TypedValue *args, int64_t nargs, const EvaluationContext &ctx,
ctx.memory); ctx.memory);
} }
TypedValue InDegree(TypedValue *args, int64_t nargs, TypedValue InDegree(const TypedValue *args, int64_t nargs,
const EvaluationContext &ctx, database::GraphDbAccessor *) { const FunctionContext &ctx) {
FType<Or<Null, Vertex>>("inDegree", args, nargs); FType<Or<Null, Vertex>>("inDegree", args, nargs);
if (args[0].IsNull()) return TypedValue(ctx.memory); if (args[0].IsNull()) return TypedValue(ctx.memory);
const auto &vertex = args[0].ValueVertex(); const auto &vertex = args[0].ValueVertex();
return TypedValue(static_cast<int64_t>(vertex.in_degree()), ctx.memory); return TypedValue(static_cast<int64_t>(vertex.in_degree()), ctx.memory);
} }
TypedValue OutDegree(TypedValue *args, int64_t nargs, TypedValue OutDegree(const TypedValue *args, int64_t nargs,
const EvaluationContext &ctx, const FunctionContext &ctx) {
database::GraphDbAccessor *) {
FType<Or<Null, Vertex>>("outDegree", args, nargs); FType<Or<Null, Vertex>>("outDegree", args, nargs);
if (args[0].IsNull()) return TypedValue(ctx.memory); if (args[0].IsNull()) return TypedValue(ctx.memory);
const auto &vertex = args[0].ValueVertex(); const auto &vertex = args[0].ValueVertex();
return TypedValue(static_cast<int64_t>(vertex.out_degree()), ctx.memory); return TypedValue(static_cast<int64_t>(vertex.out_degree()), ctx.memory);
} }
TypedValue ToBoolean(TypedValue *args, int64_t nargs, TypedValue ToBoolean(const TypedValue *args, int64_t nargs,
const EvaluationContext &ctx, const FunctionContext &ctx) {
database::GraphDbAccessor *) {
FType<Or<Null, Bool, Integer, String>>("toBoolean", args, nargs); FType<Or<Null, Bool, Integer, String>>("toBoolean", args, nargs);
switch (args[0].type()) { switch (args[0].type()) {
case TypedValue::Type::Null: case TypedValue::Type::Null:
@ -473,15 +464,14 @@ TypedValue ToBoolean(TypedValue *args, int64_t nargs,
} }
} }
TypedValue ToFloat(TypedValue *args, int64_t nargs, TypedValue ToFloat(const TypedValue *args, int64_t nargs,
const EvaluationContext &ctx, database::GraphDbAccessor *) { const FunctionContext &ctx) {
FType<Or<Null, Number, String>>("toFloat", args, nargs); FType<Or<Null, Number, String>>("toFloat", args, nargs);
switch (args[0].type()) { switch (args[0].type()) {
case TypedValue::Type::Null: case TypedValue::Type::Null:
return TypedValue(ctx.memory); return TypedValue(ctx.memory);
case TypedValue::Type::Int: case TypedValue::Type::Int:
return TypedValue(static_cast<double>(args[0].ValueInt()), return TypedValue(static_cast<double>(args[0].ValueInt()), ctx.memory);
ctx.memory);
case TypedValue::Type::Double: case TypedValue::Type::Double:
return TypedValue(args[0], ctx.memory); return TypedValue(args[0], ctx.memory);
case TypedValue::Type::String: case TypedValue::Type::String:
@ -497,9 +487,8 @@ TypedValue ToFloat(TypedValue *args, int64_t nargs,
} }
} }
TypedValue ToInteger(TypedValue *args, int64_t nargs, TypedValue ToInteger(const TypedValue *args, int64_t nargs,
const EvaluationContext &ctx, const FunctionContext &ctx) {
database::GraphDbAccessor *) {
FType<Or<Null, Bool, Number, String>>("toInteger", args, nargs); FType<Or<Null, Bool, Number, String>>("toInteger", args, nargs);
switch (args[0].type()) { switch (args[0].type()) {
case TypedValue::Type::Null: case TypedValue::Type::Null:
@ -527,17 +516,19 @@ TypedValue ToInteger(TypedValue *args, int64_t nargs,
} }
} }
TypedValue Type(TypedValue *args, int64_t nargs, const EvaluationContext &ctx, TypedValue Type(const TypedValue *args, int64_t nargs,
database::GraphDbAccessor *dba) { const FunctionContext &ctx) {
FType<Or<Null, Edge>>("type", args, nargs); FType<Or<Null, Edge>>("type", args, nargs);
auto *dba = ctx.db_accessor;
if (args[0].IsNull()) return TypedValue(ctx.memory); if (args[0].IsNull()) return TypedValue(ctx.memory);
return TypedValue(dba->EdgeTypeName(args[0].ValueEdge().EdgeType()), return TypedValue(dba->EdgeTypeName(args[0].ValueEdge().EdgeType()),
ctx.memory); ctx.memory);
} }
TypedValue Keys(TypedValue *args, int64_t nargs, const EvaluationContext &ctx, TypedValue Keys(const TypedValue *args, int64_t nargs,
database::GraphDbAccessor *dba) { const FunctionContext &ctx) {
FType<Or<Null, Vertex, Edge>>("keys", args, nargs); FType<Or<Null, Vertex, Edge>>("keys", args, nargs);
auto *dba = ctx.db_accessor;
auto get_keys = [&](const auto &record_accessor) { auto get_keys = [&](const auto &record_accessor) {
TypedValue::TVector keys(ctx.memory); TypedValue::TVector keys(ctx.memory);
for (const auto &property : record_accessor.Properties()) { for (const auto &property : record_accessor.Properties()) {
@ -557,9 +548,10 @@ TypedValue Keys(TypedValue *args, int64_t nargs, const EvaluationContext &ctx,
} }
} }
TypedValue Labels(TypedValue *args, int64_t nargs, const EvaluationContext &ctx, TypedValue Labels(const TypedValue *args, int64_t nargs,
database::GraphDbAccessor *dba) { const FunctionContext &ctx) {
FType<Or<Null, Vertex>>("labels", args, nargs); FType<Or<Null, Vertex>>("labels", args, nargs);
auto *dba = ctx.db_accessor;
if (args[0].IsNull()) return TypedValue(ctx.memory); if (args[0].IsNull()) return TypedValue(ctx.memory);
TypedValue::TVector labels(ctx.memory); TypedValue::TVector labels(ctx.memory);
for (const auto &label : args[0].ValueVertex().labels()) { for (const auto &label : args[0].ValueVertex().labels()) {
@ -568,8 +560,8 @@ TypedValue Labels(TypedValue *args, int64_t nargs, const EvaluationContext &ctx,
return TypedValue(std::move(labels)); return TypedValue(std::move(labels));
} }
TypedValue Nodes(TypedValue *args, int64_t nargs, const EvaluationContext &ctx, TypedValue Nodes(const TypedValue *args, int64_t nargs,
database::GraphDbAccessor *) { const FunctionContext &ctx) {
FType<Or<Null, Path>>("nodes", args, nargs); FType<Or<Null, Path>>("nodes", args, nargs);
if (args[0].IsNull()) return TypedValue(ctx.memory); if (args[0].IsNull()) return TypedValue(ctx.memory);
const auto &vertices = args[0].ValuePath().vertices(); const auto &vertices = args[0].ValuePath().vertices();
@ -579,9 +571,8 @@ TypedValue Nodes(TypedValue *args, int64_t nargs, const EvaluationContext &ctx,
return TypedValue(std::move(values)); return TypedValue(std::move(values));
} }
TypedValue Relationships(TypedValue *args, int64_t nargs, TypedValue Relationships(const TypedValue *args, int64_t nargs,
const EvaluationContext &ctx, const FunctionContext &ctx) {
database::GraphDbAccessor *) {
FType<Or<Null, Path>>("relationships", args, nargs); FType<Or<Null, Path>>("relationships", args, nargs);
if (args[0].IsNull()) return TypedValue(ctx.memory); if (args[0].IsNull()) return TypedValue(ctx.memory);
const auto &edges = args[0].ValuePath().edges(); const auto &edges = args[0].ValuePath().edges();
@ -591,8 +582,8 @@ TypedValue Relationships(TypedValue *args, int64_t nargs,
return TypedValue(std::move(values)); return TypedValue(std::move(values));
} }
TypedValue Range(TypedValue *args, int64_t nargs, const EvaluationContext &ctx, TypedValue Range(const TypedValue *args, int64_t nargs,
database::GraphDbAccessor *) { const FunctionContext &ctx) {
FType<Or<Null, Integer>, Or<Null, Integer>, FType<Or<Null, Integer>, Or<Null, Integer>,
Optional<Or<Null, NonZeroInteger>>>("range", args, nargs); Optional<Or<Null, NonZeroInteger>>>("range", args, nargs);
for (int64_t i = 0; i < nargs; ++i) for (int64_t i = 0; i < nargs; ++i)
@ -613,8 +604,8 @@ TypedValue Range(TypedValue *args, int64_t nargs, const EvaluationContext &ctx,
return TypedValue(std::move(list)); return TypedValue(std::move(list));
} }
TypedValue Tail(TypedValue *args, int64_t nargs, const EvaluationContext &ctx, TypedValue Tail(const TypedValue *args, int64_t nargs,
database::GraphDbAccessor *) { const FunctionContext &ctx) {
FType<Or<Null, List>>("tail", args, nargs); FType<Or<Null, List>>("tail", args, nargs);
if (args[0].IsNull()) return TypedValue(ctx.memory); if (args[0].IsNull()) return TypedValue(ctx.memory);
TypedValue::TVector list(args[0].ValueList(), ctx.memory); TypedValue::TVector list(args[0].ValueList(), ctx.memory);
@ -623,9 +614,8 @@ TypedValue Tail(TypedValue *args, int64_t nargs, const EvaluationContext &ctx,
return TypedValue(std::move(list)); return TypedValue(std::move(list));
} }
TypedValue UniformSample(TypedValue *args, int64_t nargs, TypedValue UniformSample(const TypedValue *args, int64_t nargs,
const EvaluationContext &ctx, const FunctionContext &ctx) {
database::GraphDbAccessor *) {
FType<Or<Null, List>, Or<Null, NonNegativeInteger>>("uniformSample", args, FType<Or<Null, List>, Or<Null, NonNegativeInteger>>("uniformSample", args,
nargs); nargs);
static thread_local std::mt19937 pseudo_rand_gen_{std::random_device{}()}; static thread_local std::mt19937 pseudo_rand_gen_{std::random_device{}()};
@ -643,8 +633,8 @@ TypedValue UniformSample(TypedValue *args, int64_t nargs,
return TypedValue(std::move(sampled)); return TypedValue(std::move(sampled));
} }
TypedValue Abs(TypedValue *args, int64_t nargs, const EvaluationContext &ctx, TypedValue Abs(const TypedValue *args, int64_t nargs,
database::GraphDbAccessor *) { const FunctionContext &ctx) {
FType<Or<Null, Number>>("abs", args, nargs); FType<Or<Null, Number>>("abs", args, nargs);
switch (args[0].type()) { switch (args[0].type()) {
case TypedValue::Type::Null: case TypedValue::Type::Null:
@ -659,8 +649,8 @@ TypedValue Abs(TypedValue *args, int64_t nargs, const EvaluationContext &ctx,
} }
#define WRAP_CMATH_FLOAT_FUNCTION(name, lowercased_name) \ #define WRAP_CMATH_FLOAT_FUNCTION(name, lowercased_name) \
TypedValue name(TypedValue *args, int64_t nargs, \ TypedValue name(const TypedValue *args, int64_t nargs, \
const EvaluationContext &ctx, database::GraphDbAccessor *) { \ const FunctionContext &ctx) { \
FType<Or<Null, Number>>(#lowercased_name, args, nargs); \ FType<Or<Null, Number>>(#lowercased_name, args, nargs); \
switch (args[0].type()) { \ switch (args[0].type()) { \
case TypedValue::Type::Null: \ case TypedValue::Type::Null: \
@ -693,8 +683,8 @@ WRAP_CMATH_FLOAT_FUNCTION(Tan, tan)
#undef WRAP_CMATH_FLOAT_FUNCTION #undef WRAP_CMATH_FLOAT_FUNCTION
TypedValue Atan2(TypedValue *args, int64_t nargs, const EvaluationContext &ctx, TypedValue Atan2(const TypedValue *args, int64_t nargs,
database::GraphDbAccessor *) { const FunctionContext &ctx) {
FType<Or<Null, Number>, Or<Null, Number>>("atan2", args, nargs); FType<Or<Null, Number>, Or<Null, Number>>("atan2", args, nargs);
if (args[0].type() == TypedValue::Type::Null) return TypedValue(ctx.memory); if (args[0].type() == TypedValue::Type::Null) return TypedValue(ctx.memory);
if (args[1].type() == TypedValue::Type::Null) return TypedValue(ctx.memory); if (args[1].type() == TypedValue::Type::Null) return TypedValue(ctx.memory);
@ -713,8 +703,8 @@ TypedValue Atan2(TypedValue *args, int64_t nargs, const EvaluationContext &ctx,
return TypedValue(atan2(y, x), ctx.memory); return TypedValue(atan2(y, x), ctx.memory);
} }
TypedValue Sign(TypedValue *args, int64_t nargs, const EvaluationContext &ctx, TypedValue Sign(const TypedValue *args, int64_t nargs,
database::GraphDbAccessor *) { const FunctionContext &ctx) {
FType<Or<Null, Number>>("sign", args, nargs); FType<Or<Null, Number>>("sign", args, nargs);
auto sign = [&](auto x) { return TypedValue((0 < x) - (x < 0), ctx.memory); }; auto sign = [&](auto x) { return TypedValue((0 < x) - (x < 0), ctx.memory); };
switch (args[0].type()) { switch (args[0].type()) {
@ -729,20 +719,20 @@ TypedValue Sign(TypedValue *args, int64_t nargs, const EvaluationContext &ctx,
} }
} }
TypedValue E(TypedValue *args, int64_t nargs, const EvaluationContext &ctx, TypedValue E(const TypedValue *args, int64_t nargs,
database::GraphDbAccessor *) { const FunctionContext &ctx) {
FType<void>("e", args, nargs); FType<void>("e", args, nargs);
return TypedValue(M_E, ctx.memory); return TypedValue(M_E, ctx.memory);
} }
TypedValue Pi(TypedValue *args, int64_t nargs, const EvaluationContext &ctx, TypedValue Pi(const TypedValue *args, int64_t nargs,
database::GraphDbAccessor *) { const FunctionContext &ctx) {
FType<void>("pi", args, nargs); FType<void>("pi", args, nargs);
return TypedValue(M_PI, ctx.memory); return TypedValue(M_PI, ctx.memory);
} }
TypedValue Rand(TypedValue *args, int64_t nargs, const EvaluationContext &ctx, TypedValue Rand(const TypedValue *args, int64_t nargs,
database::GraphDbAccessor *) { const FunctionContext &ctx) {
FType<void>("rand", args, nargs); FType<void>("rand", args, nargs);
static thread_local std::mt19937 pseudo_rand_gen_{std::random_device{}()}; static thread_local std::mt19937 pseudo_rand_gen_{std::random_device{}()};
static thread_local std::uniform_real_distribution<> rand_dist_{0, 1}; static thread_local std::uniform_real_distribution<> rand_dist_{0, 1};
@ -750,9 +740,8 @@ TypedValue Rand(TypedValue *args, int64_t nargs, const EvaluationContext &ctx,
} }
template <class TPredicate> template <class TPredicate>
TypedValue StringMatchOperator(TypedValue *args, int64_t nargs, TypedValue StringMatchOperator(const TypedValue *args, int64_t nargs,
const EvaluationContext &ctx, const FunctionContext &ctx) {
database::GraphDbAccessor *) {
FType<Or<Null, String>, Or<Null, String>>(TPredicate::name, args, nargs); FType<Or<Null, String>, Or<Null, String>>(TPredicate::name, args, nargs);
if (args[0].IsNull() || args[1].IsNull()) return TypedValue(ctx.memory); if (args[0].IsNull() || args[1].IsNull()) return TypedValue(ctx.memory);
const auto &s1 = args[0].ValueString(); const auto &s1 = args[0].ValueString();
@ -793,8 +782,8 @@ struct ContainsPredicate {
}; };
auto Contains = StringMatchOperator<ContainsPredicate>; auto Contains = StringMatchOperator<ContainsPredicate>;
TypedValue Assert(TypedValue *args, int64_t nargs, const EvaluationContext &ctx, TypedValue Assert(const TypedValue *args, int64_t nargs,
database::GraphDbAccessor *) { const FunctionContext &ctx) {
FType<Bool, Optional<String>>("assert", args, nargs); FType<Bool, Optional<String>>("assert", args, nargs);
if (!args[0].ValueBool()) { if (!args[0].ValueBool()) {
std::string message("Assertion failed"); std::string message("Assertion failed");
@ -808,9 +797,8 @@ TypedValue Assert(TypedValue *args, int64_t nargs, const EvaluationContext &ctx,
return TypedValue(args[0], ctx.memory); return TypedValue(args[0], ctx.memory);
} }
TypedValue Counter(TypedValue *args, int64_t nargs, TypedValue Counter(const TypedValue *args, int64_t nargs,
const EvaluationContext &context, const FunctionContext &context) {
database::GraphDbAccessor *) {
FType<String, Integer, Optional<NonZeroInteger>>("counter", args, nargs); FType<String, Integer, Optional<NonZeroInteger>>("counter", args, nargs);
int64_t step = 1; int64_t step = 1;
if (nargs == 3) { if (nargs == 3) {
@ -818,15 +806,15 @@ TypedValue Counter(TypedValue *args, int64_t nargs,
} }
auto [it, inserted] = auto [it, inserted] =
context.counters.emplace(args[0].ValueString(), args[1].ValueInt()); context.counters->emplace(args[0].ValueString(), args[1].ValueInt());
auto value = it->second; auto value = it->second;
it->second += step; it->second += step;
return TypedValue(value, context.memory); return TypedValue(value, context.memory);
} }
TypedValue Id(TypedValue *args, int64_t nargs, const EvaluationContext &ctx, TypedValue Id(const TypedValue *args, int64_t nargs,
database::GraphDbAccessor *dba) { const FunctionContext &ctx) {
FType<Or<Vertex, Edge>>("id", args, nargs); FType<Or<Vertex, Edge>>("id", args, nargs);
const auto &arg = args[0]; const auto &arg = args[0];
if (arg.IsVertex()) if (arg.IsVertex())
@ -835,8 +823,8 @@ TypedValue Id(TypedValue *args, int64_t nargs, const EvaluationContext &ctx,
return TypedValue(arg.ValueEdge().CypherId(), ctx.memory); return TypedValue(arg.ValueEdge().CypherId(), ctx.memory);
} }
TypedValue ToString(TypedValue *args, int64_t nargs, TypedValue ToString(const TypedValue *args, int64_t nargs,
const EvaluationContext &ctx, database::GraphDbAccessor *) { const FunctionContext &ctx) {
FType<Or<Null, String, Number, Bool>>("toString", args, nargs); FType<Or<Null, String, Number, Bool>>("toString", args, nargs);
const auto &arg = args[0]; const auto &arg = args[0];
switch (arg.type()) { switch (arg.type()) {
@ -858,23 +846,22 @@ TypedValue ToString(TypedValue *args, int64_t nargs,
} }
} }
TypedValue Timestamp(TypedValue *args, int64_t nargs, TypedValue Timestamp(const TypedValue *args, int64_t nargs,
const EvaluationContext &ctx, const FunctionContext &ctx) {
database::GraphDbAccessor *) {
FType<void>("timestamp", args, nargs); FType<void>("timestamp", args, nargs);
return TypedValue(ctx.timestamp, ctx.memory); return TypedValue(ctx.timestamp, ctx.memory);
} }
TypedValue Left(TypedValue *args, int64_t nargs, const EvaluationContext &ctx, TypedValue Left(const TypedValue *args, int64_t nargs,
database::GraphDbAccessor *dba) { const FunctionContext &ctx) {
FType<Or<Null, String>, Or<Null, NonNegativeInteger>>("left", args, nargs); FType<Or<Null, String>, Or<Null, NonNegativeInteger>>("left", args, nargs);
if (args[0].IsNull() || args[1].IsNull()) return TypedValue(ctx.memory); if (args[0].IsNull() || args[1].IsNull()) return TypedValue(ctx.memory);
return TypedValue(utils::Substr(args[0].ValueString(), 0, args[1].ValueInt()), return TypedValue(utils::Substr(args[0].ValueString(), 0, args[1].ValueInt()),
ctx.memory); ctx.memory);
} }
TypedValue Right(TypedValue *args, int64_t nargs, const EvaluationContext &ctx, TypedValue Right(const TypedValue *args, int64_t nargs,
database::GraphDbAccessor *dba) { const FunctionContext &ctx) {
FType<Or<Null, String>, Or<Null, NonNegativeInteger>>("right", args, nargs); FType<Or<Null, String>, Or<Null, NonNegativeInteger>>("right", args, nargs);
if (args[0].IsNull() || args[1].IsNull()) return TypedValue(ctx.memory); if (args[0].IsNull() || args[1].IsNull()) return TypedValue(ctx.memory);
const auto &str = args[0].ValueString(); const auto &str = args[0].ValueString();
@ -885,7 +872,7 @@ TypedValue Right(TypedValue *args, int64_t nargs, const EvaluationContext &ctx,
} }
TypedValue CallStringFunction( TypedValue CallStringFunction(
TypedValue *args, int64_t nargs, utils::MemoryResource *memory, const TypedValue *args, int64_t nargs, utils::MemoryResource *memory,
const char *name, const char *name,
std::function<TypedValue::TString(const TypedValue::TString &)> fun) { std::function<TypedValue::TString(const TypedValue::TString &)> fun) {
FType<Or<Null, String>>(name, args, nargs); FType<Or<Null, String>>(name, args, nargs);
@ -893,39 +880,39 @@ TypedValue CallStringFunction(
return TypedValue(fun(args[0].ValueString()), memory); return TypedValue(fun(args[0].ValueString()), memory);
} }
TypedValue LTrim(TypedValue *args, int64_t nargs, const EvaluationContext &ctx, TypedValue LTrim(const TypedValue *args, int64_t nargs,
database::GraphDbAccessor *) { const FunctionContext &ctx) {
return CallStringFunction( return CallStringFunction(
args, nargs, ctx.memory, "lTrim", [&](const auto &str) { args, nargs, ctx.memory, "lTrim", [&](const auto &str) {
return TypedValue::TString(utils::LTrim(str), ctx.memory); return TypedValue::TString(utils::LTrim(str), ctx.memory);
}); });
} }
TypedValue RTrim(TypedValue *args, int64_t nargs, const EvaluationContext &ctx, TypedValue RTrim(const TypedValue *args, int64_t nargs,
database::GraphDbAccessor *) { const FunctionContext &ctx) {
return CallStringFunction( return CallStringFunction(
args, nargs, ctx.memory, "rTrim", [&](const auto &str) { args, nargs, ctx.memory, "rTrim", [&](const auto &str) {
return TypedValue::TString(utils::RTrim(str), ctx.memory); return TypedValue::TString(utils::RTrim(str), ctx.memory);
}); });
} }
TypedValue Trim(TypedValue *args, int64_t nargs, const EvaluationContext &ctx, TypedValue Trim(const TypedValue *args, int64_t nargs,
database::GraphDbAccessor *) { const FunctionContext &ctx) {
return CallStringFunction( return CallStringFunction(
args, nargs, ctx.memory, "trim", [&](const auto &str) { args, nargs, ctx.memory, "trim", [&](const auto &str) {
return TypedValue::TString(utils::Trim(str), ctx.memory); return TypedValue::TString(utils::Trim(str), ctx.memory);
}); });
} }
TypedValue Reverse(TypedValue *args, int64_t nargs, TypedValue Reverse(const TypedValue *args, int64_t nargs,
const EvaluationContext &ctx, database::GraphDbAccessor *) { const FunctionContext &ctx) {
return CallStringFunction( return CallStringFunction(
args, nargs, ctx.memory, "reverse", args, nargs, ctx.memory, "reverse",
[&](const auto &str) { return utils::Reversed(str, ctx.memory); }); [&](const auto &str) { return utils::Reversed(str, ctx.memory); });
} }
TypedValue ToLower(TypedValue *args, int64_t nargs, TypedValue ToLower(const TypedValue *args, int64_t nargs,
const EvaluationContext &ctx, database::GraphDbAccessor *) { const FunctionContext &ctx) {
return CallStringFunction(args, nargs, ctx.memory, "toLower", return CallStringFunction(args, nargs, ctx.memory, "toLower",
[&](const auto &str) { [&](const auto &str) {
TypedValue::TString res(ctx.memory); TypedValue::TString res(ctx.memory);
@ -934,8 +921,8 @@ TypedValue ToLower(TypedValue *args, int64_t nargs,
}); });
} }
TypedValue ToUpper(TypedValue *args, int64_t nargs, TypedValue ToUpper(const TypedValue *args, int64_t nargs,
const EvaluationContext &ctx, database::GraphDbAccessor *) { const FunctionContext &ctx) {
return CallStringFunction(args, nargs, ctx.memory, "toUpper", return CallStringFunction(args, nargs, ctx.memory, "toUpper",
[&](const auto &str) { [&](const auto &str) {
TypedValue::TString res(ctx.memory); TypedValue::TString res(ctx.memory);
@ -944,9 +931,8 @@ TypedValue ToUpper(TypedValue *args, int64_t nargs,
}); });
} }
TypedValue Replace(TypedValue *args, int64_t nargs, TypedValue Replace(const TypedValue *args, int64_t nargs,
const EvaluationContext &ctx, const FunctionContext &ctx) {
database::GraphDbAccessor *dba) {
FType<Or<Null, String>, Or<Null, String>, Or<Null, String>>("replace", args, FType<Or<Null, String>, Or<Null, String>, Or<Null, String>>("replace", args,
nargs); nargs);
if (args[0].IsNull() || args[1].IsNull() || args[2].IsNull()) { if (args[0].IsNull() || args[1].IsNull() || args[2].IsNull()) {
@ -958,8 +944,8 @@ TypedValue Replace(TypedValue *args, int64_t nargs,
return TypedValue(std::move(replaced)); return TypedValue(std::move(replaced));
} }
TypedValue Split(TypedValue *args, int64_t nargs, const EvaluationContext &ctx, TypedValue Split(const TypedValue *args, int64_t nargs,
database::GraphDbAccessor *dba) { const FunctionContext &ctx) {
FType<Or<Null, String>, Or<Null, String>>("split", args, nargs); FType<Or<Null, String>, Or<Null, String>>("split", args, nargs);
if (args[0].IsNull() || args[1].IsNull()) { if (args[0].IsNull() || args[1].IsNull()) {
return TypedValue(ctx.memory); return TypedValue(ctx.memory);
@ -969,9 +955,8 @@ TypedValue Split(TypedValue *args, int64_t nargs, const EvaluationContext &ctx,
return TypedValue(std::move(result)); return TypedValue(std::move(result));
} }
TypedValue Substring(TypedValue *args, int64_t nargs, TypedValue Substring(const TypedValue *args, int64_t nargs,
const EvaluationContext &ctx, const FunctionContext &ctx) {
database::GraphDbAccessor *) {
FType<Or<Null, String>, NonNegativeInteger, Optional<NonNegativeInteger>>( FType<Or<Null, String>, NonNegativeInteger, Optional<NonNegativeInteger>>(
"substring", args, nargs); "substring", args, nargs);
if (args[0].IsNull()) return TypedValue(ctx.memory); if (args[0].IsNull()) return TypedValue(ctx.memory);
@ -984,8 +969,8 @@ TypedValue Substring(TypedValue *args, int64_t nargs,
} // namespace } // namespace
std::function<TypedValue(TypedValue *, int64_t, const EvaluationContext &ctx, std::function<TypedValue(const TypedValue *, int64_t,
database::GraphDbAccessor *)> const FunctionContext &ctx)>
NameToFunction(const std::string &function_name) { NameToFunction(const std::string &function_name) {
// Scalar functions // Scalar functions
if (function_name == "DEGREE") return Degree; if (function_name == "DEGREE") return Degree;

View File

@ -1,13 +1,19 @@
/// @file /// @file
#pragma once #pragma once
#include <vector> #include <functional>
#include <string>
#include <unordered_map>
#include "query/typed_value.hpp" #include "utils/memory.hpp"
namespace database {
class GraphDbAccessor;
}
namespace query { namespace query {
struct EvaluationContext; class TypedValue;
namespace { namespace {
const char kStartsWith[] = "STARTSWITH"; const char kStartsWith[] = "STARTSWITH";
@ -15,15 +21,21 @@ const char kEndsWith[] = "ENDSWITH";
const char kContains[] = "CONTAINS"; const char kContains[] = "CONTAINS";
} // namespace } // namespace
struct FunctionContext {
database::GraphDbAccessor *db_accessor;
utils::MemoryResource *memory;
int64_t timestamp;
std::unordered_map<std::string, int64_t> *counters;
};
/// Return the function implementation with the given name. /// Return the function implementation with the given name.
/// ///
/// Note, returned function signature uses C-style access to an array to allow /// Note, returned function signature uses C-style access to an array to allow
/// having an array stored anywhere the caller likes, as long as it is /// having an array stored anywhere the caller likes, as long as it is
/// contiguous in memory. Since most functions don't take many arguments, it's /// contiguous in memory. Since most functions don't take many arguments, it's
/// convenient to have them stored in the calling stack frame. /// convenient to have them stored in the calling stack frame.
std::function<TypedValue(TypedValue *arguments, int64_t num_arguments, std::function<TypedValue(const TypedValue *arguments, int64_t num_arguments,
const EvaluationContext &context, const FunctionContext &context)>
database::GraphDbAccessor *)>
NameToFunction(const std::string &function_name); NameToFunction(const std::string &function_name);
} // namespace query } // namespace query

View File

@ -371,6 +371,8 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
} }
TypedValue Visit(Function &function) override { TypedValue Visit(Function &function) override {
FunctionContext function_ctx{dba_, ctx_->memory, ctx_->timestamp,
&ctx_->counters};
// Stack allocate evaluated arguments when there's a small number of them. // Stack allocate evaluated arguments when there's a small number of them.
if (function.arguments_.size() <= 8) { if (function.arguments_.size() <= 8) {
TypedValue arguments[8] = { TypedValue arguments[8] = {
@ -382,7 +384,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
arguments[i] = function.arguments_[i]->Accept(*this); arguments[i] = function.arguments_[i]->Accept(*this);
} }
auto res = function.function_(arguments, function.arguments_.size(), auto res = function.function_(arguments, function.arguments_.size(),
*ctx_, dba_); function_ctx);
CHECK(res.GetMemoryResource() == ctx_->memory); CHECK(res.GetMemoryResource() == ctx_->memory);
return res; return res;
} else { } else {
@ -392,7 +394,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
arguments.emplace_back(argument->Accept(*this)); arguments.emplace_back(argument->Accept(*this));
} }
auto res = auto res =
function.function_(arguments.data(), arguments.size(), *ctx_, dba_); function.function_(arguments.data(), arguments.size(), function_ctx);
CHECK(res.GetMemoryResource() == ctx_->memory); CHECK(res.GetMemoryResource() == ctx_->memory);
return res; return res;
} }