From c830bc7d812193f84843725b46fca2750de842c8 Mon Sep 17 00:00:00 2001 From: niko4299 Date: Fri, 22 Jul 2022 16:47:04 +0200 Subject: [PATCH] Added edge filtering to storage, need to add filtering in simple Expand in operator.cpp --- src/auth/models.cpp | 6 +- src/memgraph.cpp | 2 +- src/query/db_accessor.hpp | 44 ++-- src/query/frontend/ast/ast.lcp | 4 +- .../frontend/ast/cypher_main_visitor.cpp | 9 +- .../opencypher/grammar/MemgraphCypher.g4 | 2 +- .../frontend/stripped_lexer_constants.hpp | 3 +- src/query/interpreter.cpp | 13 +- src/query/plan/operator.cpp | 67 ++++-- .../v2/replication/replication_server.cpp | 5 +- src/storage/v2/vertex_accessor.cpp | 227 ++++++++++-------- src/storage/v2/vertex_accessor.hpp | 15 +- 12 files changed, 226 insertions(+), 171 deletions(-) diff --git a/src/auth/models.cpp b/src/auth/models.cpp index 7e2cca0e5..fc6517fba 100644 --- a/src/auth/models.cpp +++ b/src/auth/models.cpp @@ -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"]); diff --git a/src/memgraph.cpp b/src/memgraph.cpp index 463c1f09c..6bee0e2fd 100644 --- a/src/memgraph.cpp +++ b/src/memgraph.cpp @@ -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); diff --git a/src/query/db_accessor.hpp b/src/query/db_accessor.hpp index eb1e93b12..64fcedbb2 100644 --- a/src/query/db_accessor.hpp +++ b/src/query/db_accessor.hpp @@ -11,14 +11,13 @@ #pragma once -#include #include #include #include -#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 &edge_types, + const FineGrainedAccessChecker *fine_grained_access_checker) const -> storage::Result { - 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 { - 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 { - auto maybe_edges = impl_.OutEdges(view, &execution_context.fine_grained_access_checker); + auto InEdges(storage::View view, const std::vector &edge_types, + const FineGrainedAccessChecker *fine_grained_access_checker, const VertexAccessor &dest) const + -> storage::Result { + 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 &edge_types, + const FineGrainedAccessChecker *fine_grained_access_checker) const -> storage::Result { - 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 { + 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 &edge_types, + const FineGrainedAccessChecker *fine_grained_access_checker, const VertexAccessor &dest) const + -> storage::Result { + 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 { size_t operator()(const memgraph::query::VertexAccessor &v) const { return std::hash{}(v.impl_); } diff --git a/src/query/frontend/ast/ast.lcp b/src/query/frontend/ast/ast.lcp index 32a7cad0e..c8bf8c06f 100644 --- a/src/query/frontend/ast/ast.lcp +++ b/src/query/frontend/ast/ast.lcp @@ -2267,8 +2267,8 @@ cpp<# #>cpp AuthQuery(Action action, std::string user, std::string role, std::string user_or_role, Expression *password, - std::vector privileges, - std::vector labels, std::vector edgeTypes) + std::vector privileges, std::vector labels, + std::vector edgeTypes) : action_(action), user_(user), role_(role), diff --git a/src/query/frontend/ast/cypher_main_visitor.cpp b/src/query/frontend/ast/cypher_main_visitor.cpp index 8aa2462d9..160a5dc8c 100644 --- a/src/query/frontend/ast/cypher_main_visitor.cpp +++ b/src/query/frontend/ast/cypher_main_visitor.cpp @@ -1298,7 +1298,9 @@ antlrcpp::Any CypherMainVisitor::visitDenyPrivilege(MemgraphCypher::DenyPrivileg auth->user_or_role_ = ctx->userOrRole->accept(this).as(); if (ctx->privilegeList()) { for (auto *privilege : ctx->privilegeList()->privilege()) { - if (privilege->LABELS()) { + if (privilege->EDGE_TYPES()) { + auth->edgetypes_ = privilege->edgeTypeList()->accept(this).as>(); + } else if (privilege->LABELS()) { auth->labels_ = privilege->labelList()->accept(this).as>(); } 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(); if (ctx->privilegeList()) { for (auto *privilege : ctx->privilegeList()->privilege()) { - if (privilege->LABELS()) { + if (privilege->EDGE_TYPES()) { + auth->edgetypes_ = privilege->edgeTypeList()->accept(this).as>(); + } else if (privilege->LABELS()) { auth->labels_ = privilege->labelList()->accept(this).as>(); } 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!"); } diff --git a/src/query/frontend/opencypher/grammar/MemgraphCypher.g4 b/src/query/frontend/opencypher/grammar/MemgraphCypher.g4 index 6ab820303..d5b8f0ee8 100644 --- a/src/query/frontend/opencypher/grammar/MemgraphCypher.g4 +++ b/src/query/frontend/opencypher/grammar/MemgraphCypher.g4 @@ -262,12 +262,12 @@ privilege : CREATE privilegeList : privilege ( ',' privilege )* ; - edgeTypeList : '*' | listOfEdgeTypes ; listOfEdgeTypes : edgeType ( ',' edgeType )* ; edgeType : COLON symbolicName ; + labelList : '*' | listOfLabels ; listOfLabels : label ( ',' label )* ; diff --git a/src/query/frontend/stripped_lexer_constants.hpp b/src/query/frontend/stripped_lexer_constants.hpp index b87f1893b..0fd4dfd22 100644 --- a/src/query/frontend/stripped_lexer_constants.hpp +++ b/src/query/frontend/stripped_lexer_constants.hpp @@ -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 kUnescapedNameAllowedStarts( diff --git a/src/query/interpreter.cpp b/src/query/interpreter.cpp index d537ad758..a12859cc8 100644 --- a/src/query/interpreter.cpp +++ b/src/query/interpreter.cpp @@ -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>(); @@ -968,7 +969,7 @@ PullPlan::PullPlan(const std::shared_ptr 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) { diff --git a/src/query/plan/operator.cpp b/src/query/plan/operator.cpp index a1f1e1c5f..63bdebceb 100644 --- a/src/query/plan/operator.cpp +++ b/src/query/plan/operator.cpp @@ -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 &edge_types, utils::MemoryResource *memory) { + const std::vector &edge_types, utils::MemoryResource *memory, + const ExecutionContext &context) { // wraps an EdgeAccessor into a pair 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 chain_elements(memory); + utils::pmr::vector + 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(), EdgeAtom::Direction::IN, - self_.common_.edge_types, utils::NewDeleteResource())); + using ExpandEdges = + decltype(ExpandFromVertex(std::declval(), EdgeAtom::Direction::IN, self_.common_.edge_types, + utils::NewDeleteResource(), std::declval())); utils::pmr::vector 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(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); } diff --git a/src/storage/v2/replication/replication_server.cpp b/src/storage/v2/replication/replication_server.cpp index fed501d6e..0dc1b387f 100644 --- a/src/storage/v2/replication/replication_server.cpp +++ b/src/storage/v2/replication/replication_server.cpp @@ -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]; diff --git a/src/storage/v2/vertex_accessor.cpp b/src/storage/v2/vertex_accessor.cpp index fa3d24964..789beb0e0 100644 --- a/src/storage/v2/vertex_accessor.cpp +++ b/src/storage/v2/vertex_accessor.cpp @@ -13,7 +13,6 @@ #include -#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> VertexAccessor::Properties(View view } Result> VertexAccessor::InEdges( - View view, const query::FineGrainedAccessChecker *fine_grained_access_checker, - const VertexAccessor *destination) const { + View view, const std::vector &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> 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 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 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 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 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 ret; @@ -426,8 +434,8 @@ Result> VertexAccessor::InEdges( } Result> VertexAccessor::OutEdges( - View view, const query::FineGrainedAccessChecker *fine_grained_access_checker, - const VertexAccessor *destination) const { + View view, const std::vector &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> 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 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 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 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 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 ret; diff --git a/src/storage/v2/vertex_accessor.hpp b/src/storage/v2/vertex_accessor.hpp index ab28241d8..695ef4828 100644 --- a/src/storage/v2/vertex_accessor.hpp +++ b/src/storage/v2/vertex_accessor.hpp @@ -14,11 +14,10 @@ #include #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> InEdges(View view, const ExecutionContex *execution_context = nullptr, - const VertexAccessor *destination = nullptr) const; + Result> InEdges( + View view, const std::vector &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> OutEdges(View view, const ExecutionContex *execution_context = nullptr, - const VertexAccessor *destination = nullptr) const; + Result> OutEdges( + View view, const std::vector &edge_types = {}, + const query::FineGrainedAccessChecker *fine_grained_access_checker = nullptr, + const VertexAccessor *destination = nullptr) const; Result InDegree(View view) const;