Added edge filtering to storage, need to add filtering in simple Expand in operator.cpp

This commit is contained in:
niko4299
2022-07-22 16:47:04 +02:00
parent ca6ee0c209
commit c830bc7d81
12 changed files with 226 additions and 171 deletions

View File

@@ -296,10 +296,12 @@ FineGrainedAccessHandler::FineGrainedAccessHandler(const FineGrainedAccessPermis
: label_permissions_(labelPermissions), edge_type_permissions_(edgeTypePermissions) {}
const FineGrainedAccessPermissions &FineGrainedAccessHandler::label_permissions() const { return label_permissions_; }
FineGrainedAccessPermissions &FineGrainedAccessHandler::label_permissions() { return label_permissions_; }
const FineGrainedAccessPermissions &FineGrainedAccessHandler::edge_type_permissions() const {
return edge_type_permissions_;
}
FineGrainedAccessPermissions &FineGrainedAccessHandler::edge_type_permissions() { return edge_type_permissions_; }
nlohmann::json FineGrainedAccessHandler::Serialize() const {
nlohmann::json data = nlohmann::json::object();
@@ -312,8 +314,8 @@ FineGrainedAccessHandler FineGrainedAccessHandler::Deserialize(const nlohmann::j
if (!data.is_object()) {
throw AuthException("Couldn't load role data!");
}
if (!data["fine_grained_access_handler"].is_object()) {
throw AuthException("Couldn't load FineGrainedAccessHandler data!");
if (!data["label_permissions"].is_object() && !data["edge_type_permissions"].is_object()) {
throw AuthException("Couldn't load label_permissions or edge_type_permissions data!");
}
auto label_permissions = FineGrainedAccessPermissions::Deserialize(data["label_permissions"]);
auto edge_type_permissions = FineGrainedAccessPermissions::Deserialize(data["edge_type_permissions"]);

View File

@@ -840,7 +840,7 @@ class AuthQueryHandler final : public memgraph::query::AuthQueryHandler {
edit_fun(&role->permissions(), permission);
}
for (const auto &label : labels) {
edit_fun(&user->fine_grained_access_handler().edge_type_permissions(), label);
edit_fun(&user->fine_grained_access_handler().label_permissions(), label);
}
for (const auto &edgeType : edgeTypes) {
edit_fun(&role->fine_grained_access_handler().edge_type_permissions(), edgeType);

View File

@@ -11,14 +11,13 @@
#pragma once
#include <cstddef>
#include <optional>
#include <cppitertools/filter.hpp>
#include <cppitertools/imap.hpp>
#include "query/context.hpp"
#include "query/exceptions.hpp"
#include "query/fine_grained_access_checker.hpp"
#include "storage/v2/id_types.hpp"
#include "storage/v2/property_value.hpp"
#include "storage/v2/result.hpp"
@@ -132,34 +131,48 @@ class VertexAccessor final {
return impl_.ClearProperties();
}
auto InEdges(storage::View view, const ExecutionContex &execution_context) const
auto InEdges(storage::View view, const std::vector<storage::EdgeTypeId> &edge_types,
const FineGrainedAccessChecker *fine_grained_access_checker) const
-> storage::Result<decltype(iter::imap(MakeEdgeAccessor, *impl_.InEdges(view)))> {
auto maybe_edges = impl_.InEdges(view, &execution_context.fine_grained_access_checker);
auto maybe_edges = impl_.InEdges(view, edge_types, fine_grained_access_checker);
if (maybe_edges.HasError()) return maybe_edges.GetError();
return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges));
}
auto InEdges(storage::View view) const { return InEdges(view, {}); }
auto InEdges(storage::View view, const ExecutionContex &execution_context, const VertexAccessor &dest) const
auto InEdges(storage::View view) const
-> storage::Result<decltype(iter::imap(MakeEdgeAccessor, *impl_.InEdges(view)))> {
auto maybe_edges = impl_.InEdges(view, &execution_context.fine_grained_access_checker, &dest.impl_);
auto maybe_edges = impl_.InEdges(view, {}, nullptr);
if (maybe_edges.HasError()) return maybe_edges.GetError();
return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges));
}
auto OutEdges(storage::View view, const ExecutionContex &execution_context) const
-> storage::Result<decltype(iter::imap(MakeEdgeAccessor, *impl_.OutEdges(view)))> {
auto maybe_edges = impl_.OutEdges(view, &execution_context.fine_grained_access_checker);
auto InEdges(storage::View view, const std::vector<storage::EdgeTypeId> &edge_types,
const FineGrainedAccessChecker *fine_grained_access_checker, const VertexAccessor &dest) const
-> storage::Result<decltype(iter::imap(MakeEdgeAccessor, *impl_.InEdges(view)))> {
auto maybe_edges = impl_.InEdges(view, edge_types, fine_grained_access_checker, &dest.impl_);
if (maybe_edges.HasError()) return maybe_edges.GetError();
return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges));
}
auto OutEdges(storage::View view) const { return OutEdges(view, {}); }
auto OutEdges(storage::View view, const ExecutionContex &execution_context, const VertexAccessor &dest) const
auto OutEdges(storage::View view, const std::vector<storage::EdgeTypeId> &edge_types,
const FineGrainedAccessChecker *fine_grained_access_checker) const
-> storage::Result<decltype(iter::imap(MakeEdgeAccessor, *impl_.OutEdges(view)))> {
auto maybe_edges = impl_.OutEdges(view, &execution_context.fine_grained_access_checker, &dest.impl_);
auto maybe_edges = impl_.OutEdges(view, edge_types, fine_grained_access_checker);
if (maybe_edges.HasError()) return maybe_edges.GetError();
return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges));
}
auto OutEdges(storage::View view) const
-> storage::Result<decltype(iter::imap(MakeEdgeAccessor, *impl_.OutEdges(view)))> {
auto maybe_edges = impl_.OutEdges(view, {}, nullptr);
if (maybe_edges.HasError()) return maybe_edges.GetError();
return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges));
}
auto OutEdges(storage::View view, const std::vector<storage::EdgeTypeId> &edge_types,
const FineGrainedAccessChecker *fine_grained_access_checker, const VertexAccessor &dest) const
-> storage::Result<decltype(iter::imap(MakeEdgeAccessor, *impl_.OutEdges(view)))> {
auto maybe_edges = impl_.OutEdges(view, edge_types, fine_grained_access_checker, &dest.impl_);
if (maybe_edges.HasError()) return maybe_edges.GetError();
return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges));
}
@@ -362,7 +375,6 @@ class DbAccessor final {
} // namespace memgraph::query
namespace std {
template <>
struct hash<memgraph::query::VertexAccessor> {
size_t operator()(const memgraph::query::VertexAccessor &v) const { return std::hash<decltype(v.impl_)>{}(v.impl_); }

View File

@@ -2267,8 +2267,8 @@ cpp<#
#>cpp
AuthQuery(Action action, std::string user, std::string role,
std::string user_or_role, Expression *password,
std::vector<Privilege> privileges,
std::vector<std::string> labels, std::vector<std::string> edgeTypes)
std::vector<Privilege> privileges, std::vector<std::string> labels,
std::vector<std::string> edgeTypes)
: action_(action),
user_(user),
role_(role),

View File

@@ -1298,7 +1298,9 @@ antlrcpp::Any CypherMainVisitor::visitDenyPrivilege(MemgraphCypher::DenyPrivileg
auth->user_or_role_ = ctx->userOrRole->accept(this).as<std::string>();
if (ctx->privilegeList()) {
for (auto *privilege : ctx->privilegeList()->privilege()) {
if (privilege->LABELS()) {
if (privilege->EDGE_TYPES()) {
auth->edgetypes_ = privilege->edgeTypeList()->accept(this).as<std::vector<std::string>>();
} else if (privilege->LABELS()) {
auth->labels_ = privilege->labelList()->accept(this).as<std::vector<std::string>>();
} else {
auth->privileges_.push_back(privilege->accept(this));
@@ -1320,7 +1322,9 @@ antlrcpp::Any CypherMainVisitor::visitRevokePrivilege(MemgraphCypher::RevokePriv
auth->user_or_role_ = ctx->userOrRole->accept(this).as<std::string>();
if (ctx->privilegeList()) {
for (auto *privilege : ctx->privilegeList()->privilege()) {
if (privilege->LABELS()) {
if (privilege->EDGE_TYPES()) {
auth->edgetypes_ = privilege->edgeTypeList()->accept(this).as<std::vector<std::string>>();
} else if (privilege->LABELS()) {
auth->labels_ = privilege->labelList()->accept(this).as<std::vector<std::string>>();
} else {
auth->privileges_.push_back(privilege->accept(this));
@@ -1387,7 +1391,6 @@ antlrcpp::Any CypherMainVisitor::visitPrivilege(MemgraphCypher::PrivilegeContext
if (ctx->MODULE_READ()) return AuthQuery::Privilege::MODULE_READ;
if (ctx->MODULE_WRITE()) return AuthQuery::Privilege::MODULE_WRITE;
if (ctx->WEBSOCKET()) return AuthQuery::Privilege::WEBSOCKET;
if (ctx->EDGE_TYPES()) return AuthQuery::Privilege::EDGE_TYPES;
LOG_FATAL("Should not get here - unknown privilege!");
}

View File

@@ -262,12 +262,12 @@ privilege : CREATE
privilegeList : privilege ( ',' privilege )* ;
edgeTypeList : '*' | listOfEdgeTypes ;
listOfEdgeTypes : edgeType ( ',' edgeType )* ;
edgeType : COLON symbolicName ;
labelList : '*' | listOfLabels ;
listOfLabels : label ( ',' label )* ;

View File

@@ -206,9 +206,8 @@ const trie::Trie kKeywords = {"union",
"version",
"websocket",
"foreach",
"labels",
"edge_types"};
"labels"
};
// Unicode codepoints that are allowed at the start of the unescaped name.
const std::bitset<kBitsetSize> kUnescapedNameAllowedStarts(

View File

@@ -319,10 +319,11 @@ Callback HandleAuthQuery(AuthQuery *auth_query, AuthQueryHandler *auth, const Pa
AuthQuery::Action::REVOKE_PRIVILEGE, AuthQuery::Action::SHOW_PRIVILEGES, AuthQuery::Action::SHOW_USERS_FOR_ROLE,
AuthQuery::Action::SHOW_ROLE_FOR_USER};
if (license_check_result.HasError() && enterprise_only_methods.contains(auth_query->action_)) {
throw utils::BasicException(
utils::license::LicenseCheckErrorToString(license_check_result.GetError(), "advanced authentication features"));
}
// if (license_check_result.HasError() && enterprise_only_methods.contains(auth_query->action_)) {
// throw utils::BasicException(
// utils::license::LicenseCheckErrorToString(license_check_result.GetError(), "advanced authentication
// features"));
// }
switch (auth_query->action_) {
case AuthQuery::Action::CREATE_USER:
@@ -336,7 +337,7 @@ Callback HandleAuthQuery(AuthQuery *auth_query, AuthQueryHandler *auth, const Pa
// If the license is not valid we create users with admin access
if (!valid_enterprise_license) {
spdlog::warn("Granting all the privileges to {}.", username);
auth->GrantPrivilege(username, kPrivilegesAll, {"*"});
auth->GrantPrivilege(username, kPrivilegesAll, {"*"}, {"*"});
}
return std::vector<std::vector<TypedValue>>();
@@ -968,7 +969,7 @@ PullPlan::PullPlan(const std::shared_ptr<CachedPlan> plan, const Parameters &par
#ifdef MG_ENTERPRISE
if (username.has_value()) {
memgraph::auth::User *user = interpreter_context->auth->GetUser(*username);
ctx_.fine_grained_access_checker = new FineGrainedAccessChecker{user};
ctx_.fine_grained_access_checker = new FineGrainedAccessChecker{user, dba};
}
#endif
if (interpreter_context->config.execution_timeout_sec > 0) {

View File

@@ -739,11 +739,13 @@ bool Expand::ExpandCursor::InitEdges(Frame &frame, ExecutionContext &context) {
// old_node_value may be Null when using optional matching
if (!existing_node.IsNull()) {
ExpectType(self_.common_.node_symbol, existing_node, TypedValue::Type::Vertex);
in_edges_.emplace(UnwrapEdgesResult(
vertex.InEdges(self_.view_, context.fine_grained_access_checker, existing_node.ValueVertex())));
in_edges_.emplace(
UnwrapEdgesResult(vertex.InEdges(self_.view_, self_.common_.edge_types,
context.fine_grained_access_checker, existing_node.ValueVertex())));
}
} else {
in_edges_.emplace(UnwrapEdgesResult(vertex.InEdges(self_.view_, context.fine_grained_access_checker)));
in_edges_.emplace(UnwrapEdgesResult(
vertex.InEdges(self_.view_, self_.common_.edge_types, context.fine_grained_access_checker)));
}
if (in_edges_) {
in_edges_it_.emplace(in_edges_->begin());
@@ -756,11 +758,13 @@ bool Expand::ExpandCursor::InitEdges(Frame &frame, ExecutionContext &context) {
// old_node_value may be Null when using optional matching
if (!existing_node.IsNull()) {
ExpectType(self_.common_.node_symbol, existing_node, TypedValue::Type::Vertex);
out_edges_.emplace(UnwrapEdgesResult(
vertex.OutEdges(self_.view_, context.fine_grained_access_checker, existing_node.ValueVertex())));
out_edges_.emplace(
UnwrapEdgesResult(vertex.OutEdges(self_.view_, self_.common_.edge_types,
context.fine_grained_access_checker, existing_node.ValueVertex())));
}
} else {
out_edges_.emplace(UnwrapEdgesResult(vertex.OutEdges(self_.view_, context.fine_grained_access_checker)));
out_edges_.emplace(UnwrapEdgesResult(
vertex.OutEdges(self_.view_, self_.common_.edge_types, context.fine_grained_access_checker)));
}
if (out_edges_) {
out_edges_it_.emplace(out_edges_->begin());
@@ -817,7 +821,8 @@ namespace {
* @return See above.
*/
auto ExpandFromVertex(const VertexAccessor &vertex, EdgeAtom::Direction direction,
const std::vector<storage::EdgeTypeId> &edge_types, utils::MemoryResource *memory) {
const std::vector<storage::EdgeTypeId> &edge_types, utils::MemoryResource *memory,
const ExecutionContext &context) {
// wraps an EdgeAccessor into a pair <accessor, direction>
auto wrapper = [](EdgeAtom::Direction direction, auto &&edges) {
return iter::imap([direction](const auto &edge) { return std::make_pair(edge, direction); },
@@ -825,16 +830,18 @@ auto ExpandFromVertex(const VertexAccessor &vertex, EdgeAtom::Direction directio
};
storage::View view = storage::View::OLD;
utils::pmr::vector<decltype(wrapper(direction, *vertex.InEdges(view, edge_types)))> chain_elements(memory);
utils::pmr::vector<decltype(wrapper(direction,
*vertex.InEdges(view, edge_types, context.fine_grained_access_checker)))>
chain_elements(memory);
if (direction != EdgeAtom::Direction::OUT) {
auto edges = UnwrapEdgesResult(vertex.InEdges(view, edge_types));
auto edges = UnwrapEdgesResult(vertex.InEdges(view, edge_types, context.fine_grained_access_checker));
if (edges.begin() != edges.end()) {
chain_elements.emplace_back(wrapper(EdgeAtom::Direction::IN, std::move(edges)));
}
}
if (direction != EdgeAtom::Direction::IN) {
auto edges = UnwrapEdgesResult(vertex.OutEdges(view, edge_types));
auto edges = UnwrapEdgesResult(vertex.OutEdges(view, edge_types, context.fine_grained_access_checker));
if (edges.begin() != edges.end()) {
chain_elements.emplace_back(wrapper(EdgeAtom::Direction::OUT, std::move(edges)));
}
@@ -899,8 +906,9 @@ class ExpandVariableCursor : public Cursor {
// a stack of edge iterables corresponding to the level/depth of
// the expansion currently being Pulled
using ExpandEdges = decltype(ExpandFromVertex(std::declval<VertexAccessor>(), EdgeAtom::Direction::IN,
self_.common_.edge_types, utils::NewDeleteResource()));
using ExpandEdges =
decltype(ExpandFromVertex(std::declval<VertexAccessor>(), EdgeAtom::Direction::IN, self_.common_.edge_types,
utils::NewDeleteResource(), std::declval<ExecutionContext>()));
utils::pmr::vector<ExpandEdges> edges_;
// an iterator indicating the position in the corresponding edges_ element
@@ -941,7 +949,8 @@ class ExpandVariableCursor : public Cursor {
if (upper_bound_ > 0) {
auto *memory = edges_.get_allocator().GetMemoryResource();
edges_.emplace_back(ExpandFromVertex(vertex, self_.common_.direction, self_.common_.edge_types, memory));
edges_.emplace_back(
ExpandFromVertex(vertex, self_.common_.direction, self_.common_.edge_types, memory, context));
edges_it_.emplace_back(edges_.back().begin());
}
@@ -1041,7 +1050,7 @@ class ExpandVariableCursor : public Cursor {
if (upper_bound_ > static_cast<int64_t>(edges_.size())) {
auto *memory = edges_.get_allocator().GetMemoryResource();
edges_.emplace_back(
ExpandFromVertex(current_vertex, self_.common_.direction, self_.common_.edge_types, memory));
ExpandFromVertex(current_vertex, self_.common_.direction, self_.common_.edge_types, memory, context));
edges_it_.emplace_back(edges_.back().begin());
}
@@ -1184,7 +1193,8 @@ class STShortestPathCursor : public query::plan::Cursor {
for (const auto &vertex : source_frontier) {
if (self_.common_.direction != EdgeAtom::Direction::IN) {
auto out_edges = UnwrapEdgesResult(vertex.OutEdges(storage::View::OLD, self_.common_.edge_types));
auto out_edges = UnwrapEdgesResult(
vertex.OutEdges(storage::View::OLD, self_.common_.edge_types, context.fine_grained_access_checker));
for (const auto &edge : out_edges) {
if (ShouldExpand(edge.To(), edge, frame, evaluator) && !Contains(in_edge, edge.To())) {
in_edge.emplace(edge.To(), edge);
@@ -1201,7 +1211,8 @@ class STShortestPathCursor : public query::plan::Cursor {
}
}
if (self_.common_.direction != EdgeAtom::Direction::OUT) {
auto in_edges = UnwrapEdgesResult(vertex.InEdges(storage::View::OLD, self_.common_.edge_types));
auto in_edges = UnwrapEdgesResult(
vertex.InEdges(storage::View::OLD, self_.common_.edge_types, context.fine_grained_access_checker));
for (const auto &edge : in_edges) {
if (ShouldExpand(edge.From(), edge, frame, evaluator) && !Contains(in_edge, edge.From())) {
in_edge.emplace(edge.From(), edge);
@@ -1232,7 +1243,8 @@ class STShortestPathCursor : public query::plan::Cursor {
// reversed.
for (const auto &vertex : sink_frontier) {
if (self_.common_.direction != EdgeAtom::Direction::OUT) {
auto out_edges = UnwrapEdgesResult(vertex.OutEdges(storage::View::OLD, self_.common_.edge_types));
auto out_edges = UnwrapEdgesResult(
vertex.OutEdges(storage::View::OLD, self_.common_.edge_types, context.fine_grained_access_checker));
for (const auto &edge : out_edges) {
if (ShouldExpand(vertex, edge, frame, evaluator) && !Contains(out_edge, edge.To())) {
out_edge.emplace(edge.To(), edge);
@@ -1249,7 +1261,8 @@ class STShortestPathCursor : public query::plan::Cursor {
}
}
if (self_.common_.direction != EdgeAtom::Direction::IN) {
auto in_edges = UnwrapEdgesResult(vertex.InEdges(storage::View::OLD, self_.common_.edge_types));
auto in_edges = UnwrapEdgesResult(
vertex.InEdges(storage::View::OLD, self_.common_.edge_types, context.fine_grained_access_checker));
for (const auto &edge : in_edges) {
if (ShouldExpand(vertex, edge, frame, evaluator) && !Contains(out_edge, edge.From())) {
out_edge.emplace(edge.From(), edge);
@@ -1323,13 +1336,15 @@ class SingleSourceShortestPathCursor : public query::plan::Cursor {
// populates the to_visit_next_ structure with expansions
// from the given vertex. skips expansions that don't satisfy
// the "where" condition.
auto expand_from_vertex = [this, &expand_pair](const auto &vertex) {
auto expand_from_vertex = [this, &expand_pair, &context](const auto &vertex) {
if (self_.common_.direction != EdgeAtom::Direction::IN) {
auto out_edges = UnwrapEdgesResult(vertex.OutEdges(storage::View::OLD, self_.common_.edge_types));
auto out_edges = UnwrapEdgesResult(
vertex.OutEdges(storage::View::OLD, self_.common_.edge_types, context.fine_grained_access_checker));
for (const auto &edge : out_edges) expand_pair(edge, edge.To());
}
if (self_.common_.direction != EdgeAtom::Direction::OUT) {
auto in_edges = UnwrapEdgesResult(vertex.InEdges(storage::View::OLD, self_.common_.edge_types));
auto in_edges = UnwrapEdgesResult(
vertex.InEdges(storage::View::OLD, self_.common_.edge_types, context.fine_grained_access_checker));
for (const auto &edge : in_edges) expand_pair(edge, edge.From());
}
};
@@ -1505,16 +1520,18 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor {
// Populates the priority queue structure with expansions
// from the given vertex. skips expansions that don't satisfy
// the "where" condition.
auto expand_from_vertex = [this, &expand_pair](const VertexAccessor &vertex, const TypedValue &weight,
int64_t depth) {
auto expand_from_vertex = [this, &expand_pair, &context](const VertexAccessor &vertex, const TypedValue &weight,
int64_t depth) {
if (self_.common_.direction != EdgeAtom::Direction::IN) {
auto out_edges = UnwrapEdgesResult(vertex.OutEdges(storage::View::OLD, self_.common_.edge_types));
auto out_edges = UnwrapEdgesResult(
vertex.OutEdges(storage::View::OLD, self_.common_.edge_types, context.fine_grained_access_checker));
for (const auto &edge : out_edges) {
expand_pair(edge, edge.To(), weight, depth);
}
}
if (self_.common_.direction != EdgeAtom::Direction::OUT) {
auto in_edges = UnwrapEdgesResult(vertex.InEdges(storage::View::OLD, self_.common_.edge_types));
auto in_edges = UnwrapEdgesResult(
vertex.InEdges(storage::View::OLD, self_.common_.edge_types, context.fine_grained_access_checker));
for (const auto &edge : in_edges) {
expand_pair(edge, edge.From(), weight, depth);
}

View File

@@ -403,8 +403,9 @@ uint64_t Storage::ReplicationServer::ReadAndApplyDelta(durability::BaseDecoder *
if (!from_vertex) throw utils::BasicException("Invalid transaction!");
auto to_vertex = transaction->FindVertex(delta.edge_create_delete.to_vertex, storage::View::NEW);
if (!to_vertex) throw utils::BasicException("Invalid transaction!");
auto edges = from_vertex->OutEdges(
storage::View::NEW, {transaction->NameToEdgeType(delta.edge_create_delete.edge_type)}, &*to_vertex);
auto edges =
from_vertex->OutEdges(storage::View::NEW, {transaction->NameToEdgeType(delta.edge_create_delete.edge_type)},
nullptr, &*to_vertex);
if (edges.HasError()) throw utils::BasicException("Invalid transaction!");
if (edges->size() != 1) throw utils::BasicException("Invalid transaction!");
auto &edge = (*edges)[0];

View File

@@ -13,7 +13,6 @@
#include <memory>
#include "query/context.hpp"
#include "query/fine_grained_access_checker.hpp"
#include "storage/v2/edge_accessor.hpp"
#include "storage/v2/id_types.hpp"
@@ -342,8 +341,8 @@ Result<std::map<PropertyId, PropertyValue>> VertexAccessor::Properties(View view
}
Result<std::vector<EdgeAccessor>> VertexAccessor::InEdges(
View view, const query::FineGrainedAccessChecker *fine_grained_access_checker,
const VertexAccessor *destination) const {
View view, const std::vector<storage::EdgeTypeId> &edge_types,
const query::FineGrainedAccessChecker *fine_grained_access_checker, const VertexAccessor *destination) const {
MG_ASSERT(!destination || destination->transaction_ == transaction_, "Invalid accessor!");
bool exists = true;
bool deleted = false;
@@ -358,62 +357,71 @@ Result<std::vector<EdgeAccessor>> VertexAccessor::InEdges(
for (const auto &item : vertex_->in_edges) {
const auto &[edge_type, from_vertex, edge] = item;
if (destination && from_vertex != destination->vertex_) continue;
if (!fine_grained_access_checker && fine_grained_access_checker->IsUserAuthorizedEdgeType(edge_type) &&
fine_grained_access_checker->IsUserAuthorizedLabels(from_vertex->labels))
if (!edge_types.empty() && std::find(edge_types.begin(), edge_types.end(), edge_type) == edge_types.end())
continue;
if (fine_grained_access_checker && (!fine_grained_access_checker->IsUserAuthorizedEdgeType(edge_type) ||
!fine_grained_access_checker->IsUserAuthorizedLabels(from_vertex->labels)))
continue;
in_edges.push_back(item);
}
}
delta = vertex_->delta;
}
ApplyDeltasForRead(transaction_, delta, view,
[&exists, &deleted, &in_edges, &fine_grained_access_checker, &destination](const Delta &delta) {
switch (delta.action) {
case Delta::Action::ADD_IN_EDGE: {
if (destination && delta.vertex_edge.vertex != destination->vertex_) break;
if (!fine_grained_access_checker &&
fine_grained_access_checker->IsUserAuthorizedEdgeType(delta.vertex_edge.edge_type) &&
fine_grained_access_checker->IsUserAuthorizedLabels(delta.vertex_edge.vertex->labels))
break;
// Add the edge because we don't see the removal.
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link{
delta.vertex_edge.edge_type, delta.vertex_edge.vertex, delta.vertex_edge.edge};
auto it = std::find(in_edges.begin(), in_edges.end(), link);
MG_ASSERT(it == in_edges.end(), "Invalid database state!");
in_edges.push_back(link);
break;
}
case Delta::Action::REMOVE_IN_EDGE: {
if (destination && delta.vertex_edge.vertex != destination->vertex_) break;
if (!fine_grained_access_checker &&
fine_grained_access_checker->IsUserAuthorizedEdgeType(delta.vertex_edge.edge_type) &&
fine_grained_access_checker->IsUserAuthorizedLabels(delta.vertex_edge.vertex->labels))
break;
// Remove the label because we don't see the addition.
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link{
delta.vertex_edge.edge_type, delta.vertex_edge.vertex, delta.vertex_edge.edge};
auto it = std::find(in_edges.begin(), in_edges.end(), link);
MG_ASSERT(it != in_edges.end(), "Invalid database state!");
std::swap(*it, *in_edges.rbegin());
in_edges.pop_back();
break;
}
case Delta::Action::DELETE_OBJECT: {
exists = false;
break;
}
case Delta::Action::RECREATE_OBJECT: {
deleted = false;
break;
}
case Delta::Action::ADD_LABEL:
case Delta::Action::REMOVE_LABEL:
case Delta::Action::SET_PROPERTY:
case Delta::Action::ADD_OUT_EDGE:
case Delta::Action::REMOVE_OUT_EDGE:
break;
}
});
ApplyDeltasForRead(
transaction_, delta, view,
[&exists, &deleted, &in_edges, &edge_types, &fine_grained_access_checker, &destination](const Delta &delta) {
switch (delta.action) {
case Delta::Action::ADD_IN_EDGE: {
if (destination && delta.vertex_edge.vertex != destination->vertex_) break;
if (!edge_types.empty() &&
std::find(edge_types.begin(), edge_types.end(), delta.vertex_edge.edge_type) == edge_types.end())
break;
if (fine_grained_access_checker &&
(!fine_grained_access_checker->IsUserAuthorizedEdgeType(delta.vertex_edge.edge_type) ||
!fine_grained_access_checker->IsUserAuthorizedLabels(delta.vertex_edge.vertex->labels)))
break;
// Add the edge because we don't see the removal.
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link{delta.vertex_edge.edge_type, delta.vertex_edge.vertex,
delta.vertex_edge.edge};
auto it = std::find(in_edges.begin(), in_edges.end(), link);
MG_ASSERT(it == in_edges.end(), "Invalid database state!");
in_edges.push_back(link);
break;
}
case Delta::Action::REMOVE_IN_EDGE: {
if (destination && delta.vertex_edge.vertex != destination->vertex_) break;
if (!edge_types.empty() &&
std::find(edge_types.begin(), edge_types.end(), delta.vertex_edge.edge_type) == edge_types.end())
break;
if (fine_grained_access_checker &&
(!fine_grained_access_checker->IsUserAuthorizedEdgeType(delta.vertex_edge.edge_type) ||
!fine_grained_access_checker->IsUserAuthorizedLabels(delta.vertex_edge.vertex->labels)))
break;
// Remove the label because we don't see the addition.
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link{delta.vertex_edge.edge_type, delta.vertex_edge.vertex,
delta.vertex_edge.edge};
auto it = std::find(in_edges.begin(), in_edges.end(), link);
MG_ASSERT(it != in_edges.end(), "Invalid database state!");
std::swap(*it, *in_edges.rbegin());
in_edges.pop_back();
break;
}
case Delta::Action::DELETE_OBJECT: {
exists = false;
break;
}
case Delta::Action::RECREATE_OBJECT: {
deleted = false;
break;
}
case Delta::Action::ADD_LABEL:
case Delta::Action::REMOVE_LABEL:
case Delta::Action::SET_PROPERTY:
case Delta::Action::ADD_OUT_EDGE:
case Delta::Action::REMOVE_OUT_EDGE:
break;
}
});
if (!exists) return Error::NONEXISTENT_OBJECT;
if (deleted) return Error::DELETED_OBJECT;
std::vector<EdgeAccessor> ret;
@@ -426,8 +434,8 @@ Result<std::vector<EdgeAccessor>> VertexAccessor::InEdges(
}
Result<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(
View view, const query::FineGrainedAccessChecker *fine_grained_access_checker,
const VertexAccessor *destination) const {
View view, const std::vector<storage::EdgeTypeId> &edge_types,
const query::FineGrainedAccessChecker *fine_grained_access_checker, const VertexAccessor *destination) const {
MG_ASSERT(!destination || destination->transaction_ == transaction_, "Invalid accessor!");
bool exists = true;
bool deleted = false;
@@ -442,62 +450,71 @@ Result<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(
for (const auto &item : vertex_->out_edges) {
const auto &[edge_type, to_vertex, edge] = item;
if (destination && to_vertex != destination->vertex_) continue;
if (!fine_grained_access_checker && fine_grained_access_checker->IsUserAuthorizedEdgeType(edge_type) &&
fine_grained_access_checker->IsUserAuthorizedLabels(to_vertex->labels))
if (!edge_types.empty() && std::find(edge_types.begin(), edge_types.end(), edge_type) == edge_types.end())
continue;
if (fine_grained_access_checker && (!fine_grained_access_checker->IsUserAuthorizedEdgeType(edge_type) ||
!fine_grained_access_checker->IsUserAuthorizedLabels(to_vertex->labels)))
continue;
out_edges.push_back(item);
}
}
delta = vertex_->delta;
}
ApplyDeltasForRead(transaction_, delta, view,
[&exists, &deleted, &out_edges, &fine_grained_access_checker, &destination](const Delta &delta) {
switch (delta.action) {
case Delta::Action::ADD_OUT_EDGE: {
if (destination && delta.vertex_edge.vertex != destination->vertex_) break;
if (!fine_grained_access_checker &&
fine_grained_access_checker->IsUserAuthorizedEdgeType(delta.vertex_edge.edge_type) &&
fine_grained_access_checker->IsUserAuthorizedLabels(delta.vertex_edge.vertex->labels))
break;
// Add the edge because we don't see the removal.
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link{
delta.vertex_edge.edge_type, delta.vertex_edge.vertex, delta.vertex_edge.edge};
auto it = std::find(out_edges.begin(), out_edges.end(), link);
MG_ASSERT(it == out_edges.end(), "Invalid database state!");
out_edges.push_back(link);
break;
}
case Delta::Action::REMOVE_OUT_EDGE: {
if (destination && delta.vertex_edge.vertex != destination->vertex_) break;
if (!fine_grained_access_checker &&
fine_grained_access_checker->IsUserAuthorizedEdgeType(delta.vertex_edge.edge_type) &&
fine_grained_access_checker->IsUserAuthorizedLabels(delta.vertex_edge.vertex->labels))
break;
// Remove the label because we don't see the addition.
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link{
delta.vertex_edge.edge_type, delta.vertex_edge.vertex, delta.vertex_edge.edge};
auto it = std::find(out_edges.begin(), out_edges.end(), link);
MG_ASSERT(it != out_edges.end(), "Invalid database state!");
std::swap(*it, *out_edges.rbegin());
out_edges.pop_back();
break;
}
case Delta::Action::DELETE_OBJECT: {
exists = false;
break;
}
case Delta::Action::RECREATE_OBJECT: {
deleted = false;
break;
}
case Delta::Action::ADD_LABEL:
case Delta::Action::REMOVE_LABEL:
case Delta::Action::SET_PROPERTY:
case Delta::Action::ADD_IN_EDGE:
case Delta::Action::REMOVE_IN_EDGE:
break;
}
});
ApplyDeltasForRead(
transaction_, delta, view,
[&exists, &deleted, &out_edges, &edge_types, &fine_grained_access_checker, &destination](const Delta &delta) {
switch (delta.action) {
case Delta::Action::ADD_OUT_EDGE: {
if (destination && delta.vertex_edge.vertex != destination->vertex_) break;
if (!edge_types.empty() &&
std::find(edge_types.begin(), edge_types.end(), delta.vertex_edge.edge_type) == edge_types.end())
break;
if (fine_grained_access_checker &&
(!fine_grained_access_checker->IsUserAuthorizedEdgeType(delta.vertex_edge.edge_type) ||
!fine_grained_access_checker->IsUserAuthorizedLabels(delta.vertex_edge.vertex->labels)))
break;
// Add the edge because we don't see the removal.
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link{delta.vertex_edge.edge_type, delta.vertex_edge.vertex,
delta.vertex_edge.edge};
auto it = std::find(out_edges.begin(), out_edges.end(), link);
MG_ASSERT(it == out_edges.end(), "Invalid database state!");
out_edges.push_back(link);
break;
}
case Delta::Action::REMOVE_OUT_EDGE: {
if (destination && delta.vertex_edge.vertex != destination->vertex_) break;
if (!edge_types.empty() &&
std::find(edge_types.begin(), edge_types.end(), delta.vertex_edge.edge_type) == edge_types.end())
break;
if (fine_grained_access_checker &&
(!fine_grained_access_checker->IsUserAuthorizedEdgeType(delta.vertex_edge.edge_type) ||
!fine_grained_access_checker->IsUserAuthorizedLabels(delta.vertex_edge.vertex->labels)))
break;
// Remove the label because we don't see the addition.
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link{delta.vertex_edge.edge_type, delta.vertex_edge.vertex,
delta.vertex_edge.edge};
auto it = std::find(out_edges.begin(), out_edges.end(), link);
MG_ASSERT(it != out_edges.end(), "Invalid database state!");
std::swap(*it, *out_edges.rbegin());
out_edges.pop_back();
break;
}
case Delta::Action::DELETE_OBJECT: {
exists = false;
break;
}
case Delta::Action::RECREATE_OBJECT: {
deleted = false;
break;
}
case Delta::Action::ADD_LABEL:
case Delta::Action::REMOVE_LABEL:
case Delta::Action::SET_PROPERTY:
case Delta::Action::ADD_IN_EDGE:
case Delta::Action::REMOVE_IN_EDGE:
break;
}
});
if (!exists) return Error::NONEXISTENT_OBJECT;
if (deleted) return Error::DELETED_OBJECT;
std::vector<EdgeAccessor> ret;

View File

@@ -14,11 +14,10 @@
#include <optional>
#include "query/fine_grained_access_checker.hpp"
#include "storage/v2/vertex.hpp"
#include "storage/v2/config.hpp"
#include "storage/v2/result.hpp"
#include "storage/v2/transaction.hpp"
#include "storage/v2/vertex.hpp"
#include "storage/v2/view.hpp"
namespace memgraph::storage {
@@ -82,14 +81,18 @@ class VertexAccessor final {
/// @throw std::bad_alloc
/// @throw std::length_error if the resulting vector exceeds
/// std::vector::max_size().
Result<std::vector<EdgeAccessor>> InEdges(View view, const ExecutionContex *execution_context = nullptr,
const VertexAccessor *destination = nullptr) const;
Result<std::vector<EdgeAccessor>> InEdges(
View view, const std::vector<storage::EdgeTypeId> &edge_types = {},
const query::FineGrainedAccessChecker *fine_grained_access_checker = nullptr,
const VertexAccessor *destination = nullptr) const;
/// @throw std::bad_alloc
/// @throw std::length_error if the resulting vector exceeds
/// std::vector::max_size().
Result<std::vector<EdgeAccessor>> OutEdges(View view, const ExecutionContex *execution_context = nullptr,
const VertexAccessor *destination = nullptr) const;
Result<std::vector<EdgeAccessor>> OutEdges(
View view, const std::vector<storage::EdgeTypeId> &edge_types = {},
const query::FineGrainedAccessChecker *fine_grained_access_checker = nullptr,
const VertexAccessor *destination = nullptr) const;
Result<size_t> InDegree(View view) const;