From 7bd45f87144c9a2a07b3ddac856732a6177a6797 Mon Sep 17 00:00:00 2001 From: Teon Banek <teon.banek@memgraph.io> Date: Wed, 11 Sep 2019 16:10:53 +0200 Subject: [PATCH] Make query execution work with storage_v2 Reviewers: mferencevic, ipaljak Reviewed By: mferencevic Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D2203 --- src/CMakeLists.txt | 53 ++ src/database/single_node/dump.cpp | 101 +++- src/database/single_node/dump.hpp | 16 +- src/glue/communication.cpp | 24 + src/memgraph.cpp | 10 + src/memgraph_init.cpp | 59 +- src/memgraph_init.hpp | 18 + src/query/common.cpp | 48 -- src/query/common.hpp | 31 +- src/query/context.hpp | 14 +- src/query/db_accessor.hpp | 22 +- .../interpret/awesome_memgraph_functions.cpp | 88 ++- .../interpret/awesome_memgraph_functions.hpp | 9 +- src/query/interpret/eval.hpp | 144 +++-- src/query/interpreter.cpp | 169 ++++-- src/query/interpreter.hpp | 32 +- src/query/path.hpp | 17 +- src/query/plan/operator.cpp | 513 ++++++++++++------ src/query/plan/operator.lcp | 11 +- src/query/plan/pretty_print.cpp | 47 +- src/query/plan/pretty_print.hpp | 41 +- src/query/plan/rewrite/index_lookup.hpp | 6 +- src/query/plan/rule_based_planner.hpp | 6 +- src/query/plan/vertex_count_cache.hpp | 10 +- src/query/repl.cpp | 5 +- src/query/transaction_engine.hpp | 37 +- src/query/typed_value.cpp | 4 +- src/query/typed_value.hpp | 4 +- src/storage/common/types/types.hpp | 11 + src/storage/edge_accessor.hpp | 5 + src/storage/single_node/record_accessor.hpp | 2 + src/storage/v2/edge_accessor.hpp | 2 + src/storage/v2/storage.cpp | 5 + src/storage/vertex_accessor.hpp | 5 + tests/benchmark/expansion.cpp | 6 +- tests/benchmark/query/eval.cpp | 9 +- tests/benchmark/query/execution.cpp | 47 +- tests/benchmark/query/planner.cpp | 9 +- tests/manual/interactive_planning.cpp | 15 +- tests/manual/single_query.cpp | 5 +- .../memgraph_V1/features/memgraph.feature | 2 +- tests/unit/CMakeLists.txt | 33 +- tests/unit/bfs_common.hpp | 44 +- tests/unit/bfs_single_node.cpp | 4 +- tests/unit/bolt_encoder.cpp | 9 +- tests/unit/database_dump.cpp | 48 +- tests/unit/database_transaction_timeout.cpp | 6 +- tests/unit/interpreter.cpp | 47 +- tests/unit/plan_pretty_print.cpp | 3 +- tests/unit/query_expression_evaluator.cpp | 114 ++-- .../unit/query_plan_accumulate_aggregate.cpp | 36 +- tests/unit/query_plan_bag_semantics.cpp | 18 +- tests/unit/query_plan_checker.hpp | 18 +- tests/unit/query_plan_common.hpp | 2 +- .../query_plan_create_set_remove_delete.cpp | 166 ++++-- tests/unit/query_plan_edge_cases.cpp | 3 +- tests/unit/query_plan_match_filter_return.cpp | 189 ++++--- ...query_plan_v2_create_set_remove_delete.cpp | 119 ++++ tests/unit/query_variable_start_planner.cpp | 43 +- tests/unit/typed_value.cpp | 8 +- 60 files changed, 1694 insertions(+), 878 deletions(-) create mode 100644 tests/unit/query_plan_v2_create_set_remove_delete.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index af4c17a43..4fa35d7ac 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -108,6 +108,59 @@ target_compile_definitions(mg-single-node PUBLIC MG_SINGLE_NODE) # END Memgraph Single Node # ---------------------------------------------------------------------------- +# ---------------------------------------------------------------------------- +# Memgraph Single Node v2 +# ---------------------------------------------------------------------------- +set(mg_single_node_v2_sources + ${lcp_common_cpp_files} + audit/log.cpp + database/single_node/dump.cpp + glue/auth.cpp + glue/communication.cpp + query/common.cpp + query/frontend/ast/cypher_main_visitor.cpp + query/frontend/ast/pretty_print.cpp + query/frontend/parsing.cpp + query/frontend/semantic/required_privileges.cpp + query/frontend/semantic/symbol_generator.cpp + query/frontend/stripped.cpp + query/interpret/awesome_memgraph_functions.cpp + query/interpreter.cpp + query/plan/operator.cpp + query/plan/preprocess.cpp + query/plan/pretty_print.cpp + query/plan/profile.cpp + query/plan/rewrite/index_lookup.cpp + query/plan/rule_based_planner.cpp + query/plan/variable_start_planner.cpp + query/typed_value.cpp + memgraph_init.cpp +) + +set(MG_SINGLE_NODE_V2_LIBS stdc++fs Threads::Threads fmt cppitertools + antlr_opencypher_parser_lib dl glog gflags mg-storage-v2 + mg-utils mg-io mg-requests mg-communication) +# These are enterprise subsystems +set(MG_SINGLE_NODE_V2_LIBS ${MG_SINGLE_NODE_V2_LIBS} mg-integrations-kafka mg-auth) + +if (USE_LTALLOC) + list(APPEND MG_SINGLE_NODE_V2_LIBS ltalloc) + # TODO(mferencevic): Enable this when clang is updated on apollo. + # set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto") +endif() + +add_library(mg-single-node-v2 STATIC ${mg_single_node_v2_sources}) +target_link_libraries(mg-single-node-v2 ${MG_SINGLE_NODE_V2_LIBS}) +add_dependencies(mg-single-node-v2 generate_opencypher_parser) +add_dependencies(mg-single-node-v2 generate_lcp_common) +target_compile_definitions(mg-single-node-v2 PUBLIC MG_SINGLE_NODE_V2) +add_executable(memgraph-v2 memgraph.cpp) +target_link_libraries(memgraph-v2 mg-single-node-v2 kvstore_lib telemetry_lib) + +# ---------------------------------------------------------------------------- +# END Memgraph Single Node v2 +# ---------------------------------------------------------------------------- + # ---------------------------------------------------------------------------- # Memgraph Single Node High Availability # ---------------------------------------------------------------------------- diff --git a/src/database/single_node/dump.cpp b/src/database/single_node/dump.cpp index 50e049bbf..f419c906a 100644 --- a/src/database/single_node/dump.cpp +++ b/src/database/single_node/dump.cpp @@ -10,7 +10,7 @@ #include <glog/logging.h> -#include "database/graph_db_accessor.hpp" +#include "query/exceptions.hpp" #include "utils/algorithm.hpp" #include "utils/string.hpp" @@ -75,8 +75,12 @@ void DumpPropertyValue(std::ostream *os, const PropertyValue &value) { } } -void DumpProperties(std::ostream *os, GraphDbAccessor *dba, +void DumpProperties(std::ostream *os, query::DbAccessor *dba, +#ifdef MG_SINGLE_NODE_V2 + const std::map<storage::Property, PropertyValue> &store, +#else const PropertyValueStore &store, +#endif std::optional<uint64_t> property_id = std::nullopt) { *os << "{"; if (property_id) { @@ -84,89 +88,136 @@ void DumpProperties(std::ostream *os, GraphDbAccessor *dba, if (store.size() > 0) *os << ", "; } utils::PrintIterable(*os, store, ", ", [&dba](auto &os, const auto &kv) { - os << dba->PropertyName(kv.first) << ": "; + os << dba->PropertyToName(kv.first) << ": "; DumpPropertyValue(&os, kv.second); }); *os << "}"; } -void DumpVertex(std::ostream *os, GraphDbAccessor *dba, - const VertexAccessor &vertex) { +void DumpVertex(std::ostream *os, query::DbAccessor *dba, + const query::VertexAccessor &vertex) { *os << "CREATE ("; *os << ":" << kInternalVertexLabel; - for (const auto &label : vertex.labels()) { - *os << ":" << dba->LabelName(label); + auto maybe_labels = vertex.Labels(storage::View::OLD); + if (maybe_labels.HasError()) { + switch (maybe_labels.GetError()) { + case storage::Error::DELETED_OBJECT: + throw query::QueryRuntimeException( + "Trying to get labels from a deleted node."); + case storage::Error::SERIALIZATION_ERROR: + case storage::Error::VERTEX_HAS_EDGES: + throw query::QueryRuntimeException( + "Unexpected error when getting labels."); + } + } + for (const auto &label : *maybe_labels) { + *os << ":" << dba->LabelToName(label); } *os << " "; - DumpProperties(os, dba, vertex.Properties(), + auto maybe_props = vertex.Properties(storage::View::OLD); + if (maybe_props.HasError()) { + switch (maybe_props.GetError()) { + case storage::Error::DELETED_OBJECT: + throw query::QueryRuntimeException( + "Trying to get properties from a deleted object."); + case storage::Error::SERIALIZATION_ERROR: + case storage::Error::VERTEX_HAS_EDGES: + throw query::QueryRuntimeException( + "Unexpected error when getting properties."); + } + } + DumpProperties(os, dba, *maybe_props, std::optional<uint64_t>(vertex.CypherId())); *os << ");"; } -void DumpEdge(std::ostream *os, GraphDbAccessor *dba, - const EdgeAccessor &edge) { +void DumpEdge(std::ostream *os, query::DbAccessor *dba, + const query::EdgeAccessor &edge) { *os << "MATCH "; *os << "(u:" << kInternalVertexLabel << "), "; *os << "(v:" << kInternalVertexLabel << ")"; *os << " WHERE "; - *os << "u." << kInternalPropertyId << " = " << edge.from().CypherId(); + *os << "u." << kInternalPropertyId << " = " << edge.From().CypherId(); *os << " AND "; - *os << "v." << kInternalPropertyId << " = " << edge.to().CypherId() << " "; + *os << "v." << kInternalPropertyId << " = " << edge.To().CypherId() << " "; *os << "CREATE (u)-["; - *os << ":" << dba->EdgeTypeName(edge.EdgeType()); - const auto &props = edge.Properties(); - if (props.size() > 0) { + *os << ":" << dba->EdgeTypeToName(edge.EdgeType()); + auto maybe_props = edge.Properties(storage::View::OLD); + if (maybe_props.HasError()) { + switch (maybe_props.GetError()) { + case storage::Error::DELETED_OBJECT: + throw query::QueryRuntimeException( + "Trying to get properties from a deleted object."); + case storage::Error::SERIALIZATION_ERROR: + case storage::Error::VERTEX_HAS_EDGES: + throw query::QueryRuntimeException( + "Unexpected error when getting properties."); + } + } + if (maybe_props->size() > 0) { *os << " "; - DumpProperties(os, dba, edge.Properties()); + DumpProperties(os, dba, *maybe_props); } *os << "]->(v);"; } -void DumpIndexKey(std::ostream *os, GraphDbAccessor *dba, +#ifndef MG_SINGLE_NODE_V2 +void DumpIndexKey(std::ostream *os, query::DbAccessor *dba, const LabelPropertyIndex::Key &key) { - *os << "CREATE INDEX ON :" << dba->LabelName(key.label_) << "(" - << dba->PropertyName(key.property_) << ");"; + *os << "CREATE INDEX ON :" << dba->LabelToName(key.label_) << "(" + << dba->PropertyToName(key.property_) << ");"; } void DumpUniqueConstraint( - std::ostream *os, GraphDbAccessor *dba, + std::ostream *os, query::DbAccessor *dba, const storage::constraints::ConstraintEntry &constraint) { - *os << "CREATE CONSTRAINT ON (u:" << dba->LabelName(constraint.label) + *os << "CREATE CONSTRAINT ON (u:" << dba->LabelToName(constraint.label) << ") ASSERT "; utils::PrintIterable(*os, constraint.properties, ", ", [&dba](auto &os, const auto &property) { - os << "u." << dba->PropertyName(property); + os << "u." << dba->PropertyToName(property); }); *os << " IS UNIQUE;"; } +#endif } // namespace -CypherDumpGenerator::CypherDumpGenerator(GraphDbAccessor *dba) +CypherDumpGenerator::CypherDumpGenerator(query::DbAccessor *dba) : dba_(dba), created_internal_index_(false), cleaned_internal_index_(false), cleaned_internal_label_property_(false) { CHECK(dba); +#ifdef MG_SINGLE_NODE_V2 + throw utils::NotYetImplemented("Dumping indices and constraints"); +#else indices_state_.emplace(dba->GetIndicesKeys()); unique_constraints_state_.emplace(dba->ListUniqueConstraints()); - vertices_state_.emplace(dba->Vertices(false)); - edges_state_.emplace(dba->Edges(false)); +#endif + vertices_state_.emplace(dba->Vertices(storage::View::OLD)); + edges_state_.emplace(dba->Edges(storage::View::OLD)); } bool CypherDumpGenerator::NextQuery(std::ostream *os) { +#ifdef MG_SINGLE_NODE_V2 + if (!vertices_state_->Empty() && !created_internal_index_) { +#else if (!indices_state_->ReachedEnd()) { DumpIndexKey(os, dba_, *indices_state_->GetCurrentAndAdvance()); return true; } else if (!vertices_state_->Empty() && !created_internal_index_) { +#endif *os << "CREATE INDEX ON :" << kInternalVertexLabel << "(" << kInternalPropertyId << ");"; created_internal_index_ = true; return true; +#ifndef MG_SINGLE_NODE_V2 } else if (!unique_constraints_state_->ReachedEnd()) { DumpUniqueConstraint(os, dba_, *unique_constraints_state_->GetCurrentAndAdvance()); return true; +#endif } else if (!vertices_state_->ReachedEnd()) { DumpVertex(os, dba_, *vertices_state_->GetCurrentAndAdvance()); return true; diff --git a/src/database/single_node/dump.hpp b/src/database/single_node/dump.hpp index 58842d68e..14078c324 100644 --- a/src/database/single_node/dump.hpp +++ b/src/database/single_node/dump.hpp @@ -2,8 +2,11 @@ #include <ostream> -#include "database/graph_db_accessor.hpp" +// TODO: Move this whole file to query folder +#include "query/db_accessor.hpp" +#ifndef MG_SINGLE_NODE_V2 #include "storage/common/constraints/unique_constraints.hpp" +#endif namespace database { @@ -14,7 +17,7 @@ namespace database { /// queries. class CypherDumpGenerator { public: - explicit CypherDumpGenerator(GraphDbAccessor *dba); + explicit CypherDumpGenerator(query::DbAccessor *dba); CypherDumpGenerator(const CypherDumpGenerator &other) = delete; // NOLINTNEXTLINE(performance-noexcept-move-constructor) @@ -64,20 +67,23 @@ class CypherDumpGenerator { bool empty_; }; - GraphDbAccessor *dba_; + query::DbAccessor *dba_; bool created_internal_index_; bool cleaned_internal_index_; bool cleaned_internal_label_property_; +#ifndef MG_SINGLE_NODE_V2 std::optional<ContainerState<std::vector<LabelPropertyIndex::Key>>> indices_state_; std::optional< ContainerState<std::vector<storage::constraints::ConstraintEntry>>> unique_constraints_state_; - std::optional<ContainerState<decltype(dba_->Vertices(false))>> +#endif + std::optional<ContainerState<decltype(dba_->Vertices(storage::View::OLD))>> vertices_state_; - std::optional<ContainerState<decltype(dba_->Edges(false))>> edges_state_; + std::optional<ContainerState<decltype(dba_->Edges(storage::View::OLD))>> + edges_state_; }; } // namespace database diff --git a/src/glue/communication.cpp b/src/glue/communication.cpp index f3cf3b95d..880775bf1 100644 --- a/src/glue/communication.cpp +++ b/src/glue/communication.cpp @@ -49,6 +49,30 @@ query::TypedValue ToTypedValue(const Value &value) { } } +#ifdef MG_SINGLE_NODE_V2 +storage::Result<communication::bolt::Vertex> ToBoltVertex( + const query::VertexAccessor &vertex, const storage::Storage &db, + storage::View view) { + return ToBoltVertex(vertex.impl_, db, view); +} + +storage::Result<communication::bolt::Edge> ToBoltEdge( + const query::EdgeAccessor &edge, const storage::Storage &db, + storage::View view) { + return ToBoltEdge(edge.impl_, db, view); +} +#else +communication::bolt::Vertex ToBoltVertex(const query::VertexAccessor &vertex, + storage::View view) { + return ToBoltVertex(vertex.impl_, view); +} + +communication::bolt::Edge ToBoltEdge(const query::EdgeAccessor &edge, + storage::View view) { + return ToBoltEdge(edge.impl_, view); +} +#endif + #ifdef MG_SINGLE_NODE_V2 storage::Result<Value> ToBoltValue(const query::TypedValue &value, const storage::Storage &db, diff --git a/src/memgraph.cpp b/src/memgraph.cpp index d3e1b8c75..f71d66399 100644 --- a/src/memgraph.cpp +++ b/src/memgraph.cpp @@ -10,7 +10,11 @@ #include <glog/logging.h> #include "communication/server.hpp" +#ifdef MG_SINGLE_NODE_V2 +#include "storage/v2/storage.hpp" +#else #include "database/single_node/graph_db.hpp" +#endif #include "integrations/kafka/exceptions.hpp" #include "integrations/kafka/streams.hpp" #include "memgraph_init.hpp" @@ -88,7 +92,11 @@ void SingleNodeMain() { // Main storage and execution engines initialization +#ifdef MG_SINGLE_NODE_V2 + storage::Storage db; +#else database::GraphDb db; +#endif query::Interpreter interpreter; SessionData session_data{&db, &interpreter, &auth, &audit_log}; @@ -123,6 +131,7 @@ void SingleNodeMain() { // Setup telemetry std::optional<telemetry::Telemetry> telemetry; +#ifndef MG_SINGLE_NODE_V2 if (FLAGS_telemetry_enabled) { telemetry.emplace( "https://telemetry.memgraph.com/88b5e7e8-746a-11e8-9f85-538a9e9690cc/", @@ -132,6 +141,7 @@ void SingleNodeMain() { return {{"vertices", dba.VerticesCount()}, {"edges", dba.EdgesCount()}}; }); } +#endif // Handler for regular termination signals auto shutdown = [&server] { diff --git a/src/memgraph_init.cpp b/src/memgraph_init.cpp index 8df44cb5e..c3c349b5f 100644 --- a/src/memgraph_init.cpp +++ b/src/memgraph_init.cpp @@ -29,6 +29,9 @@ BoltSession::BoltSession(SessionData *data, : communication::bolt::Session<communication::InputStream, communication::OutputStream>(input_stream, output_stream), +#ifdef MG_SINGLE_NODE_V2 + db_(data->db), +#endif transaction_engine_(data->db, data->interpreter), #ifndef MG_SINGLE_NODE_HA auth_(data->auth), @@ -78,12 +81,30 @@ std::vector<std::string> BoltSession::Interpret( std::map<std::string, communication::bolt::Value> BoltSession::PullAll( TEncoder *encoder) { try { +#ifdef MG_SINGLE_NODE_V2 + TypedValueResultStream stream(encoder, db_); +#else TypedValueResultStream stream(encoder); +#endif const auto &summary = transaction_engine_.PullAll(&stream); std::map<std::string, communication::bolt::Value> decoded_summary; for (const auto &kv : summary) { +#ifdef MG_SINGLE_NODE_V2 + auto maybe_value = glue::ToBoltValue(kv.second, *db_, storage::View::NEW); + if (maybe_value.HasError()) { + switch (maybe_value.GetError()) { + case storage::Error::DELETED_OBJECT: + case storage::Error::SERIALIZATION_ERROR: + case storage::Error::VERTEX_HAS_EDGES: + throw communication::bolt::ClientError( + "Unexpected storage error when streaming summary."); + } + } + decoded_summary.emplace(kv.first, std::move(*maybe_value)); +#else decoded_summary.emplace(kv.first, glue::ToBoltValue(kv.second, storage::View::NEW)); +#endif } return decoded_summary; } catch (const query::QueryException &e) { @@ -106,15 +127,37 @@ bool BoltSession::Authenticate(const std::string &username, #endif } +#ifdef MG_SINGLE_NODE_V2 +BoltSession::TypedValueResultStream::TypedValueResultStream( + TEncoder *encoder, const storage::Storage *db) + : encoder_(encoder), db_(db) {} +#else BoltSession::TypedValueResultStream::TypedValueResultStream(TEncoder *encoder) : encoder_(encoder) {} +#endif void BoltSession::TypedValueResultStream::Result( const std::vector<query::TypedValue> &values) { std::vector<communication::bolt::Value> decoded_values; decoded_values.reserve(values.size()); for (const auto &v : values) { +#ifdef MG_SINGLE_NODE_V2 + auto maybe_value = glue::ToBoltValue(v, *db_, storage::View::NEW); + if (maybe_value.HasError()) { + switch (maybe_value.GetError()) { + case storage::Error::DELETED_OBJECT: + throw communication::bolt::ClientError( + "Returning a deleted object as a result."); + case storage::Error::VERTEX_HAS_EDGES: + case storage::Error::SERIALIZATION_ERROR: + throw communication::bolt::ClientError( + "Unexpected storage error when streaming results."); + } + } + decoded_values.emplace_back(std::move(*maybe_value)); +#else decoded_values.push_back(glue::ToBoltValue(v, storage::View::NEW)); +#endif } encoder_->MessageRecord(decoded_values); } @@ -123,15 +166,29 @@ void KafkaStreamWriter( SessionData &session_data, const std::string &query, const std::map<std::string, communication::bolt::Value> ¶ms) { auto dba = session_data.db->Access(); + query::DbAccessor execution_dba(&dba); KafkaResultStream stream; std::map<std::string, PropertyValue> params_pv; for (const auto &kv : params) params_pv.emplace(kv.first, glue::ToPropertyValue(kv.second)); try { - (*session_data.interpreter)(query, dba, params_pv, false, + (*session_data.interpreter)(query, &execution_dba, params_pv, false, utils::NewDeleteResource()) .PullAll(stream); +#ifdef MG_SINGLE_NODE_V2 + auto maybe_constraint_violation = dba.Commit(); + if (maybe_constraint_violation.HasError()) { + const auto &constraint_violation = maybe_constraint_violation.GetError(); + auto label_name = dba.LabelToName(constraint_violation.label); + auto property_name = dba.PropertyToName(constraint_violation.property); + LOG(WARNING) << fmt::format( + "[Kafka] query execution failed with an exception: " + "Unable to commit due to constraint violation on :{}({}).", + label_name, property_name); + } +#else dba.Commit(); +#endif } catch (const utils::BasicException &e) { LOG(WARNING) << "[Kafka] query execution failed with an exception: " << e.what(); diff --git a/src/memgraph_init.hpp b/src/memgraph_init.hpp index 8f0899279..a5006b019 100644 --- a/src/memgraph_init.hpp +++ b/src/memgraph_init.hpp @@ -18,6 +18,12 @@ #include "query/interpreter.hpp" #include "query/transaction_engine.hpp" +#ifdef MG_SINGLE_NODE_V2 +namespace database { +using GraphDb = storage::Storage; +} +#endif + DECLARE_string(durability_directory); /// Encapsulates Dbms and Interpreter that are passed through the network server @@ -65,14 +71,26 @@ class BoltSession final /// before forwarding the calls to original TEncoder. class TypedValueResultStream { public: +#ifdef MG_SINGLE_NODE_V2 + TypedValueResultStream(TEncoder *encoder, const storage::Storage *db); +#else TypedValueResultStream(TEncoder *encoder); +#endif void Result(const std::vector<query::TypedValue> &values); private: TEncoder *encoder_; +#ifdef MG_SINGLE_NODE_V2 + // NOTE: Needed only for ToBoltValue conversions + const storage::Storage *db_; +#endif }; +#ifdef MG_SINGLE_NODE_V2 + // NOTE: Needed only for ToBoltValue conversions + const storage::Storage *db_; +#endif query::TransactionEngine transaction_engine_; #ifndef MG_SINGLE_NODE_HA auth::Auth *auth_; diff --git a/src/query/common.cpp b/src/query/common.cpp index b3cd0626d..ff463ac49 100644 --- a/src/query/common.cpp +++ b/src/query/common.cpp @@ -2,39 +2,6 @@ namespace query { -void ReconstructTypedValue(TypedValue &value) { - using Type = TypedValue::Type; - switch (value.type()) { - case Type::Vertex: - if (!value.ValueVertex().Reconstruct()) throw ReconstructionException(); - break; - case Type::Edge: - if (!value.ValueEdge().Reconstruct()) throw ReconstructionException(); - break; - case Type::List: - for (TypedValue &inner_value : value.ValueList()) - ReconstructTypedValue(inner_value); - break; - case Type::Map: - for (auto &kv : value.ValueMap()) - ReconstructTypedValue(kv.second); - break; - case Type::Path: - for (auto &vertex : value.ValuePath().vertices()) { - if (!vertex.Reconstruct()) throw ReconstructionException(); - } - for (auto &edge : value.ValuePath().edges()) { - if (!edge.Reconstruct()) throw ReconstructionException(); - } - case Type::Null: - case Type::Bool: - case Type::Int: - case Type::Double: - case Type::String: - break; - } -} - namespace impl { bool TypedValueCompare(const TypedValue &a, const TypedValue &b) { @@ -81,19 +48,4 @@ bool TypedValueCompare(const TypedValue &a, const TypedValue &b) { } // namespace impl -template <typename TAccessor> -void SwitchAccessor(TAccessor &accessor, storage::View view) { - switch (view) { - case storage::View::NEW: - accessor.SwitchNew(); - break; - case storage::View::OLD: - accessor.SwitchOld(); - break; - } -} - -template void SwitchAccessor<>(VertexAccessor &accessor, storage::View view); -template void SwitchAccessor<>(EdgeAccessor &accessor, storage::View view); - } // namespace query diff --git a/src/query/common.hpp b/src/query/common.hpp index 2312e498a..668b58e87 100644 --- a/src/query/common.hpp +++ b/src/query/common.hpp @@ -6,7 +6,7 @@ #include <glog/logging.h> -#include "database/graph_db_accessor.hpp" +#include "query/db_accessor.hpp" #include "query/exceptions.hpp" #include "query/frontend/ast/ast.hpp" #include "query/frontend/semantic/symbol.hpp" @@ -16,11 +16,6 @@ namespace query { -/// Recursively reconstruct all the accessors in the given TypedValue. -/// -/// @throw ReconstructionException if any reconstruction failed. -void ReconstructTypedValue(TypedValue &value); - namespace impl { bool TypedValueCompare(const TypedValue &a, const TypedValue &b); } // namespace impl @@ -66,10 +61,6 @@ class TypedValueVectorCompare final { std::vector<Ordering> ordering_; }; -/// Switch the given [Vertex/Edge]Accessor to the desired state. -template <class TAccessor> -void SwitchAccessor(TAccessor &accessor, storage::View view); - /// Raise QueryRuntimeException if the value for symbol isn't of expected type. inline void ExpectType(const Symbol &symbol, const TypedValue &value, TypedValue::Type expected) { @@ -85,15 +76,23 @@ template <class TRecordAccessor> void PropsSetChecked(TRecordAccessor *record, const storage::Property &key, const TypedValue &value) { try { - record->PropsSet(key, PropertyValue(value)); + auto maybe_error = record->SetProperty(key, PropertyValue(value)); + if (maybe_error.HasError()) { + switch (maybe_error.GetError()) { + case storage::Error::SERIALIZATION_ERROR: + throw QueryRuntimeException( + "Can't serialize due to concurrent operations."); + case storage::Error::DELETED_OBJECT: + throw QueryRuntimeException( + "Trying to set properties on a deleted object."); + case storage::Error::VERTEX_HAS_EDGES: + throw QueryRuntimeException( + "Unexpected error when setting a property."); + } + } } catch (const TypedValueException &) { throw QueryRuntimeException("'{}' cannot be used as a property value.", value.type()); - } catch (const RecordDeletedError &) { - throw QueryRuntimeException( - "Trying to set properties on a deleted graph element."); - } catch (const database::ConstraintViolationException &e) { - throw QueryRuntimeException(e.what()); } } diff --git a/src/query/context.hpp b/src/query/context.hpp index 101f6fb8f..da6933f8d 100644 --- a/src/query/context.hpp +++ b/src/query/context.hpp @@ -1,6 +1,6 @@ #pragma once -#include "database/graph_db_accessor.hpp" +#include "query/common.hpp" #include "query/frontend/semantic/symbol_table.hpp" #include "query/parameters.hpp" #include "query/plan/profile.hpp" @@ -26,29 +26,27 @@ struct EvaluationContext { }; inline std::vector<storage::Property> NamesToProperties( - const std::vector<std::string> &property_names, - database::GraphDbAccessor *dba) { + const std::vector<std::string> &property_names, DbAccessor *dba) { std::vector<storage::Property> properties; properties.reserve(property_names.size()); for (const auto &name : property_names) { - properties.push_back(dba->Property(name)); + properties.push_back(dba->NameToProperty(name)); } return properties; } inline std::vector<storage::Label> NamesToLabels( - const std::vector<std::string> &label_names, - database::GraphDbAccessor *dba) { + const std::vector<std::string> &label_names, DbAccessor *dba) { std::vector<storage::Label> labels; labels.reserve(label_names.size()); for (const auto &name : label_names) { - labels.push_back(dba->Label(name)); + labels.push_back(dba->NameToLabel(name)); } return labels; } struct ExecutionContext { - database::GraphDbAccessor *db_accessor{nullptr}; + DbAccessor *db_accessor{nullptr}; SymbolTable symbol_table; EvaluationContext evaluation_context; bool is_profile_query{false}; diff --git a/src/query/db_accessor.hpp b/src/query/db_accessor.hpp index c3c2f6ddc..34b29f6fa 100644 --- a/src/query/db_accessor.hpp +++ b/src/query/db_accessor.hpp @@ -625,19 +625,20 @@ class DbAccessor final { bool MustAbort() const { return false; } + // TODO: Index manipulation should not go through Accessor bool CreateIndex(storage::Label label, storage::Property prop) { - return accessor_->CreateIndex(label, prop); + throw utils::NotYetImplemented("CreateIndex"); } bool DropIndex(storage::Label label, storage::Property prop) { - return accessor_->DropIndex(label, prop); + throw utils::NotYetImplemented("DropIndex"); } - // TODO: These should probably be in some kind of StorageInfo class instead of - // here. + // TODO: Querying information should probably be in some kind of StorageInfo + // class instead of here in Accessor. bool LabelPropertyIndexExists(storage::Label label, storage::Property prop) const { - return accessor_->LabelPropertyIndexExists(label, prop); + throw utils::NotYetImplemented("LabelPropertyIndexExists"); } int64_t VerticesCount() const { return accessor_->ApproximateVertexCount(); } @@ -663,14 +664,15 @@ class DbAccessor final { return accessor_->ApproximateVertexCount(label, property, lower, upper); } - auto CreateExistenceConstraint(storage::Label label, - storage::Property property) { - return accessor_->CreateExistenceConstraint(label, property); + // TODO: Constraints manipulation should not go through Accessor + utils::BasicResult<storage::ExistenceConstraintViolation, bool> + CreateExistenceConstraint(storage::Label label, storage::Property property) { + throw utils::NotYetImplemented("CreateExistenceConstraint"); } - auto DropExistenceConstraint(storage::Label label, + bool DropExistenceConstraint(storage::Label label, storage::Property property) { - return accessor_->DropExistenceConstraint(label, property); + throw utils::NotYetImplemented("DropExistenceConstraint"); } }; #else diff --git a/src/query/interpret/awesome_memgraph_functions.cpp b/src/query/interpret/awesome_memgraph_functions.cpp index 45f5fa637..83ad64cc5 100644 --- a/src/query/interpret/awesome_memgraph_functions.cpp +++ b/src/query/interpret/awesome_memgraph_functions.cpp @@ -7,7 +7,10 @@ #include <functional> #include <random> -#include "database/graph_db_accessor.hpp" +#ifndef MG_SINGLE_NODE_V2 +#include "database/single_node/dump.hpp" +#endif +#include "query/db_accessor.hpp" #include "query/exceptions.hpp" #include "query/typed_value.hpp" #include "utils/string.hpp" @@ -336,7 +339,7 @@ TypedValue EndNode(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { FType<Or<Null, Edge>>("endNode", args, nargs); 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(const TypedValue *args, int64_t nargs, @@ -363,8 +366,20 @@ TypedValue Properties(const TypedValue *args, int64_t nargs, auto *dba = ctx.db_accessor; auto get_properties = [&](const auto &record_accessor) { TypedValue::TMap properties(ctx.memory); - for (const auto &property : record_accessor.Properties()) { - properties.emplace(dba->PropertyName(property.first), property.second); + auto maybe_props = record_accessor.Properties(ctx.view); + if (maybe_props.HasError()) { + switch (maybe_props.GetError()) { + case storage::Error::DELETED_OBJECT: + throw QueryRuntimeException( + "Trying to get properties from a deleted object."); + case storage::Error::SERIALIZATION_ERROR: + case storage::Error::VERTEX_HAS_EDGES: + throw QueryRuntimeException( + "Unexpected error when getting properties."); + } + } + for (const auto &property : *maybe_props) { + properties.emplace(dba->PropertyToName(property.first), property.second); } return TypedValue(std::move(properties)); }; @@ -411,17 +426,35 @@ TypedValue StartNode(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { FType<Or<Null, Edge>>("startNode", args, nargs); if (args[0].IsNull()) return TypedValue(ctx.memory); - return TypedValue(args[0].ValueEdge().from(), ctx.memory); + return TypedValue(args[0].ValueEdge().From(), ctx.memory); } +namespace { + +size_t UnwrapDegreeResult(storage::Result<size_t> maybe_degree) { + if (maybe_degree.HasError()) { + switch (maybe_degree.GetError()) { + case storage::Error::DELETED_OBJECT: + throw QueryRuntimeException("Trying to get degree of a deleted node."); + case storage::Error::SERIALIZATION_ERROR: + case storage::Error::VERTEX_HAS_EDGES: + throw QueryRuntimeException( + "Unexpected error when getting node degree."); + } + } + return *maybe_degree; +} + +} // namespace + TypedValue Degree(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { FType<Or<Null, Vertex>>("degree", args, nargs); if (args[0].IsNull()) return TypedValue(ctx.memory); const auto &vertex = args[0].ValueVertex(); - return TypedValue( - static_cast<int64_t>(vertex.out_degree() + vertex.in_degree()), - ctx.memory); + size_t out_degree = UnwrapDegreeResult(vertex.OutDegree(ctx.view)); + size_t in_degree = UnwrapDegreeResult(vertex.InDegree(ctx.view)); + return TypedValue(static_cast<int64_t>(out_degree + in_degree), ctx.memory); } TypedValue InDegree(const TypedValue *args, int64_t nargs, @@ -429,7 +462,8 @@ TypedValue InDegree(const TypedValue *args, int64_t nargs, FType<Or<Null, Vertex>>("inDegree", args, nargs); if (args[0].IsNull()) return TypedValue(ctx.memory); const auto &vertex = args[0].ValueVertex(); - return TypedValue(static_cast<int64_t>(vertex.in_degree()), ctx.memory); + size_t in_degree = UnwrapDegreeResult(vertex.InDegree(ctx.view)); + return TypedValue(static_cast<int64_t>(in_degree), ctx.memory); } TypedValue OutDegree(const TypedValue *args, int64_t nargs, @@ -437,7 +471,8 @@ TypedValue OutDegree(const TypedValue *args, int64_t nargs, FType<Or<Null, Vertex>>("outDegree", args, nargs); if (args[0].IsNull()) return TypedValue(ctx.memory); const auto &vertex = args[0].ValueVertex(); - return TypedValue(static_cast<int64_t>(vertex.out_degree()), ctx.memory); + size_t out_degree = UnwrapDegreeResult(vertex.OutDegree(ctx.view)); + return TypedValue(static_cast<int64_t>(out_degree), ctx.memory); } TypedValue ToBoolean(const TypedValue *args, int64_t nargs, @@ -521,18 +556,30 @@ TypedValue Type(const TypedValue *args, int64_t nargs, FType<Or<Null, Edge>>("type", args, nargs); auto *dba = ctx.db_accessor; if (args[0].IsNull()) return TypedValue(ctx.memory); - return TypedValue(dba->EdgeTypeName(args[0].ValueEdge().EdgeType()), + return TypedValue(dba->EdgeTypeToName(args[0].ValueEdge().EdgeType()), ctx.memory); } +// TODO: How is Keys different from Properties function? TypedValue Keys(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { FType<Or<Null, Vertex, Edge>>("keys", args, nargs); auto *dba = ctx.db_accessor; auto get_keys = [&](const auto &record_accessor) { TypedValue::TVector keys(ctx.memory); - for (const auto &property : record_accessor.Properties()) { - keys.emplace_back(dba->PropertyName(property.first)); + auto maybe_props = record_accessor.Properties(ctx.view); + if (maybe_props.HasError()) { + switch (maybe_props.GetError()) { + case storage::Error::DELETED_OBJECT: + throw QueryRuntimeException( + "Trying to get keys from a deleted object."); + case storage::Error::SERIALIZATION_ERROR: + case storage::Error::VERTEX_HAS_EDGES: + throw QueryRuntimeException("Unexpected error when getting keys."); + } + } + for (const auto &property : *maybe_props) { + keys.emplace_back(dba->PropertyToName(property.first)); } return TypedValue(std::move(keys)); }; @@ -554,8 +601,19 @@ TypedValue Labels(const TypedValue *args, int64_t nargs, auto *dba = ctx.db_accessor; if (args[0].IsNull()) return TypedValue(ctx.memory); TypedValue::TVector labels(ctx.memory); - for (const auto &label : args[0].ValueVertex().labels()) { - labels.emplace_back(dba->LabelName(label)); + auto maybe_labels = args[0].ValueVertex().Labels(ctx.view); + if (maybe_labels.HasError()) { + switch (maybe_labels.GetError()) { + case storage::Error::DELETED_OBJECT: + throw QueryRuntimeException( + "Trying to get labels from a deleted node."); + case storage::Error::SERIALIZATION_ERROR: + case storage::Error::VERTEX_HAS_EDGES: + throw QueryRuntimeException("Unexpected error when getting labels."); + } + } + for (const auto &label : *maybe_labels) { + labels.emplace_back(dba->LabelToName(label)); } return TypedValue(std::move(labels)); } diff --git a/src/query/interpret/awesome_memgraph_functions.hpp b/src/query/interpret/awesome_memgraph_functions.hpp index e915d8c11..eacea62a9 100644 --- a/src/query/interpret/awesome_memgraph_functions.hpp +++ b/src/query/interpret/awesome_memgraph_functions.hpp @@ -5,14 +5,12 @@ #include <string> #include <unordered_map> +#include "storage/v2/view.hpp" #include "utils/memory.hpp" -namespace database { -class GraphDbAccessor; -} - namespace query { +class DbAccessor; class TypedValue; namespace { @@ -22,10 +20,11 @@ const char kContains[] = "CONTAINS"; } // namespace struct FunctionContext { - database::GraphDbAccessor *db_accessor; + DbAccessor *db_accessor; utils::MemoryResource *memory; int64_t timestamp; std::unordered_map<std::string, int64_t> *counters; + storage::View view; }; /// Return the function implementation with the given name. diff --git a/src/query/interpret/eval.hpp b/src/query/interpret/eval.hpp index f06f881e4..1475b2677 100644 --- a/src/query/interpret/eval.hpp +++ b/src/query/interpret/eval.hpp @@ -7,9 +7,9 @@ #include <regex> #include <vector> -#include "database/graph_db_accessor.hpp" #include "query/common.hpp" #include "query/context.hpp" +#include "query/db_accessor.hpp" #include "query/exceptions.hpp" #include "query/frontend/ast/ast.hpp" #include "query/frontend/semantic/symbol_table.hpp" @@ -22,8 +22,8 @@ namespace query { class ExpressionEvaluator : public ExpressionVisitor<TypedValue> { public: ExpressionEvaluator(Frame *frame, const SymbolTable &symbol_table, - const EvaluationContext &ctx, - database::GraphDbAccessor *dba, storage::View view) + const EvaluationContext &ctx, DbAccessor *dba, + storage::View view) : frame_(frame), symbol_table_(&symbol_table), ctx_(&ctx), @@ -42,9 +42,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> { } TypedValue Visit(Identifier &ident) override { - TypedValue value(frame_->at(symbol_table_->at(ident)), ctx_->memory); - SwitchAccessors(value); - return value; + return TypedValue(frame_->at(symbol_table_->at(ident)), ctx_->memory); } #define BINARY_OPERATOR_VISITOR(OP_NODE, CPP_OP, CYPHER_OP) \ @@ -203,8 +201,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> { if (!index.IsString()) throw QueryRuntimeException( "Expected a string as a property name, got {}.", index.type()); - return TypedValue(lhs.ValueVertex().PropsAt( - dba_->Property(std::string(index.ValueString()))), + return TypedValue(GetProperty(lhs.ValueVertex(), index.ValueString()), ctx_->memory); } @@ -212,8 +209,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> { if (!index.IsString()) throw QueryRuntimeException( "Expected a string as a property name, got {}.", index.type()); - return TypedValue(lhs.ValueEdge().PropsAt( - dba_->Property(std::string(index.ValueString()))), + return TypedValue(GetProperty(lhs.ValueEdge(), index.ValueString()), ctx_->memory); } @@ -282,12 +278,12 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> { case TypedValue::Type::Null: return TypedValue(ctx_->memory); case TypedValue::Type::Vertex: - return TypedValue(expression_result.ValueVertex().PropsAt( - GetProperty(property_lookup.property_)), + return TypedValue(GetProperty(expression_result.ValueVertex(), + property_lookup.property_), ctx_->memory); case TypedValue::Type::Edge: - return TypedValue(expression_result.ValueEdge().PropsAt( - GetProperty(property_lookup.property_)), + return TypedValue(GetProperty(expression_result.ValueEdge(), + property_lookup.property_), ctx_->memory); case TypedValue::Type::Map: { // NOTE: Take non-const reference to map, so that we can move out the @@ -313,7 +309,19 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> { case TypedValue::Type::Vertex: { const auto &vertex = expression_result.ValueVertex(); for (const auto &label : labels_test.labels_) { - if (!vertex.has_label(GetLabel(label))) { + auto has_label = vertex.HasLabel(view_, GetLabel(label)); + if (has_label.HasError()) { + switch (has_label.GetError()) { + case storage::Error::DELETED_OBJECT: + throw QueryRuntimeException( + "Trying to access labels on a deleted node."); + case storage::Error::SERIALIZATION_ERROR: + case storage::Error::VERTEX_HAS_EDGES: + throw QueryRuntimeException( + "Unexpected error when accessing labels."); + } + } + if (!*has_label) { return TypedValue(false, ctx_->memory); } } @@ -346,11 +354,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> { } TypedValue Visit(Aggregation &aggregation) override { - TypedValue value(frame_->at(symbol_table_->at(aggregation)), ctx_->memory); - // Aggregation is probably always simple type, but let's switch accessor - // just to be sure. - SwitchAccessors(value); - return value; + return TypedValue(frame_->at(symbol_table_->at(aggregation)), ctx_->memory); } TypedValue Visit(Coalesce &coalesce) override { @@ -372,7 +376,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> { TypedValue Visit(Function &function) override { FunctionContext function_ctx{dba_, ctx_->memory, ctx_->timestamp, - &ctx_->counters}; + &ctx_->counters, view_}; // Stack allocate evaluated arguments when there's a small number of them. if (function.arguments_.size() <= 8) { TypedValue arguments[8] = { @@ -538,74 +542,50 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> { } private: - storage::Property GetProperty(PropertyIx prop) { - return ctx_->properties[prop.ix]; - } - - storage::Label GetLabel(LabelIx label) { - return ctx_->labels[label.ix]; - } - - // If the given TypedValue contains accessors, switch them to New or Old, - // depending on use_new_ flag. - void SwitchAccessors(TypedValue &value) { - switch (value.type()) { - case TypedValue::Type::Vertex: { - auto &vertex = value.ValueVertex(); - switch (view_) { - case storage::View::NEW: - vertex.SwitchNew(); - break; - case storage::View::OLD: - vertex.SwitchOld(); - break; - } - break; + template <class TRecordAccessor> + PropertyValue GetProperty(const TRecordAccessor &record_accessor, + PropertyIx prop) { + auto maybe_prop = + record_accessor.GetProperty(view_, ctx_->properties[prop.ix]); + if (maybe_prop.HasError()) { + switch (maybe_prop.GetError()) { + case storage::Error::DELETED_OBJECT: + throw QueryRuntimeException( + "Trying to get a property from a deleted object."); + case storage::Error::SERIALIZATION_ERROR: + case storage::Error::VERTEX_HAS_EDGES: + throw QueryRuntimeException( + "Unexpected error when getting a property."); } - case TypedValue::Type::Edge: { - auto &edge = value.ValueEdge(); - switch (view_) { - case storage::View::NEW: - edge.SwitchNew(); - break; - case storage::View::OLD: - edge.SwitchOld(); - break; - } - break; - } - case TypedValue::Type::List: { - auto &list = value.ValueList(); - for (auto &list_value : list) SwitchAccessors(list_value); - break; - } - case TypedValue::Type::Map: { - auto &map = value.ValueMap(); - for (auto &kv : map) SwitchAccessors(kv.second); - break; - } - case TypedValue::Type::Path: - switch (view_) { - case storage::View::NEW: - value.ValuePath().SwitchNew(); - break; - case storage::View::OLD: - value.ValuePath().SwitchOld(); - break; - } - case TypedValue::Type::Null: - case TypedValue::Type::Bool: - case TypedValue::Type::String: - case TypedValue::Type::Int: - case TypedValue::Type::Double: - break; } + return *maybe_prop; } + template <class TRecordAccessor> + PropertyValue GetProperty(const TRecordAccessor &record_accessor, + const std::string_view &name) { + auto maybe_prop = + record_accessor.GetProperty(view_, dba_->NameToProperty(name)); + if (maybe_prop.HasError()) { + switch (maybe_prop.GetError()) { + case storage::Error::DELETED_OBJECT: + throw QueryRuntimeException( + "Trying to get a property from a deleted object."); + case storage::Error::SERIALIZATION_ERROR: + case storage::Error::VERTEX_HAS_EDGES: + throw QueryRuntimeException( + "Unexpected error when getting a property."); + } + } + return *maybe_prop; + } + + storage::Label GetLabel(LabelIx label) { return ctx_->labels[label.ix]; } + Frame *frame_; const SymbolTable *symbol_table_; const EvaluationContext *ctx_; - database::GraphDbAccessor *dba_; + DbAccessor *dba_; // which switching approach should be used when evaluating storage::View view_; }; diff --git a/src/query/interpreter.cpp b/src/query/interpreter.cpp index 2a597572b..e58558784 100644 --- a/src/query/interpreter.cpp +++ b/src/query/interpreter.cpp @@ -5,7 +5,7 @@ #include <glog/logging.h> #include "auth/auth.hpp" -#ifdef MG_SINGLE_NODE +#ifndef MG_SINGLE_NODE_HA #include "database/single_node/dump.hpp" #endif #include "glue/auth.hpp" @@ -37,12 +37,12 @@ DEFINE_VALIDATED_int32(query_plan_cache_ttl, 60, namespace query { -#ifdef MG_SINGLE_NODE +#ifndef MG_SINGLE_NODE_HA namespace { class DumpClosure final { public: - explicit DumpClosure(database::GraphDbAccessor *dba) : dump_generator_(dba) {} + explicit DumpClosure(DbAccessor *dba) : dump_generator_(dba) {} // Please note that this copy constructor actually moves the other object. We // want this because lambdas are not movable, i.e. its move constructor @@ -96,13 +96,13 @@ class SingleNodeLogicalPlan final : public LogicalPlan { Interpreter::CachedPlan::CachedPlan(std::unique_ptr<LogicalPlan> plan) : plan_(std::move(plan)) {} -void Interpreter::PrettyPrintPlan(const database::GraphDbAccessor &dba, +void Interpreter::PrettyPrintPlan(const DbAccessor &dba, const plan::LogicalOperator *plan_root, std::ostream *out) { plan::PrettyPrint(dba, plan_root, out); } -std::string Interpreter::PlanToJson(const database::GraphDbAccessor &dba, +std::string Interpreter::PlanToJson(const DbAccessor &dba, const plan::LogicalOperator *plan_root) { return plan::PlanToJson(dba, plan_root).dump(); } @@ -120,7 +120,7 @@ TypedValue EvaluateOptionalExpression(Expression *expression, Callback HandleAuthQuery(AuthQuery *auth_query, auth::Auth *auth, const Parameters ¶meters, - database::GraphDbAccessor *db_accessor) { + DbAccessor *db_accessor) { // Empty frame for evaluation of password expression. This is OK since // password should be either null or string literal and it's evaluation // should not depend on frame. @@ -417,7 +417,7 @@ Callback HandleAuthQuery(AuthQuery *auth_query, auth::Auth *auth, Callback HandleStreamQuery(StreamQuery *stream_query, integrations::kafka::Streams *streams, const Parameters ¶meters, - database::GraphDbAccessor *db_accessor) { + DbAccessor *db_accessor) { // Empty frame and symbol table for evaluation of expressions. This is OK // since all expressions should be literals or parameter lookups. Frame frame(0); @@ -580,12 +580,12 @@ Callback HandleStreamQuery(StreamQuery *stream_query, Callback HandleIndexQuery(IndexQuery *index_query, std::function<void()> invalidate_plan_cache, - database::GraphDbAccessor *db_accessor) { - auto label = db_accessor->Label(index_query->label_.name); + DbAccessor *db_accessor) { + auto label = db_accessor->NameToLabel(index_query->label_.name); std::vector<storage::Property> properties; properties.reserve(index_query->properties_.size()); for (const auto &prop : index_query->properties_) { - properties.push_back(db_accessor->Property(prop.name)); + properties.push_back(db_accessor->NameToProperty(prop.name)); } if (properties.size() > 1) { @@ -595,11 +595,15 @@ Callback HandleIndexQuery(IndexQuery *index_query, Callback callback; switch (index_query->action_) { case IndexQuery::Action::CREATE: - callback.fn = [label, properties, db_accessor, - invalidate_plan_cache] { + callback.fn = [label, properties, db_accessor, invalidate_plan_cache] { +#ifdef MG_SINGLE_NODE_V2 + CHECK(properties.size() == 1); + db_accessor->CreateIndex(label, properties[0]); + invalidate_plan_cache(); +#else try { CHECK(properties.size() == 1); - db_accessor->BuildIndex(label, properties[0]); + db_accessor->CreateIndex(label, properties[0]); invalidate_plan_cache(); } catch (const database::ConstraintViolationException &e) { throw QueryRuntimeException(e.what()); @@ -608,26 +612,32 @@ Callback HandleIndexQuery(IndexQuery *index_query, } catch (const database::TransactionException &e) { throw QueryRuntimeException(e.what()); } +#endif return std::vector<std::vector<TypedValue>>(); }; return callback; case IndexQuery::Action::DROP: callback.fn = [label, properties, db_accessor, invalidate_plan_cache] { +#ifdef MG_SINGLE_NODE_V2 + CHECK(properties.size() == 1); + db_accessor->DropIndex(label, properties[0]); + invalidate_plan_cache(); +#else try { CHECK(properties.size() == 1); - db_accessor->DeleteIndex(label, properties[0]); + db_accessor->DropIndex(label, properties[0]); invalidate_plan_cache(); } catch (const database::TransactionException &e) { throw QueryRuntimeException(e.what()); } +#endif return std::vector<std::vector<TypedValue>>(); }; return callback; } } -Callback HandleInfoQuery(InfoQuery *info_query, - database::GraphDbAccessor *db_accessor) { +Callback HandleInfoQuery(InfoQuery *info_query, DbAccessor *db_accessor) { Callback callback; switch (info_query->info_type_) { case InfoQuery::InfoType::STORAGE: @@ -662,6 +672,9 @@ Callback HandleInfoQuery(InfoQuery *info_query, #endif break; case InfoQuery::InfoType::INDEX: +#ifdef MG_SINGLE_NODE_V2 + throw utils::NotYetImplemented("IndexInfo"); +#else callback.header = {"created index"}; callback.fn = [db_accessor] { auto info = db_accessor->IndexInfo(); @@ -673,7 +686,11 @@ Callback HandleInfoQuery(InfoQuery *info_query, return results; }; break; +#endif case InfoQuery::InfoType::CONSTRAINT: +#ifdef MG_SINGLE_NODE_V2 + throw utils::NotYetImplemented("ConstraintInfo"); +#else callback.header = {"constraint type", "label", "properties"}; callback.fn = [db_accessor] { std::vector<std::vector<TypedValue>> results; @@ -681,11 +698,12 @@ Callback HandleInfoQuery(InfoQuery *info_query, std::vector<std::string> property_names(e.properties.size()); std::transform(e.properties.begin(), e.properties.end(), property_names.begin(), [&db_accessor](const auto &p) { - return db_accessor->PropertyName(p); + return db_accessor->PropertyToName(p); }); std::vector<TypedValue> constraint{ - TypedValue("unique"), TypedValue(db_accessor->LabelName(e.label)), + TypedValue("unique"), + TypedValue(db_accessor->LabelToName(e.label)), TypedValue(utils::Join(property_names, ","))}; results.emplace_back(constraint); @@ -693,6 +711,7 @@ Callback HandleInfoQuery(InfoQuery *info_query, return results; }; break; +#endif case InfoQuery::InfoType::RAFT: #if defined(MG_SINGLE_NODE_HA) callback.header = {"info", "value"}; @@ -700,8 +719,9 @@ Callback HandleInfoQuery(InfoQuery *info_query, std::vector<std::vector<TypedValue>> results( {{TypedValue("is_leader"), TypedValue(db_accessor->raft()->IsLeader())}, - {TypedValue("term_id"), TypedValue(static_cast<int64_t>( - db_accessor->raft()->TermId()))}}); + {TypedValue("term_id"), + TypedValue(static_cast<int64_t>( + db_accessor->raft()->TermId()))}}); return results; }; // It is critical to abort this query because it can be executed on @@ -716,12 +736,13 @@ Callback HandleInfoQuery(InfoQuery *info_query, } Callback HandleConstraintQuery(ConstraintQuery *constraint_query, - database::GraphDbAccessor *db_accessor) { + DbAccessor *db_accessor) { std::vector<storage::Property> properties; - auto label = db_accessor->Label(constraint_query->constraint_.label.name); + auto label = + db_accessor->NameToLabel(constraint_query->constraint_.label.name); properties.reserve(constraint_query->constraint_.properties.size()); for (const auto &prop : constraint_query->constraint_.properties) { - properties.push_back(db_accessor->Property(prop.name)); + properties.push_back(db_accessor->NameToProperty(prop.name)); } Callback callback; @@ -731,8 +752,34 @@ Callback HandleConstraintQuery(ConstraintQuery *constraint_query, case Constraint::Type::NODE_KEY: throw utils::NotYetImplemented("Node key constraints"); case Constraint::Type::EXISTS: +#ifdef MG_SINGLE_NODE_V2 + if (properties.empty() || properties.size() > 1) { + throw SyntaxException( + "Exactly one property must be used for existence constraints."); + } + callback.fn = [label, properties, db_accessor] { + auto res = + db_accessor->CreateExistenceConstraint(label, properties[0]); + if (res.HasError()) { + auto violation = res.GetError(); + auto label_name = db_accessor->LabelToName(violation.label); + auto property_name = + db_accessor->PropertyToName(violation.property); + throw QueryRuntimeException( + "Unable to create a constraint :{}({}), because an existing " + "node violates it.", + label_name, property_name); + } + return std::vector<std::vector<TypedValue>>(); + }; + break; +#else throw utils::NotYetImplemented("Existence constraints"); +#endif case Constraint::Type::UNIQUE: +#ifdef MG_SINGLE_NODE_V2 + throw utils::NotYetImplemented("Unique constraints"); +#else callback.fn = [label, properties, db_accessor] { try { db_accessor->BuildUniqueConstraint(label, properties); @@ -746,6 +793,7 @@ Callback HandleConstraintQuery(ConstraintQuery *constraint_query, } }; break; +#endif } } break; case ConstraintQuery::ActionType::DROP: { @@ -753,8 +801,23 @@ Callback HandleConstraintQuery(ConstraintQuery *constraint_query, case Constraint::Type::NODE_KEY: throw utils::NotYetImplemented("Node key constraints"); case Constraint::Type::EXISTS: +#ifdef MG_SINGLE_NODE_V2 + if (properties.empty() || properties.size() > 1) { + throw SyntaxException( + "Exactly one property must be used for existence constraints."); + } + callback.fn = [label, properties, db_accessor] { + db_accessor->DropExistenceConstraint(label, properties[0]); + return std::vector<std::vector<TypedValue>>(); + }; + break; +#else throw utils::NotYetImplemented("Existence constraints"); +#endif case Constraint::Type::UNIQUE: +#ifdef MG_SINGLE_NODE_V2 + throw utils::NotYetImplemented("Unique constraints"); +#else callback.fn = [label, properties, db_accessor] { try { db_accessor->DeleteUniqueConstraint(label, properties); @@ -764,6 +827,7 @@ Callback HandleConstraintQuery(ConstraintQuery *constraint_query, } }; break; +#endif } } break; } @@ -773,7 +837,7 @@ Callback HandleConstraintQuery(ConstraintQuery *constraint_query, Interpreter::Interpreter() : is_tsc_available_(utils::CheckAvailableTSC()) {} Interpreter::Results Interpreter::operator()( - const std::string &query_string, database::GraphDbAccessor &db_accessor, + const std::string &query_string, DbAccessor *db_accessor, const std::map<std::string, PropertyValue> ¶ms, bool in_explicit_transaction, utils::MemoryResource *execution_memory) { AstStorage ast_storage; @@ -781,8 +845,8 @@ Interpreter::Results Interpreter::operator()( std::map<std::string, TypedValue> summary; utils::Timer parsing_timer; - auto queries = StripAndParseQuery(query_string, ¶meters, &ast_storage, - &db_accessor, params); + auto queries = + StripAndParseQuery(query_string, ¶meters, &ast_storage, params); frontend::StrippedQuery &stripped_query = queries.first; ParsedQuery &parsed_query = queries.second; auto parsing_time = parsing_timer.Elapsed(); @@ -804,7 +868,7 @@ Interpreter::Results Interpreter::operator()( #ifdef MG_SINGLE_NODE_HA { InfoQuery *info_query = nullptr; - if (!db_accessor.raft()->IsLeader() && + if (!db_accessor->raft()->IsLeader() && (!(info_query = utils::Downcast<InfoQuery>(parsed_query.query)) || info_query->info_type_ != InfoQuery::InfoType::RAFT)) { throw raft::CantExecuteQueries(); @@ -814,7 +878,7 @@ Interpreter::Results Interpreter::operator()( if (auto *cypher_query = utils::Downcast<CypherQuery>(parsed_query.query)) { plan = CypherQueryToPlan(stripped_query.hash(), cypher_query, - std::move(ast_storage), parameters, &db_accessor); + std::move(ast_storage), parameters, db_accessor); auto planning_time = planning_timer.Elapsed(); summary["planning_time"] = planning_time.count(); summary["cost_estimate"] = plan->cost(); @@ -831,7 +895,7 @@ Interpreter::Results Interpreter::operator()( .first); } - return Results(&db_accessor, parameters, plan, std::move(output_symbols), + return Results(db_accessor, parameters, plan, std::move(output_symbols), std::move(header), std::move(summary), parsed_query.required_privileges, execution_memory); } @@ -866,7 +930,7 @@ Interpreter::Results Interpreter::operator()( // and the one that's executed when the query is ran standalone. auto queries = StripAndParseQuery(query_string.substr(kExplainQueryStart.size()), - ¶meters, &ast_storage, &db_accessor, params); + ¶meters, &ast_storage, params); frontend::StrippedQuery &stripped_query = queries.first; ParsedQuery &parsed_query = queries.second; auto *cypher_query = utils::Downcast<CypherQuery>(parsed_query.query); @@ -874,10 +938,10 @@ Interpreter::Results Interpreter::operator()( << "Cypher grammar should not allow other queries in EXPLAIN"; std::shared_ptr<CachedPlan> cypher_query_plan = CypherQueryToPlan(stripped_query.hash(), cypher_query, - std::move(ast_storage), parameters, &db_accessor); + std::move(ast_storage), parameters, db_accessor); std::stringstream printed_plan; - PrettyPrintPlan(db_accessor, &cypher_query_plan->plan(), &printed_plan); + PrettyPrintPlan(*db_accessor, &cypher_query_plan->plan(), &printed_plan); std::vector<std::vector<TypedValue>> printed_plan_rows; for (const auto &row : @@ -885,7 +949,7 @@ Interpreter::Results Interpreter::operator()( printed_plan_rows.push_back(std::vector<TypedValue>{TypedValue(row)}); } - summary["explain"] = PlanToJson(db_accessor, &cypher_query_plan->plan()); + summary["explain"] = PlanToJson(*db_accessor, &cypher_query_plan->plan()); SymbolTable symbol_table; auto query_plan_symbol = symbol_table.CreateSymbol("QUERY PLAN", false); @@ -902,7 +966,7 @@ Interpreter::Results Interpreter::operator()( std::vector<std::string> header{query_plan_symbol.name()}; - return Results(&db_accessor, parameters, plan, std::move(output_symbols), + return Results(db_accessor, parameters, plan, std::move(output_symbols), std::move(header), std::move(summary), parsed_query.required_privileges, execution_memory); } @@ -926,7 +990,7 @@ Interpreter::Results Interpreter::operator()( // "metaqueries" for explain queries auto queries = StripAndParseQuery(query_string.substr(kProfileQueryStart.size()), - ¶meters, &ast_storage, &db_accessor, params); + ¶meters, &ast_storage, params); frontend::StrippedQuery &stripped_query = queries.first; ParsedQuery &parsed_query = queries.second; auto *cypher_query = utils::Downcast<CypherQuery>(parsed_query.query); @@ -934,7 +998,7 @@ Interpreter::Results Interpreter::operator()( << "Cypher grammar should not allow other queries in PROFILE"; auto cypher_query_plan = CypherQueryToPlan(stripped_query.hash(), cypher_query, - std::move(ast_storage), parameters, &db_accessor); + std::move(ast_storage), parameters, db_accessor); // Copy the symbol table and add our own symbols (used by the `OutputTable` // operator below) @@ -984,16 +1048,14 @@ Interpreter::Results Interpreter::operator()( auto planning_time = planning_timer.Elapsed(); summary["planning_time"] = planning_time.count(); - return Results(&db_accessor, parameters, plan, std::move(output_symbols), + return Results(db_accessor, parameters, plan, std::move(output_symbols), std::move(header), std::move(summary), parsed_query.required_privileges, execution_memory, /* is_profile_query */ true, /* should_abort_query */ true); } if (auto *dump_query = utils::Downcast<DumpQuery>(parsed_query.query)) { -#ifdef MG_SINGLE_NODE - database::CypherDumpGenerator dump(&db_accessor); - +#ifndef MG_SINGLE_NODE_HA SymbolTable symbol_table; auto query_symbol = symbol_table.CreateSymbol("QUERY", false); @@ -1001,13 +1063,13 @@ Interpreter::Results Interpreter::operator()( std::vector<std::string> header = {query_symbol.name()}; auto output_plan = std::make_unique<plan::OutputTableStream>( - output_symbols, DumpClosure(&db_accessor)); + output_symbols, DumpClosure(db_accessor)); plan = std::make_shared<CachedPlan>(std::make_unique<SingleNodeLogicalPlan>( std::move(output_plan), 0.0, AstStorage{}, symbol_table)); summary["planning_time"] = planning_timer.Elapsed().count(); - return Results(&db_accessor, parameters, plan, std::move(output_symbols), + return Results(db_accessor, parameters, plan, std::move(output_symbols), std::move(header), std::move(summary), parsed_query.required_privileges, execution_memory, /* is_profile_query */ false, @@ -1030,7 +1092,7 @@ Interpreter::Results Interpreter::operator()( } }; callback = - HandleIndexQuery(index_query, invalidate_plan_cache, &db_accessor); + HandleIndexQuery(index_query, invalidate_plan_cache, db_accessor); } else if (auto *auth_query = utils::Downcast<AuthQuery>(parsed_query.query)) { #ifdef MG_SINGLE_NODE_HA @@ -1041,7 +1103,7 @@ Interpreter::Results Interpreter::operator()( if (in_explicit_transaction) { throw UserModificationInMulticommandTxException(); } - callback = HandleAuthQuery(auth_query, auth_, parameters, &db_accessor); + callback = HandleAuthQuery(auth_query, auth_, parameters, db_accessor); #endif } else if (auto *stream_query = utils::Downcast<StreamQuery>(parsed_query.query)) { @@ -1053,14 +1115,14 @@ Interpreter::Results Interpreter::operator()( throw StreamClauseInMulticommandTxException(); } callback = HandleStreamQuery(stream_query, kafka_streams_, parameters, - &db_accessor); + db_accessor); #endif } else if (auto *info_query = utils::Downcast<InfoQuery>(parsed_query.query)) { - callback = HandleInfoQuery(info_query, &db_accessor); + callback = HandleInfoQuery(info_query, db_accessor); } else if (auto *constraint_query = utils::Downcast<ConstraintQuery>(parsed_query.query)) { - callback = HandleConstraintQuery(constraint_query, &db_accessor); + callback = HandleConstraintQuery(constraint_query, db_accessor); } else { LOG(FATAL) << "Should not get here -- unknown query type!"; } @@ -1081,7 +1143,7 @@ Interpreter::Results Interpreter::operator()( summary["planning_time"] = planning_time.count(); summary["cost_estimate"] = 0.0; - return Results(&db_accessor, parameters, plan, std::move(output_symbols), + return Results(db_accessor, parameters, plan, std::move(output_symbols), callback.header, std::move(summary), parsed_query.required_privileges, execution_memory, /* is_profile_query */ false, callback.should_abort_query); @@ -1089,7 +1151,7 @@ Interpreter::Results Interpreter::operator()( std::shared_ptr<Interpreter::CachedPlan> Interpreter::CypherQueryToPlan( HashType query_hash, CypherQuery *query, AstStorage ast_storage, - const Parameters ¶meters, database::GraphDbAccessor *db_accessor) { + const Parameters ¶meters, DbAccessor *db_accessor) { auto plan_cache_access = plan_cache_.access(); auto it = plan_cache_access.find(query_hash); if (it != plan_cache_access.end()) { @@ -1108,8 +1170,7 @@ std::shared_ptr<Interpreter::CachedPlan> Interpreter::CypherQueryToPlan( Interpreter::ParsedQuery Interpreter::ParseQuery( const std::string &stripped_query, const std::string &original_query, - const frontend::ParsingContext &context, AstStorage *ast_storage, - database::GraphDbAccessor *db_accessor) { + const frontend::ParsingContext &context, AstStorage *ast_storage) { if (!context.is_query_cached) { // Parse original query into antlr4 AST. auto parser = [&] { @@ -1167,7 +1228,7 @@ Interpreter::ParsedQuery Interpreter::ParseQuery( std::pair<frontend::StrippedQuery, Interpreter::ParsedQuery> Interpreter::StripAndParseQuery( const std::string &query_string, Parameters *parameters, - AstStorage *ast_storage, database::GraphDbAccessor *db_accessor, + AstStorage *ast_storage, const std::map<std::string, PropertyValue> ¶ms) { frontend::StrippedQuery stripped_query(query_string); @@ -1185,14 +1246,14 @@ Interpreter::StripAndParseQuery( parsing_context.is_query_cached = true; auto parsed_query = ParseQuery(stripped_query.query(), query_string, - parsing_context, ast_storage, db_accessor); + parsing_context, ast_storage); return {std::move(stripped_query), std::move(parsed_query)}; } std::unique_ptr<LogicalPlan> Interpreter::MakeLogicalPlan( CypherQuery *query, AstStorage ast_storage, const Parameters ¶meters, - database::GraphDbAccessor *db_accessor) { + DbAccessor *db_accessor) { auto vertex_counts = plan::MakeVertexCountCache(db_accessor); auto symbol_table = MakeSymbolTable(query); diff --git a/src/query/interpreter.hpp b/src/query/interpreter.hpp index 21e1d8b13..2e941e056 100644 --- a/src/query/interpreter.hpp +++ b/src/query/interpreter.hpp @@ -2,9 +2,8 @@ #include <gflags/gflags.h> -#include "database/graph_db.hpp" -#include "database/graph_db_accessor.hpp" #include "query/context.hpp" +#include "query/db_accessor.hpp" #include "query/frontend/ast/ast.hpp" #include "query/frontend/ast/cypher_main_visitor.hpp" #include "query/frontend/stripped.hpp" @@ -82,8 +81,7 @@ class Interpreter { */ class Results { friend Interpreter; - Results(database::GraphDbAccessor *db_accessor, - const query::Parameters ¶meters, + Results(DbAccessor *db_accessor, const query::Parameters ¶meters, std::shared_ptr<CachedPlan> plan, std::vector<Symbol> output_symbols, std::vector<std::string> header, std::map<std::string, TypedValue> summary, @@ -216,8 +214,7 @@ class Interpreter { * Generates an Results object for the parameters. The resulting object * can be Pulled with its results written to an arbitrary stream. */ - virtual Results operator()(const std::string &query, - database::GraphDbAccessor &db_accessor, + virtual Results operator()(const std::string &query, DbAccessor *db_accessor, const std::map<std::string, PropertyValue> ¶ms, bool in_explicit_transaction, utils::MemoryResource *execution_memory); @@ -228,20 +225,20 @@ class Interpreter { protected: std::pair<frontend::StrippedQuery, ParsedQuery> StripAndParseQuery( const std::string &, Parameters *, AstStorage *ast_storage, - database::GraphDbAccessor *, const std::map<std::string, PropertyValue> &); // high level tree -> logical plan // AstStorage and SymbolTable may be modified during planning. The created // LogicalPlan must take ownership of AstStorage and SymbolTable. - virtual std::unique_ptr<LogicalPlan> MakeLogicalPlan( - CypherQuery *, AstStorage, const Parameters &, - database::GraphDbAccessor *); + virtual std::unique_ptr<LogicalPlan> MakeLogicalPlan(CypherQuery *, + AstStorage, + const Parameters &, + DbAccessor *); - virtual void PrettyPrintPlan(const database::GraphDbAccessor &, + virtual void PrettyPrintPlan(const DbAccessor &, const plan::LogicalOperator *, std::ostream *); - virtual std::string PlanToJson(const database::GraphDbAccessor &, + virtual std::string PlanToJson(const DbAccessor &, const plan::LogicalOperator *); private: @@ -290,16 +287,17 @@ class Interpreter { bool is_tsc_available_; // high level tree -> CachedPlan - std::shared_ptr<CachedPlan> CypherQueryToPlan( - HashType query_hash, CypherQuery *query, AstStorage ast_storage, - const Parameters ¶meters, database::GraphDbAccessor *db_accessor); + std::shared_ptr<CachedPlan> CypherQueryToPlan(HashType query_hash, + CypherQuery *query, + AstStorage ast_storage, + const Parameters ¶meters, + DbAccessor *db_accessor); // stripped query -> high level tree ParsedQuery ParseQuery(const std::string &stripped_query, const std::string &original_query, const frontend::ParsingContext &context, - AstStorage *ast_storage, - database::GraphDbAccessor *db_accessor); + AstStorage *ast_storage); }; } // namespace query diff --git a/src/query/path.hpp b/src/query/path.hpp index 89b288c97..fcabc6a74 100644 --- a/src/query/path.hpp +++ b/src/query/path.hpp @@ -5,8 +5,7 @@ #include "glog/logging.h" -#include "storage/edge_accessor.hpp" -#include "storage/vertex_accessor.hpp" +#include "query/db_accessor.hpp" #include "utils/memory.hpp" #include "utils/pmr/vector.hpp" @@ -144,7 +143,7 @@ class Path { << "Attempting to stream out an invalid path"; os << path.vertices_[0]; for (int i = 0; i < static_cast<int>(path.edges_.size()); i++) { - bool arrow_to_left = path.vertices_[i] == path.edges_[i].to(); + bool arrow_to_left = path.vertices_[i] == path.edges_[i].To(); if (arrow_to_left) os << "<"; os << "-" << path.edges_[i] << "-"; if (!arrow_to_left) os << ">"; @@ -154,18 +153,6 @@ class Path { return os; } - /// Calls SwitchNew on all the elements of the path. - void SwitchNew() { - for (auto &v : vertices_) v.SwitchNew(); - for (auto &e : edges_) e.SwitchNew(); - } - - /// Calls SwitchNew on all the elements of the path. - void SwitchOld() { - for (auto &v : vertices_) v.SwitchOld(); - for (auto &e : edges_) e.SwitchOld(); - } - private: // Contains all the vertices in the path. utils::pmr::vector<VertexAccessor> vertices_; diff --git a/src/query/plan/operator.cpp b/src/query/plan/operator.cpp index d4935cee0..384b48a5b 100644 --- a/src/query/plan/operator.cpp +++ b/src/query/plan/operator.cpp @@ -16,7 +16,6 @@ #include <cppitertools/chain.hpp> #include <cppitertools/imap.hpp> -#include "database/graph_db_accessor.hpp" #include "query/context.hpp" #include "query/exceptions.hpp" #include "query/frontend/ast/ast.hpp" @@ -123,7 +122,21 @@ VertexAccessor &CreateLocalVertex(const NodeCreationInfo &node_info, const ExecutionContext &context) { auto &dba = *context.db_accessor; auto new_node = dba.InsertVertex(); - for (auto label : node_info.labels) new_node.add_label(label); + for (auto label : node_info.labels) { + auto maybe_error = new_node.AddLabel(label); + if (maybe_error.HasError()) { + switch (maybe_error.GetError()) { + case storage::Error::SERIALIZATION_ERROR: + throw QueryRuntimeException( + "Can't serialize due to concurrent operations."); + case storage::Error::DELETED_OBJECT: + throw QueryRuntimeException( + "Trying to set a label on a deleted node."); + case storage::Error::VERTEX_HAS_EDGES: + throw QueryRuntimeException("Unexpected error when setting a label."); + } + } + } // Evaluator should use the latest accessors, as modified in this query, when // setting properties on new nodes. ExpressionEvaluator evaluator(frame, context.symbol_table, @@ -200,14 +213,27 @@ CreateExpand::CreateExpandCursor::CreateExpandCursor(const CreateExpand &self, namespace { -void CreateEdge(const EdgeCreationInfo &edge_info, - database::GraphDbAccessor *dba, VertexAccessor *from, - VertexAccessor *to, Frame *frame, +void CreateEdge(const EdgeCreationInfo &edge_info, DbAccessor *dba, + VertexAccessor *from, VertexAccessor *to, Frame *frame, ExpressionEvaluator *evaluator) { - EdgeAccessor edge = dba->InsertEdge(*from, *to, edge_info.edge_type); - for (auto kv : edge_info.properties) - PropsSetChecked(&edge, kv.first, kv.second->Accept(*evaluator)); - (*frame)[edge_info.symbol] = edge; + auto maybe_edge = dba->InsertEdge(from, to, edge_info.edge_type); + if (maybe_edge.HasValue()) { + auto &edge = *maybe_edge; + for (auto kv : edge_info.properties) + PropsSetChecked(&edge, kv.first, kv.second->Accept(*evaluator)); + (*frame)[edge_info.symbol] = edge; + } else { + switch (maybe_edge.GetError()) { + case storage::Error::SERIALIZATION_ERROR: + throw QueryRuntimeException( + "Can't serialize due to concurrent operations."); + case storage::Error::DELETED_OBJECT: + throw QueryRuntimeException( + "Trying to create an edge on a deleted node."); + case storage::Error::VERTEX_HAS_EDGES: + throw QueryRuntimeException("Unexpected error when creating an edge."); + } + } } } // namespace @@ -224,16 +250,14 @@ bool CreateExpand::CreateExpandCursor::Pull(Frame &frame, auto &v1 = vertex_value.ValueVertex(); // Similarly to CreateNode, newly created edges and nodes should use the - // latest accesors. + // storage::View::NEW. + // E.g. we pickup new properties: `CREATE (n {p: 42}) -[:r {ep: n.p}]-> ()` ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, context.db_accessor, storage::View::NEW); - // E.g. we pickup new properties: `CREATE (n {p: 42}) -[:r {ep: n.p}]-> ()` - v1.SwitchNew(); // get the destination vertex (possibly an existing node) auto &v2 = OtherVertex(frame, context); - v2.SwitchNew(); // create an edge between the two nodes auto *dba = context.db_accessor; @@ -274,8 +298,8 @@ VertexAccessor &CreateExpand::CreateExpandCursor::OtherVertex( template <class TVerticesFun> class ScanAllCursor : public Cursor { public: - explicit ScanAllCursor(Symbol output_symbol, UniqueCursorPtr &&input_cursor, - TVerticesFun &&get_vertices) + explicit ScanAllCursor(Symbol output_symbol, UniqueCursorPtr input_cursor, + TVerticesFun get_vertices) : output_symbol_(output_symbol), input_cursor_(std::move(input_cursor)), get_vertices_(std::move(get_vertices)) {} @@ -283,7 +307,7 @@ class ScanAllCursor : public Cursor { bool Pull(Frame &frame, ExecutionContext &context) override { SCOPED_PROFILE_OP("ScanAll"); - if (context.db_accessor->should_abort()) throw HintedAbortError(); + if (context.db_accessor->MustAbort()) throw HintedAbortError(); while (!vertices_ || vertices_it_.value() == vertices_.value().end()) { if (!input_cursor_->Pull(frame, context)) return false; @@ -298,7 +322,8 @@ class ScanAllCursor : public Cursor { vertices_it_.emplace(vertices_.value().begin()); } - frame[output_symbol_] = *vertices_it_.value()++; + frame[output_symbol_] = *vertices_it_.value(); + ++vertices_it_.value(); return true; } @@ -331,7 +356,7 @@ ACCEPT_WITH_INPUT(ScanAll) UniqueCursorPtr ScanAll::MakeCursor(utils::MemoryResource *mem) const { auto vertices = [this](Frame &, ExecutionContext &context) { auto *db = context.db_accessor; - return std::make_optional(db->Vertices(view_ == storage::View::NEW)); + return std::make_optional(db->Vertices(view_)); }; return MakeUniqueCursorPtr<ScanAllCursor<decltype(vertices)>>( mem, output_symbol_, input_->MakeCursor(mem), std::move(vertices)); @@ -353,8 +378,7 @@ ACCEPT_WITH_INPUT(ScanAllByLabel) UniqueCursorPtr ScanAllByLabel::MakeCursor(utils::MemoryResource *mem) const { auto vertices = [this](Frame &, ExecutionContext &context) { auto *db = context.db_accessor; - return std::make_optional( - db->Vertices(label_, view_ == storage::View::NEW)); + return std::make_optional(db->Vertices(view_, label_)); }; return MakeUniqueCursorPtr<ScanAllCursor<decltype(vertices)>>( mem, output_symbol_, input_->MakeCursor(mem), std::move(vertices)); @@ -380,7 +404,7 @@ UniqueCursorPtr ScanAllByLabelPropertyRange::MakeCursor( utils::MemoryResource *mem) const { auto vertices = [this](Frame &frame, ExecutionContext &context) -> std::optional<decltype(context.db_accessor->Vertices( - label_, property_, std::nullopt, std::nullopt, false))> { + view_, label_, property_, std::nullopt, std::nullopt))> { auto *db = context.db_accessor; ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, @@ -404,9 +428,8 @@ UniqueCursorPtr ScanAllByLabelPropertyRange::MakeCursor( // is treated as not satisfying the filter, so return no vertices. if (maybe_lower && maybe_lower->value().IsNull()) return std::nullopt; if (maybe_upper && maybe_upper->value().IsNull()) return std::nullopt; - return std::make_optional(db->Vertices(label_, property_, maybe_lower, - maybe_upper, - view_ == storage::View::NEW)); + return std::make_optional( + db->Vertices(view_, label_, property_, maybe_lower, maybe_upper)); }; return MakeUniqueCursorPtr<ScanAllCursor<decltype(vertices)>>( mem, output_symbol_, input_->MakeCursor(mem), std::move(vertices)); @@ -431,7 +454,7 @@ UniqueCursorPtr ScanAllByLabelPropertyValue::MakeCursor( utils::MemoryResource *mem) const { auto vertices = [this](Frame &frame, ExecutionContext &context) -> std::optional<decltype(context.db_accessor->Vertices( - label_, property_, PropertyValue(), false))> { + view_, label_, property_, PropertyValue()))> { auto *db = context.db_accessor; ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, @@ -442,9 +465,8 @@ UniqueCursorPtr ScanAllByLabelPropertyValue::MakeCursor( throw QueryRuntimeException("'{}' cannot be used as a property value.", value.type()); } - return std::make_optional(db->Vertices(label_, property_, - PropertyValue(value), - view_ == storage::View::NEW)); + return std::make_optional( + db->Vertices(view_, label_, property_, PropertyValue(value))); }; return MakeUniqueCursorPtr<ScanAllCursor<decltype(vertices)>>( mem, output_symbol_, input_->MakeCursor(mem), std::move(vertices)); @@ -458,6 +480,23 @@ bool CheckExistingNode(const VertexAccessor &new_node, ExpectType(existing_node_sym, existing_node, TypedValue::Type::Vertex); return existing_node.ValueVertex() != new_node; } + +template <class TEdges> +auto UnwrapEdgesResult(storage::Result<TEdges> &&result) { + if (result.HasError()) { + switch (result.GetError()) { + case storage::Error::DELETED_OBJECT: + throw QueryRuntimeException( + "Trying to get relationships of a deleted node."); + case storage::Error::VERTEX_HAS_EDGES: + case storage::Error::SERIALIZATION_ERROR: + throw QueryRuntimeException( + "Unexpected error when accessing relationships."); + } + } + return std::move(*result); +} + } // namespace Expand::Expand(const std::shared_ptr<LogicalOperator> &input, @@ -496,10 +535,10 @@ bool Expand::ExpandCursor::Pull(Frame &frame, ExecutionContext &context) { if (self_.common_.existing_node) return; switch (direction) { case EdgeAtom::Direction::IN: - frame[self_.common_.node_symbol] = new_edge.from(); + frame[self_.common_.node_symbol] = new_edge.From(); break; case EdgeAtom::Direction::OUT: - frame[self_.common_.node_symbol] = new_edge.to(); + frame[self_.common_.node_symbol] = new_edge.To(); break; case EdgeAtom::Direction::BOTH: LOG(FATAL) << "Must indicate exact expansion direction here"; @@ -507,7 +546,7 @@ bool Expand::ExpandCursor::Pull(Frame &frame, ExecutionContext &context) { }; while (true) { - if (context.db_accessor->should_abort()) throw HintedAbortError(); + if (context.db_accessor->MustAbort()) throw HintedAbortError(); // attempt to get a value from the incoming edges if (in_edges_ && *in_edges_it_ != in_edges_->end()) { auto edge = *(*in_edges_it_)++; @@ -523,7 +562,7 @@ bool Expand::ExpandCursor::Pull(Frame &frame, ExecutionContext &context) { // we should do only one expansion for cycles, and it was // already done in the block above if (self_.common_.direction == EdgeAtom::Direction::BOTH && - edge.is_cycle()) + edge.IsCycle()) continue; frame[self_.common_.edge_symbol] = edge; pull_node(edge, EdgeAtom::Direction::OUT); @@ -560,7 +599,6 @@ bool Expand::ExpandCursor::InitEdges(Frame &frame, ExecutionContext &context) { ExpectType(self_.input_symbol_, vertex_value, TypedValue::Type::Vertex); auto &vertex = vertex_value.ValueVertex(); - SwitchAccessor(vertex, self_.view_); auto direction = self_.common_.direction; if (direction == EdgeAtom::Direction::IN || @@ -571,11 +609,13 @@ bool Expand::ExpandCursor::InitEdges(Frame &frame, ExecutionContext &context) { if (!existing_node.IsNull()) { ExpectType(self_.common_.node_symbol, existing_node, TypedValue::Type::Vertex); - in_edges_.emplace(vertex.in(existing_node.ValueVertex(), - &self_.common_.edge_types)); + in_edges_.emplace(UnwrapEdgesResult( + vertex.InEdges(self_.view_, self_.common_.edge_types, + existing_node.ValueVertex()))); } } else { - in_edges_.emplace(vertex.in(&self_.common_.edge_types)); + in_edges_.emplace(UnwrapEdgesResult( + vertex.InEdges(self_.view_, self_.common_.edge_types))); } if (in_edges_) { in_edges_it_.emplace(in_edges_->begin()); @@ -590,11 +630,13 @@ bool Expand::ExpandCursor::InitEdges(Frame &frame, ExecutionContext &context) { if (!existing_node.IsNull()) { ExpectType(self_.common_.node_symbol, existing_node, TypedValue::Type::Vertex); - out_edges_.emplace(vertex.out(existing_node.ValueVertex(), - &self_.common_.edge_types)); + out_edges_.emplace(UnwrapEdgesResult( + vertex.OutEdges(self_.view_, self_.common_.edge_types, + existing_node.ValueVertex()))); } } else { - out_edges_.emplace(vertex.out(&self_.common_.edge_types)); + out_edges_.emplace(UnwrapEdgesResult( + vertex.OutEdges(self_.view_, self_.common_.edge_types))); } if (out_edges_) { out_edges_it_.emplace(out_edges_->begin()); @@ -645,6 +687,21 @@ std::vector<Symbol> ExpandVariable::ModifiedSymbols( } namespace { + +size_t UnwrapDegreeResult(storage::Result<size_t> maybe_degree) { + if (maybe_degree.HasError()) { + switch (maybe_degree.GetError()) { + case storage::Error::DELETED_OBJECT: + throw QueryRuntimeException("Trying to get degree of a deleted node."); + case storage::Error::SERIALIZATION_ERROR: + case storage::Error::VERTEX_HAS_EDGES: + throw QueryRuntimeException( + "Unexpected error when getting node degree."); + } + } + return *maybe_degree; +} + /** * Helper function that returns an iterable over * <EdgeAtom::Direction, EdgeAccessor> pairs @@ -661,27 +718,30 @@ auto ExpandFromVertex(const VertexAccessor &vertex, const std::vector<storage::EdgeType> &edge_types, utils::MemoryResource *memory) { // wraps an EdgeAccessor into a pair <accessor, direction> - auto wrapper = [](EdgeAtom::Direction direction, auto &&vertices) { + auto wrapper = [](EdgeAtom::Direction direction, auto &&edges) { return iter::imap( - [direction](const EdgeAccessor &edge) { + [direction](const auto &edge) { return std::make_pair(edge, direction); }, - std::forward<decltype(vertices)>(vertices)); + std::forward<decltype(edges)>(edges)); }; - // prepare a vector of elements we'll pass to the itertools - utils::pmr::vector<decltype(wrapper(direction, vertex.in()))> chain_elements( - memory); + storage::View view = storage::View::OLD; + utils::pmr::vector<decltype( + wrapper(direction, *vertex.InEdges(view, edge_types)))> + chain_elements(memory); - if (direction != EdgeAtom::Direction::OUT && vertex.in_degree() > 0) { - auto edges = vertex.in(&edge_types); + size_t in_degree = UnwrapDegreeResult(vertex.InDegree(view)); + if (direction != EdgeAtom::Direction::OUT && in_degree > 0) { + auto edges = UnwrapEdgesResult(vertex.InEdges(view, edge_types)); if (edges.begin() != edges.end()) { chain_elements.emplace_back( wrapper(EdgeAtom::Direction::IN, std::move(edges))); } } - if (direction != EdgeAtom::Direction::IN && vertex.out_degree() > 0) { - auto edges = vertex.out(&edge_types); + size_t out_degree = UnwrapDegreeResult(vertex.OutDegree(view)); + if (direction != EdgeAtom::Direction::IN && out_degree > 0) { + auto edges = UnwrapEdgesResult(vertex.OutEdges(view, edge_types)); if (edges.begin() != edges.end()) { chain_elements.emplace_back( wrapper(EdgeAtom::Direction::OUT, std::move(edges))); @@ -770,7 +830,7 @@ class ExpandVariableCursor : public Cursor { // Input Vertex could be null if it is created by a failed optional match. // In those cases we skip that input pull and continue with the next. while (true) { - if (context.db_accessor->should_abort()) throw HintedAbortError(); + if (context.db_accessor->MustAbort()) throw HintedAbortError(); if (!input_cursor_->Pull(frame, context)) return false; TypedValue &vertex_value = frame[self_.input_symbol_]; @@ -779,7 +839,6 @@ class ExpandVariableCursor : public Cursor { ExpectType(self_.input_symbol_, vertex_value, TypedValue::Type::Vertex); auto &vertex = vertex_value.ValueVertex(); - SwitchAccessor(vertex, storage::View::OLD); // Evaluate the upper and lower bounds. ExpressionEvaluator evaluator(&frame, context.symbol_table, @@ -798,7 +857,6 @@ class ExpandVariableCursor : public Cursor { : std::numeric_limits<int64_t>::max(); if (upper_bound_ > 0) { - SwitchAccessor(vertex, storage::View::OLD); auto *memory = edges_.get_allocator().GetMemoryResource(); edges_.emplace_back(ExpandFromVertex(vertex, self_.common_.direction, self_.common_.edge_types, memory)); @@ -852,7 +910,7 @@ class ExpandVariableCursor : public Cursor { // existing_node criterions, so expand in a loop until either the input // vertex is exhausted or a valid variable-length expansion is available. while (true) { - if (context.db_accessor->should_abort()) throw HintedAbortError(); + if (context.db_accessor->MustAbort()) throw HintedAbortError(); // pop from the stack while there is stuff to pop and the current // level is exhausted while (!edges_.empty() && edges_it_.back() == edges_.back().end()) { @@ -883,8 +941,7 @@ class ExpandVariableCursor : public Cursor { // if we are here, we have a valid stack, // get the edge, increase the relevant iterator - std::pair<EdgeAccessor, EdgeAtom::Direction> current_edge = - *edges_it_.back()++; + auto current_edge = *edges_it_.back()++; // Check edge-uniqueness. bool found_existing = @@ -897,8 +954,8 @@ class ExpandVariableCursor : public Cursor { AppendEdge(current_edge.first, &edges_on_frame); VertexAccessor current_vertex = current_edge.second == EdgeAtom::Direction::IN - ? current_edge.first.from() - : current_edge.first.to(); + ? current_edge.first.From() + : current_edge.first.To(); if (self_.common_.existing_node && !CheckExistingNode(current_vertex, self_.common_.node_symbol, frame)) @@ -916,7 +973,6 @@ class ExpandVariableCursor : public Cursor { // we are doing depth-first search, so place the current // edge's expansions onto the stack, if we should continue to expand if (upper_bound_ > static_cast<int64_t>(edges_.size())) { - SwitchAccessor(current_vertex, storage::View::OLD); auto *memory = edges_.get_allocator().GetMemoryResource(); edges_.emplace_back(ExpandFromVertex(current_vertex, self_.common_.direction, @@ -1001,8 +1057,8 @@ class STShortestPathCursor : public query::plan::Cursor { while (true) { const auto &last_edge = in_edge.at(last_vertex); if (!last_edge) break; - last_vertex = - last_edge->from_is(last_vertex) ? last_edge->to() : last_edge->from(); + last_vertex = last_edge->From() == last_vertex ? last_edge->To() + : last_edge->From(); result.emplace_back(*last_edge); } std::reverse(result.begin(), result.end()); @@ -1010,8 +1066,8 @@ class STShortestPathCursor : public query::plan::Cursor { while (true) { const auto &last_edge = out_edge.at(last_vertex); if (!last_edge) break; - last_vertex = - last_edge->from_is(last_vertex) ? last_edge->to() : last_edge->from(); + last_vertex = last_edge->From() == last_vertex ? last_edge->To() + : last_edge->From(); result.emplace_back(*last_edge); } frame->at(self_.common_.edge_symbol) = std::move(result); @@ -1032,9 +1088,9 @@ class STShortestPathCursor : public query::plan::Cursor { "Expansion condition must evaluate to boolean or null"); } - bool FindPath(const database::GraphDbAccessor &dba, - const VertexAccessor &source, const VertexAccessor &sink, - int64_t lower_bound, int64_t upper_bound, Frame *frame, + bool FindPath(const DbAccessor &dba, const VertexAccessor &source, + const VertexAccessor &sink, int64_t lower_bound, + int64_t upper_bound, Frame *frame, ExpressionEvaluator *evaluator) { using utils::Contains; @@ -1069,45 +1125,49 @@ class STShortestPathCursor : public query::plan::Cursor { out_edge[sink] = std::nullopt; while (true) { - if (dba.should_abort()) throw HintedAbortError(); + if (dba.MustAbort()) throw HintedAbortError(); // Top-down step (expansion from the source). ++current_length; if (current_length > upper_bound) return false; for (const auto &vertex : source_frontier) { if (self_.common_.direction != EdgeAtom::Direction::IN) { - for (const auto &edge : vertex.out(&self_.common_.edge_types)) { - if (ShouldExpand(edge.to(), edge, frame, evaluator) && - !Contains(in_edge, edge.to())) { - in_edge.emplace(edge.to(), edge); - if (Contains(out_edge, edge.to())) { + auto out_edges = UnwrapEdgesResult( + vertex.OutEdges(storage::View::OLD, self_.common_.edge_types)); + for (const auto &edge : out_edges) { + if (ShouldExpand(edge.To(), edge, frame, evaluator) && + !Contains(in_edge, edge.To())) { + in_edge.emplace(edge.To(), edge); + if (Contains(out_edge, edge.To())) { if (current_length >= lower_bound) { - ReconstructPath(edge.to(), in_edge, out_edge, frame, + ReconstructPath(edge.To(), in_edge, out_edge, frame, pull_memory); return true; } else { return false; } } - source_next.push_back(edge.to()); + source_next.push_back(edge.To()); } } } if (self_.common_.direction != EdgeAtom::Direction::OUT) { - for (const auto &edge : vertex.in(&self_.common_.edge_types)) { - if (ShouldExpand(edge.from(), edge, frame, evaluator) && - !Contains(in_edge, edge.from())) { - in_edge.emplace(edge.from(), edge); - if (Contains(out_edge, edge.from())) { + auto in_edges = UnwrapEdgesResult( + vertex.InEdges(storage::View::OLD, self_.common_.edge_types)); + for (const auto &edge : in_edges) { + if (ShouldExpand(edge.From(), edge, frame, evaluator) && + !Contains(in_edge, edge.From())) { + in_edge.emplace(edge.From(), edge); + if (Contains(out_edge, edge.From())) { if (current_length >= lower_bound) { - ReconstructPath(edge.from(), in_edge, out_edge, frame, + ReconstructPath(edge.From(), in_edge, out_edge, frame, pull_memory); return true; } else { return false; } } - source_next.push_back(edge.from()); + source_next.push_back(edge.From()); } } } @@ -1126,38 +1186,42 @@ class STShortestPathCursor : public query::plan::Cursor { // reversed. for (const auto &vertex : sink_frontier) { if (self_.common_.direction != EdgeAtom::Direction::OUT) { - for (const auto &edge : vertex.out(&self_.common_.edge_types)) { + auto out_edges = UnwrapEdgesResult( + vertex.OutEdges(storage::View::OLD, self_.common_.edge_types)); + for (const auto &edge : out_edges) { if (ShouldExpand(vertex, edge, frame, evaluator) && - !Contains(out_edge, edge.to())) { - out_edge.emplace(edge.to(), edge); - if (Contains(in_edge, edge.to())) { + !Contains(out_edge, edge.To())) { + out_edge.emplace(edge.To(), edge); + if (Contains(in_edge, edge.To())) { if (current_length >= lower_bound) { - ReconstructPath(edge.to(), in_edge, out_edge, frame, + ReconstructPath(edge.To(), in_edge, out_edge, frame, pull_memory); return true; } else { return false; } } - sink_next.push_back(edge.to()); + sink_next.push_back(edge.To()); } } } if (self_.common_.direction != EdgeAtom::Direction::IN) { - for (const auto &edge : vertex.in(&self_.common_.edge_types)) { + auto in_edges = UnwrapEdgesResult( + vertex.InEdges(storage::View::OLD, self_.common_.edge_types)); + for (const auto &edge : in_edges) { if (ShouldExpand(vertex, edge, frame, evaluator) && - !Contains(out_edge, edge.from())) { - out_edge.emplace(edge.from(), edge); - if (Contains(in_edge, edge.from())) { + !Contains(out_edge, edge.From())) { + out_edge.emplace(edge.From(), edge); + if (Contains(in_edge, edge.From())) { if (current_length >= lower_bound) { - ReconstructPath(edge.from(), in_edge, out_edge, frame, + ReconstructPath(edge.From(), in_edge, out_edge, frame, pull_memory); return true; } else { return false; } } - sink_next.push_back(edge.from()); + sink_next.push_back(edge.From()); } } } @@ -1225,18 +1289,20 @@ class SingleSourceShortestPathCursor : public query::plan::Cursor { // the "where" condition. auto expand_from_vertex = [this, &expand_pair](const auto &vertex) { if (self_.common_.direction != EdgeAtom::Direction::IN) { - for (const EdgeAccessor &edge : vertex.out(&self_.common_.edge_types)) - expand_pair(edge, edge.to()); + auto out_edges = UnwrapEdgesResult( + vertex.OutEdges(storage::View::OLD, self_.common_.edge_types)); + for (const auto &edge : out_edges) expand_pair(edge, edge.To()); } if (self_.common_.direction != EdgeAtom::Direction::OUT) { - for (const EdgeAccessor &edge : vertex.in(&self_.common_.edge_types)) - expand_pair(edge, edge.from()); + auto in_edges = UnwrapEdgesResult( + vertex.InEdges(storage::View::OLD, self_.common_.edge_types)); + for (const auto &edge : in_edges) expand_pair(edge, edge.From()); } }; // do it all in a loop because we skip some elements while (true) { - if (context.db_accessor->should_abort()) throw HintedAbortError(); + if (context.db_accessor->MustAbort()) throw HintedAbortError(); // if we have nothing to visit on the current depth, switch to next if (to_visit_current_.empty()) to_visit_current_.swap(to_visit_next_); @@ -1272,8 +1338,7 @@ class SingleSourceShortestPathCursor : public query::plan::Cursor { } // take the next expansion from the queue - std::pair<EdgeAccessor, VertexAccessor> expansion = - to_visit_current_.back(); + auto expansion = to_visit_current_.back(); to_visit_current_.pop_back(); // create the frame value for the edges @@ -1284,7 +1349,7 @@ class SingleSourceShortestPathCursor : public query::plan::Cursor { while (true) { const EdgeAccessor &last_edge = edge_list.back().ValueEdge(); last_vertex = - last_edge.from() == last_vertex ? last_edge.to() : last_edge.from(); + last_edge.From() == last_vertex ? last_edge.To() : last_edge.From(); // origin_vertex must be in processed const auto &previous_edge = processed_.find(last_vertex)->second; if (!previous_edge) break; @@ -1363,9 +1428,6 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor { auto expand_pair = [this, &evaluator, &frame, &create_state]( EdgeAccessor edge, VertexAccessor vertex, double weight, int depth) { - SwitchAccessor(edge, storage::View::OLD); - SwitchAccessor(vertex, storage::View::OLD); - auto *memory = evaluator.GetMemoryResource(); if (self_.filter_lambda_.expression) { frame[self_.filter_lambda_.inner_edge_symbol] = edge; @@ -1404,19 +1466,23 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor { auto expand_from_vertex = [this, &expand_pair](const VertexAccessor &vertex, double weight, int depth) { if (self_.common_.direction != EdgeAtom::Direction::IN) { - for (const EdgeAccessor &edge : vertex.out(&self_.common_.edge_types)) { - expand_pair(edge, edge.to(), weight, depth); + auto out_edges = UnwrapEdgesResult( + vertex.OutEdges(storage::View::OLD, self_.common_.edge_types)); + for (const auto &edge : out_edges) { + expand_pair(edge, edge.To(), weight, depth); } } if (self_.common_.direction != EdgeAtom::Direction::OUT) { - for (const EdgeAccessor &edge : vertex.in(&self_.common_.edge_types)) { - expand_pair(edge, edge.from(), weight, depth); + auto in_edges = UnwrapEdgesResult( + vertex.InEdges(storage::View::OLD, self_.common_.edge_types)); + for (const auto &edge : in_edges) { + expand_pair(edge, edge.From(), weight, depth); } } }; while (true) { - if (context.db_accessor->should_abort()) throw HintedAbortError(); + if (context.db_accessor->MustAbort()) throw HintedAbortError(); if (pq_.empty()) { if (!input_cursor_->Pull(frame, context)) return false; const auto &vertex_value = frame[self_.input_symbol_]; @@ -1428,7 +1494,6 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor { // Skip expansion for such nodes. if (node.IsNull()) continue; } - SwitchAccessor(vertex, storage::View::OLD); if (self_.upper_bound_) { upper_bound_ = EvaluateInt(&evaluator, self_.upper_bound_, @@ -1456,7 +1521,7 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor { } while (!pq_.empty()) { - if (context.db_accessor->should_abort()) throw HintedAbortError(); + if (context.db_accessor->MustAbort()) throw HintedAbortError(); auto current = pq_.top(); double current_weight = std::get<0>(current); int current_depth = std::get<1>(current); @@ -1492,9 +1557,9 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor { const auto &previous_edge = previous_.find(create_state(last_vertex, last_depth))->second; if (!previous_edge) break; - last_vertex = previous_edge->from() == last_vertex - ? previous_edge->to() - : previous_edge->from(); + last_vertex = previous_edge->From() == last_vertex + ? previous_edge->To() + : previous_edge->From(); last_depth--; edge_list.emplace_back(previous_edge.value()); } @@ -1658,10 +1723,10 @@ class ConstructNamedPathCursor : public Cursor { // vertices. const auto &edges = expansion.ValueList(); for (const auto &edge_value : edges) { - const EdgeAccessor &edge = edge_value.ValueEdge(); - const VertexAccessor &from = edge.from(); + const auto &edge = edge_value.ValueEdge(); + const auto &from = edge.From(); if (path.vertices().back() == from) - path.Expand(edge, edge.to()); + path.Expand(edge, edge.To()); else path.Expand(edge, from); } @@ -1828,23 +1893,57 @@ bool Delete::DeleteCursor::Pull(Frame &frame, ExecutionContext &context) { auto &dba = *context.db_accessor; // delete edges first for (TypedValue &expression_result : expression_results) { - if (dba.should_abort()) throw HintedAbortError(); - if (expression_result.type() == TypedValue::Type::Edge) - dba.RemoveEdge(expression_result.ValueEdge()); + if (dba.MustAbort()) throw HintedAbortError(); + if (expression_result.type() == TypedValue::Type::Edge) { + auto maybe_error = dba.RemoveEdge(&expression_result.ValueEdge()); + if (maybe_error.HasError()) { + switch (maybe_error.GetError()) { + case storage::Error::SERIALIZATION_ERROR: + throw QueryRuntimeException( + "Can't serialize due to concurrent operations."); + case storage::Error::DELETED_OBJECT: + case storage::Error::VERTEX_HAS_EDGES: + throw QueryRuntimeException( + "Unexpected error when deleting an edge."); + } + } + } } // delete vertices for (TypedValue &expression_result : expression_results) { - if (dba.should_abort()) throw HintedAbortError(); + if (dba.MustAbort()) throw HintedAbortError(); switch (expression_result.type()) { case TypedValue::Type::Vertex: { - VertexAccessor &va = expression_result.ValueVertex(); - va.SwitchNew(); // necessary because an edge deletion could have - // updated - if (self_.detach_) - dba.DetachRemoveVertex(va); - else if (!dba.RemoveVertex(va)) - throw RemoveAttachedVertexException(); + auto &va = expression_result.ValueVertex(); + if (self_.detach_) { + auto maybe_error = dba.DetachRemoveVertex(&va); + if (maybe_error.HasError()) { + switch (maybe_error.GetError()) { + case storage::Error::SERIALIZATION_ERROR: + throw QueryRuntimeException( + "Can't serialize due to concurrent operations."); + case storage::Error::DELETED_OBJECT: + case storage::Error::VERTEX_HAS_EDGES: + throw QueryRuntimeException( + "Unexpected error when deleting a node."); + } + } + } else { + auto res = dba.RemoveVertex(&va); + if (res.HasError()) { + switch (res.GetError()) { + case storage::Error::SERIALIZATION_ERROR: + throw QueryRuntimeException( + "Can't serialize due to concurrent operations."); + case storage::Error::VERTEX_HAS_EDGES: + throw RemoveAttachedVertexException(); + case storage::Error::DELETED_OBJECT: + throw QueryRuntimeException( + "Unexpected error when deleting a node."); + } + } + } break; } @@ -1952,39 +2051,70 @@ namespace { /// @tparam TRecordAccessor Either RecordAccessor<Vertex> or /// RecordAccessor<Edge> template <typename TRecordAccessor> -void SetPropertiesOnRecord(database::GraphDbAccessor *dba, - TRecordAccessor *record, const TypedValue &rhs, - SetProperties::Op op) { - record->SwitchNew(); +void SetPropertiesOnRecord(DbAccessor *dba, TRecordAccessor *record, + const TypedValue &rhs, SetProperties::Op op) { if (op == SetProperties::Op::REPLACE) { - try { - record->PropsClear(); - } catch (const RecordDeletedError &) { - throw QueryRuntimeException( - "Trying to set properties on a deleted graph element."); + auto maybe_error = record->ClearProperties(); + if (maybe_error.HasError()) { + switch (maybe_error.GetError()) { + case storage::Error::DELETED_OBJECT: + throw QueryRuntimeException( + "Trying to set properties on a deleted graph element."); + case storage::Error::SERIALIZATION_ERROR: + throw QueryRuntimeException( + "Can't serialize due to concurrent operations."); + case storage::Error::VERTEX_HAS_EDGES: + throw QueryRuntimeException( + "Unexpected error when setting properties."); + } } } + auto get_props = [](const auto &record) { + auto maybe_props = record.Properties(storage::View::NEW); + if (maybe_props.HasError()) { + switch (maybe_props.GetError()) { + case storage::Error::DELETED_OBJECT: + throw QueryRuntimeException( + "Trying to get properties from a deleted object."); + case storage::Error::SERIALIZATION_ERROR: + case storage::Error::VERTEX_HAS_EDGES: + throw QueryRuntimeException( + "Unexpected error when getting properties."); + } + } + return *maybe_props; + }; + auto set_props = [record](const auto &properties) { - try { - for (const auto &kv : properties) record->PropsSet(kv.first, kv.second); - } catch (const RecordDeletedError &) { - throw QueryRuntimeException( - "Trying to set properties on a deleted graph element."); + for (const auto &kv : properties) { + auto maybe_error = record->SetProperty(kv.first, kv.second); + if (maybe_error.HasError()) { + switch (maybe_error.GetError()) { + case storage::Error::DELETED_OBJECT: + throw QueryRuntimeException( + "Trying to set properties on a deleted graph element."); + case storage::Error::SERIALIZATION_ERROR: + throw QueryRuntimeException( + "Can't serialize due to concurrent operations."); + case storage::Error::VERTEX_HAS_EDGES: + throw QueryRuntimeException( + "Unexpected error when setting properties."); + } + } } }; switch (rhs.type()) { case TypedValue::Type::Edge: - set_props(rhs.ValueEdge().Properties()); + set_props(get_props(rhs.ValueEdge())); break; case TypedValue::Type::Vertex: - set_props(rhs.ValueVertex().Properties()); + set_props(get_props(rhs.ValueVertex())); break; case TypedValue::Type::Map: { for (const auto &kv : rhs.ValueMap()) - PropsSetChecked(record, dba->Property(std::string(kv.first)), - kv.second); + PropsSetChecked(record, dba->NameToProperty(kv.first), kv.second); break; } default: @@ -2012,12 +2142,12 @@ bool SetProperties::SetPropertiesCursor::Pull(Frame &frame, switch (lhs.type()) { case TypedValue::Type::Vertex: - SetPropertiesOnRecord(context.db_accessor, &lhs.ValueVertex(), rhs, - self_.op_); + SetPropertiesOnRecord(context.db_accessor, &lhs.ValueVertex(), + rhs, self_.op_); break; case TypedValue::Type::Edge: - SetPropertiesOnRecord(context.db_accessor, &lhs.ValueEdge(), rhs, - self_.op_); + SetPropertiesOnRecord(context.db_accessor, &lhs.ValueEdge(), + rhs, self_.op_); break; case TypedValue::Type::Null: // Skip setting properties on Null (can occur in optional match). @@ -2064,11 +2194,20 @@ bool SetLabels::SetLabelsCursor::Pull(Frame &frame, ExecutionContext &context) { if (vertex_value.IsNull()) return true; ExpectType(self_.input_symbol_, vertex_value, TypedValue::Type::Vertex); auto &vertex = vertex_value.ValueVertex(); - vertex.SwitchNew(); - try { - for (auto label : self_.labels_) vertex.add_label(label); - } catch (const RecordDeletedError &) { - throw QueryRuntimeException("Trying to set labels on a deleted node."); + for (auto label : self_.labels_) { + auto maybe_error = vertex.AddLabel(label); + if (maybe_error.HasError()) { + switch (maybe_error.GetError()) { + case storage::Error::SERIALIZATION_ERROR: + throw QueryRuntimeException( + "Can't serialize due to concurrent operations."); + case storage::Error::DELETED_OBJECT: + throw QueryRuntimeException( + "Trying to set a label on a deleted node."); + case storage::Error::VERTEX_HAS_EDGES: + throw QueryRuntimeException("Unexpected error when setting a label."); + } + } } return true; @@ -2109,22 +2248,29 @@ bool RemoveProperty::RemovePropertyCursor::Pull(Frame &frame, storage::View::NEW); TypedValue lhs = self_.lhs_->expression_->Accept(evaluator); + auto remove_prop = [property = self_.property_](auto *record) { + auto maybe_error = record->RemoveProperty(property); + if (maybe_error.HasError()) { + switch (maybe_error.GetError()) { + case storage::Error::DELETED_OBJECT: + throw QueryRuntimeException( + "Trying to remove a property on a deleted graph element."); + case storage::Error::SERIALIZATION_ERROR: + throw QueryRuntimeException( + "Can't serialize due to concurrent operations."); + case storage::Error::VERTEX_HAS_EDGES: + throw QueryRuntimeException( + "Unexpected error when removing property."); + } + } + }; + switch (lhs.type()) { case TypedValue::Type::Vertex: - try { - lhs.ValueVertex().PropsErase(self_.property_); - } catch (const RecordDeletedError &) { - throw QueryRuntimeException( - "Trying to remove properties from a deleted node."); - } + remove_prop(&lhs.ValueVertex()); break; case TypedValue::Type::Edge: - try { - lhs.ValueEdge().PropsErase(self_.property_); - } catch (const RecordDeletedError &) { - throw QueryRuntimeException( - "Trying to remove properties from a deleted edge."); - } + remove_prop(&lhs.ValueEdge()); break; case TypedValue::Type::Null: // Skip removing properties on Null (can occur in optional match). @@ -2173,11 +2319,21 @@ bool RemoveLabels::RemoveLabelsCursor::Pull(Frame &frame, if (vertex_value.IsNull()) return true; ExpectType(self_.input_symbol_, vertex_value, TypedValue::Type::Vertex); auto &vertex = vertex_value.ValueVertex(); - vertex.SwitchNew(); - try { - for (auto label : self_.labels_) vertex.remove_label(label); - } catch (const RecordDeletedError &) { - throw QueryRuntimeException("Trying to remove labels from a deleted node."); + for (auto label : self_.labels_) { + auto maybe_error = vertex.RemoveLabel(label); + if (maybe_error.HasError()) { + switch (maybe_error.GetError()) { + case storage::Error::SERIALIZATION_ERROR: + throw QueryRuntimeException( + "Can't serialize due to concurrent operations."); + case storage::Error::DELETED_OBJECT: + throw QueryRuntimeException( + "Trying to remove labels from a deleted node."); + case storage::Error::VERTEX_HAS_EDGES: + throw QueryRuntimeException( + "Unexpected error when removing labels from a node."); + } + } } return true; @@ -2291,14 +2447,10 @@ class AccumulateCursor : public Cursor { pulled_all_input_ = true; cache_it_ = cache_.begin(); - if (self_.advance_command_) { - dba.AdvanceCommand(); - for (auto &row : cache_) - for (auto &col : row) query::ReconstructTypedValue(col); - } + if (self_.advance_command_) dba.AdvanceCommand(); } - if (dba.should_abort()) throw HintedAbortError(); + if (dba.MustAbort()) throw HintedAbortError(); if (cache_it_ == cache_.end()) return false; auto row_it = (cache_it_++)->begin(); for (const Symbol &symbol : self_.symbols_) frame[symbol] = *row_it++; @@ -2860,7 +3012,7 @@ class OrderByCursor : public Cursor { if (cache_it_ == cache_.end()) return false; - if (context.db_accessor->should_abort()) throw HintedAbortError(); + if (context.db_accessor->MustAbort()) throw HintedAbortError(); // place the output values on the frame DCHECK(self_.output_symbols_.size() == cache_it_->remember.size()) @@ -3091,9 +3243,8 @@ class UnwindCursor : public Cursor { bool Pull(Frame &frame, ExecutionContext &context) override { SCOPED_PROFILE_OP("Unwind"); - while (true) { - if (context.db_accessor->should_abort()) throw HintedAbortError(); + if (context.db_accessor->MustAbort()) throw HintedAbortError(); // if we reached the end of our list of values // pull from the input if (input_value_it_ == input_value_.end()) { @@ -3351,7 +3502,7 @@ class CartesianCursor : public Cursor { restore_frame(self_.right_symbols_, right_op_frame_); } - if (context.db_accessor->should_abort()) throw HintedAbortError(); + if (context.db_accessor->MustAbort()) throw HintedAbortError(); restore_frame(self_.left_symbols_, *left_op_frames_it_); left_op_frames_it_++; diff --git a/src/query/plan/operator.lcp b/src/query/plan/operator.lcp index d899ae1e4..1a3817d59 100644 --- a/src/query/plan/operator.lcp +++ b/src/query/plan/operator.lcp @@ -808,11 +808,12 @@ pulled.") void Reset() override; private: - using InEdgeT = decltype(std::declval<VertexAccessor>().in()); - using InEdgeIteratorT = decltype(std::declval<VertexAccessor>().in().begin()); - using OutEdgeT = decltype(std::declval<VertexAccessor>().out()); - using OutEdgeIteratorT = - decltype(std::declval<VertexAccessor>().out().begin()); + using InEdgeT = std::remove_reference_t<decltype( + *std::declval<VertexAccessor>().InEdges(storage::View::OLD))>; + using InEdgeIteratorT = decltype(std::declval<InEdgeT>().begin()); + using OutEdgeT = std::remove_reference_t<decltype( + *std::declval<VertexAccessor>().OutEdges(storage::View::OLD))>; + using OutEdgeIteratorT = decltype(std::declval<OutEdgeT>().begin()); const Expand &self_; const UniqueCursorPtr input_cursor_; diff --git a/src/query/plan/pretty_print.cpp b/src/query/plan/pretty_print.cpp index 53ec14aef..1db9fae5c 100644 --- a/src/query/plan/pretty_print.cpp +++ b/src/query/plan/pretty_print.cpp @@ -1,13 +1,12 @@ #include "query/plan/pretty_print.hpp" -#include "database/graph_db_accessor.hpp" +#include "query/db_accessor.hpp" #include "query/frontend/ast/pretty_print.hpp" #include "utils/string.hpp" namespace query::plan { -PlanPrinter::PlanPrinter(const database::GraphDbAccessor *dba, - std::ostream *out) +PlanPrinter::PlanPrinter(const DbAccessor *dba, std::ostream *out) : dba_(dba), out_(out) {} #define PRE_VISIT(TOp) \ @@ -24,7 +23,7 @@ bool PlanPrinter::PreVisit(CreateExpand &op) { << (op.edge_info_.direction == query::EdgeAtom::Direction::IN ? "<-" : "-") << "[" << op.edge_info_.symbol.name() << ":" - << dba_->EdgeTypeName(op.edge_info_.edge_type) << "]" + << dba_->EdgeTypeToName(op.edge_info_.edge_type) << "]" << (op.edge_info_.direction == query::EdgeAtom::Direction::OUT ? "->" : "-") << "(" << op.node_info_.symbol.name() << ")"; @@ -46,7 +45,7 @@ bool PlanPrinter::PreVisit(query::plan::ScanAllByLabel &op) { WithPrintLn([&](auto &out) { out << "* ScanAllByLabel" << " (" << op.output_symbol_.name() << " :" - << dba_->LabelName(op.label_) << ")"; + << dba_->LabelToName(op.label_) << ")"; }); return true; } @@ -55,8 +54,8 @@ bool PlanPrinter::PreVisit(query::plan::ScanAllByLabelPropertyValue &op) { WithPrintLn([&](auto &out) { out << "* ScanAllByLabelPropertyValue" << " (" << op.output_symbol_.name() << " :" - << dba_->LabelName(op.label_) << " {" - << dba_->PropertyName(op.property_) << "})"; + << dba_->LabelToName(op.label_) << " {" + << dba_->PropertyToName(op.property_) << "})"; }); return true; } @@ -65,8 +64,8 @@ bool PlanPrinter::PreVisit(query::plan::ScanAllByLabelPropertyRange &op) { WithPrintLn([&](auto &out) { out << "* ScanAllByLabelPropertyRange" << " (" << op.output_symbol_.name() << " :" - << dba_->LabelName(op.label_) << " {" - << dba_->PropertyName(op.property_) << "})"; + << dba_->LabelToName(op.label_) << " {" + << dba_->PropertyToName(op.property_) << "})"; }); return true; } @@ -79,7 +78,7 @@ bool PlanPrinter::PreVisit(query::plan::Expand &op) { << "[" << op.common_.edge_symbol.name(); utils::PrintIterable(*out_, op.common_.edge_types, "|", [this](auto &stream, const auto &edge_type) { - stream << ":" << dba_->EdgeTypeName(edge_type); + stream << ":" << dba_->EdgeTypeToName(edge_type); }); *out_ << "]" << (op.common_.direction == query::EdgeAtom::Direction::OUT ? "->" @@ -97,7 +96,7 @@ bool PlanPrinter::PreVisit(query::plan::ExpandVariable &op) { << "[" << op.common_.edge_symbol.name(); utils::PrintIterable(*out_, op.common_.edge_types, "|", [this](auto &stream, const auto &edge_type) { - stream << ":" << dba_->EdgeTypeName(edge_type); + stream << ":" << dba_->EdgeTypeToName(edge_type); }); *out_ << "]" << (op.common_.direction == query::EdgeAtom::Direction::OUT ? "->" @@ -223,14 +222,14 @@ void PlanPrinter::Branch(query::plan::LogicalOperator &op, --depth_; } -void PrettyPrint(const database::GraphDbAccessor &dba, - const LogicalOperator *plan_root, std::ostream *out) { +void PrettyPrint(const DbAccessor &dba, const LogicalOperator *plan_root, + std::ostream *out) { PlanPrinter printer(&dba, out); // FIXME(mtomic): We should make visitors that take const arguments. const_cast<LogicalOperator *>(plan_root)->Accept(printer); } -nlohmann::json PlanToJson(const database::GraphDbAccessor &dba, +nlohmann::json PlanToJson(const DbAccessor &dba, const LogicalOperator *plan_root) { impl::PlanToJsonVisitor visitor(&dba); // FIXME(mtomic): We should make visitors that take const arguments. @@ -310,16 +309,16 @@ json ToJson(const utils::Bound<Expression *> &bound) { json ToJson(const Symbol &symbol) { return symbol.name(); } -json ToJson(storage::EdgeType edge_type, const database::GraphDbAccessor &dba) { - return dba.EdgeTypeName(edge_type); +json ToJson(storage::EdgeType edge_type, const DbAccessor &dba) { + return dba.EdgeTypeToName(edge_type); } -json ToJson(storage::Label label, const database::GraphDbAccessor &dba) { - return dba.LabelName(label); +json ToJson(storage::Label label, const DbAccessor &dba) { + return dba.LabelToName(label); } -json ToJson(storage::Property property, const database::GraphDbAccessor &dba) { - return dba.PropertyName(property); +json ToJson(storage::Property property, const DbAccessor &dba) { + return dba.PropertyToName(property); } json ToJson(NamedExpression *nexpr) { @@ -331,7 +330,7 @@ json ToJson(NamedExpression *nexpr) { json ToJson( const std::vector<std::pair<storage::Property, Expression *>> &properties, - const database::GraphDbAccessor &dba) { + const DbAccessor &dba) { json json; for (const auto &prop_pair : properties) { json.emplace(ToJson(prop_pair.first, dba), ToJson(prop_pair.second)); @@ -339,8 +338,7 @@ json ToJson( return json; } -json ToJson(const NodeCreationInfo &node_info, - const database::GraphDbAccessor &dba) { +json ToJson(const NodeCreationInfo &node_info, const DbAccessor &dba) { json self; self["symbol"] = ToJson(node_info.symbol); self["labels"] = ToJson(node_info.labels, dba); @@ -348,8 +346,7 @@ json ToJson(const NodeCreationInfo &node_info, return self; } -json ToJson(const EdgeCreationInfo &edge_info, - const database::GraphDbAccessor &dba) { +json ToJson(const EdgeCreationInfo &edge_info, const DbAccessor &dba) { json self; self["symbol"] = ToJson(edge_info.symbol); self["properties"] = ToJson(edge_info.properties, dba); diff --git a/src/query/plan/pretty_print.hpp b/src/query/plan/pretty_print.hpp index ef5b2c036..5c3691162 100644 --- a/src/query/plan/pretty_print.hpp +++ b/src/query/plan/pretty_print.hpp @@ -7,8 +7,8 @@ #include "query/plan/operator.hpp" -namespace database { -class GraphDbAccessor; +namespace query { +class DbAccessor; } namespace query::plan { @@ -16,21 +16,21 @@ namespace query::plan { class LogicalOperator; /// Pretty print a `LogicalOperator` plan to a `std::ostream`. -/// GraphDbAccessor is needed for resolving label and property names. +/// DbAccessor is needed for resolving label and property names. /// Note that `plan_root` isn't modified, but we can't take it as a const /// because we don't have support for visiting a const LogicalOperator. -void PrettyPrint(const database::GraphDbAccessor &dba, - const LogicalOperator *plan_root, std::ostream *out); +void PrettyPrint(const DbAccessor &dba, const LogicalOperator *plan_root, + std::ostream *out); /// Overload of `PrettyPrint` which defaults the `std::ostream` to `std::cout`. -inline void PrettyPrint(const database::GraphDbAccessor &dba, +inline void PrettyPrint(const DbAccessor &dba, const LogicalOperator *plan_root) { PrettyPrint(dba, plan_root, &std::cout); } /// Convert a `LogicalOperator` plan to a JSON representation. -/// GraphDbAccessor is needed for resolving label and property names. -nlohmann::json PlanToJson(const database::GraphDbAccessor &dba, +/// DbAccessor is needed for resolving label and property names. +nlohmann::json PlanToJson(const DbAccessor &dba, const LogicalOperator *plan_root); class PlanPrinter : public virtual HierarchicalLogicalOperatorVisitor { @@ -39,7 +39,7 @@ class PlanPrinter : public virtual HierarchicalLogicalOperatorVisitor { using HierarchicalLogicalOperatorVisitor::PreVisit; using HierarchicalLogicalOperatorVisitor::Visit; - PlanPrinter(const database::GraphDbAccessor *dba, std::ostream *out); + PlanPrinter(const DbAccessor *dba, std::ostream *out); bool DefaultPreVisit() override; @@ -101,7 +101,7 @@ class PlanPrinter : public virtual HierarchicalLogicalOperatorVisitor { void Branch(LogicalOperator &op, const std::string &branch_name = ""); int64_t depth_{0}; - const database::GraphDbAccessor *dba_{nullptr}; + const DbAccessor *dba_{nullptr}; std::ostream *out_{nullptr}; }; @@ -119,26 +119,21 @@ nlohmann::json ToJson(const utils::Bound<Expression *> &bound); nlohmann::json ToJson(const Symbol &symbol); -nlohmann::json ToJson(storage::EdgeType edge_type, - const database::GraphDbAccessor &dba); +nlohmann::json ToJson(storage::EdgeType edge_type, const DbAccessor &dba); -nlohmann::json ToJson(storage::Label label, - const database::GraphDbAccessor &dba); +nlohmann::json ToJson(storage::Label label, const DbAccessor &dba); -nlohmann::json ToJson(storage::Property property, - const database::GraphDbAccessor &dba); +nlohmann::json ToJson(storage::Property property, const DbAccessor &dba); nlohmann::json ToJson(NamedExpression *nexpr); nlohmann::json ToJson( const std::vector<std::pair<storage::Property, Expression *>> &properties, - const database::GraphDbAccessor &dba); + const DbAccessor &dba); -nlohmann::json ToJson(const NodeCreationInfo &node_info, - const database::GraphDbAccessor &dba); +nlohmann::json ToJson(const NodeCreationInfo &node_info, const DbAccessor &dba); -nlohmann::json ToJson(const EdgeCreationInfo &edge_info, - const database::GraphDbAccessor &dba); +nlohmann::json ToJson(const EdgeCreationInfo &edge_info, const DbAccessor &dba); nlohmann::json ToJson(const Aggregate::Element &elem); @@ -153,7 +148,7 @@ nlohmann::json ToJson(const std::vector<T> &items, Args &&... args) { class PlanToJsonVisitor : public virtual HierarchicalLogicalOperatorVisitor { public: - PlanToJsonVisitor(const database::GraphDbAccessor *dba) : dba_(dba) {} + explicit PlanToJsonVisitor(const DbAccessor *dba) : dba_(dba) {} using HierarchicalLogicalOperatorVisitor::PostVisit; using HierarchicalLogicalOperatorVisitor::PreVisit; @@ -204,7 +199,7 @@ class PlanToJsonVisitor : public virtual HierarchicalLogicalOperatorVisitor { protected: nlohmann::json output_; - const database::GraphDbAccessor *dba_; + const DbAccessor *dba_; nlohmann::json PopOutput() { nlohmann::json tmp; diff --git a/src/query/plan/rewrite/index_lookup.hpp b/src/query/plan/rewrite/index_lookup.hpp index 482027ded..eb119ef6a 100644 --- a/src/query/plan/rewrite/index_lookup.hpp +++ b/src/query/plan/rewrite/index_lookup.hpp @@ -418,10 +418,12 @@ class IndexLookupRewriter final : public HierarchicalLogicalOperatorVisitor { } } - storage::Label GetLabel(LabelIx label) { return db_->Label(label.name); } + storage::Label GetLabel(LabelIx label) { + return db_->NameToLabel(label.name); + } storage::Property GetProperty(PropertyIx prop) { - return db_->Property(prop.name); + return db_->NameToProperty(prop.name); } LabelIx FindBestLabelIndex(const std::unordered_set<LabelIx> &labels) { diff --git a/src/query/plan/rule_based_planner.hpp b/src/query/plan/rule_based_planner.hpp index 331f975bd..59bc895f4 100644 --- a/src/query/plan/rule_based_planner.hpp +++ b/src/query/plan/rule_based_planner.hpp @@ -221,15 +221,15 @@ class RuleBasedPlanner { TPlanningContext *context_; storage::Label GetLabel(LabelIx label) { - return context_->db->Label(label.name); + return context_->db->NameToLabel(label.name); } storage::Property GetProperty(PropertyIx prop) { - return context_->db->Property(prop.name); + return context_->db->NameToProperty(prop.name); } storage::EdgeType GetEdgeType(EdgeTypeIx edge_type) { - return context_->db->EdgeType(edge_type.name); + return context_->db->NameToEdgeType(edge_type.name); } std::unique_ptr<LogicalOperator> GenCreate( diff --git a/src/query/plan/vertex_count_cache.hpp b/src/query/plan/vertex_count_cache.hpp index d83c7f5df..dfaf3b479 100644 --- a/src/query/plan/vertex_count_cache.hpp +++ b/src/query/plan/vertex_count_cache.hpp @@ -18,9 +18,13 @@ class VertexCountCache { public: VertexCountCache(TDbAccessor *db) : db_(db) {} - auto Label(const std::string &name) { return db_->Label(name); } - auto Property(const std::string &name) { return db_->Property(name); } - auto EdgeType(const std::string &name) { return db_->EdgeType(name); } + auto NameToLabel(const std::string &name) { return db_->NameToLabel(name); } + auto NameToProperty(const std::string &name) { + return db_->NameToProperty(name); + } + auto NameToEdgeType(const std::string &name) { + return db_->NameToEdgeType(name); + } int64_t VerticesCount() { if (!vertices_count_) vertices_count_ = db_->VerticesCount(); diff --git a/src/query/repl.cpp b/src/query/repl.cpp index aa23a27e2..14c856b8b 100644 --- a/src/query/repl.cpp +++ b/src/query/repl.cpp @@ -63,8 +63,9 @@ void query::Repl(database::GraphDb *db, query::Interpreter *interpreter) { try { auto dba = db->Access(); ResultStreamFaker<query::TypedValue> stream; - auto results = - (*interpreter)(command, dba, {}, false, utils::NewDeleteResource()); + DbAccessor execution_dba(&dba); + auto results = (*interpreter)(command, &execution_dba, {}, false, + utils::NewDeleteResource()); stream.Header(results.header()); results.PullAll(stream); stream.Summary(results.summary()); diff --git a/src/query/transaction_engine.hpp b/src/query/transaction_engine.hpp index 1519507c5..b286d77de 100644 --- a/src/query/transaction_engine.hpp +++ b/src/query/transaction_engine.hpp @@ -14,7 +14,11 @@ static constexpr size_t kExecutionMemoryBlockSize = 1U * 1024U * 1024U; class TransactionEngine final { public: +#ifdef MG_SINGLE_NODE_V2 + TransactionEngine(storage::Storage *db, Interpreter *interpreter) +#else TransactionEngine(database::GraphDb *db, Interpreter *interpreter) +#endif : db_(db), interpreter_(interpreter), execution_memory_(&initial_memory_block_[0], @@ -72,7 +76,10 @@ class TransactionEngine final { if (in_explicit_transaction_ && db_accessor_) AdvanceCommand(); // Create a DB accessor if we don't yet have one. - if (!db_accessor_) db_accessor_.emplace(db_->Access()); + if (!db_accessor_) { + db_accessor_.emplace(db_->Access()); + execution_db_accessor_.emplace(&*db_accessor_); + } // Clear leftover results. results_ = std::nullopt; @@ -80,7 +87,7 @@ class TransactionEngine final { // Interpret the query and return the headers. try { - results_.emplace((*interpreter_)(query, *db_accessor_, params, + results_.emplace((*interpreter_)(query, &*execution_db_accessor_, params, in_explicit_transaction_, &execution_memory_)); return {std::move(results_->header()), std::move(results_->privileges())}; @@ -129,13 +136,20 @@ class TransactionEngine final { in_explicit_transaction_ = false; if (!db_accessor_) return; db_accessor_->Abort(); + execution_db_accessor_ = std::nullopt; db_accessor_ = std::nullopt; } private: +#ifdef MG_SINGLE_NODE_V2 + storage::Storage *db_{nullptr}; + std::optional<storage::Storage::Accessor> db_accessor_; +#else database::GraphDb *db_{nullptr}; - Interpreter *interpreter_{nullptr}; std::optional<database::GraphDbAccessor> db_accessor_; +#endif + std::optional<DbAccessor> execution_db_accessor_; + Interpreter *interpreter_{nullptr}; // The `query::Interpreter::Results` object MUST be destroyed before the // `database::GraphDbAccessor` is destroyed because the `Results` object holds // references to the `GraphDb` object and will crash the database when @@ -151,7 +165,24 @@ class TransactionEngine final { results_ = std::nullopt; execution_memory_.Release(); if (!db_accessor_) return; +#ifdef MG_SINGLE_NODE_V2 + auto maybe_constraint_violation = db_accessor_->Commit(); + if (maybe_constraint_violation.HasError()) { + const auto &constraint_violation = maybe_constraint_violation.GetError(); + auto label_name = execution_db_accessor_->LabelToName( + constraint_violation.label); + auto property_name = execution_db_accessor_->PropertyToName( + constraint_violation.property); + execution_db_accessor_ = std::nullopt; + db_accessor_ = std::nullopt; + throw QueryException( + "Unable to commit due to existence constraint violation on :{}({}).", + label_name, property_name); + } +#else db_accessor_->Commit(); +#endif + execution_db_accessor_ = std::nullopt; db_accessor_ = std::nullopt; } diff --git a/src/query/typed_value.cpp b/src/query/typed_value.cpp index 3c97a24f0..dec08b625 100644 --- a/src/query/typed_value.cpp +++ b/src/query/typed_value.cpp @@ -904,9 +904,9 @@ size_t TypedValue::Hash::operator()(const TypedValue &value) const { return hash; } case TypedValue::Type::Vertex: - return value.ValueVertex().gid().AsUint(); + return value.ValueVertex().Gid().AsUint(); case TypedValue::Type::Edge: - return value.ValueEdge().gid().AsUint(); + return value.ValueEdge().Gid().AsUint(); case TypedValue::Type::Path: { const auto &vertices = value.ValuePath().vertices(); const auto &edges = value.ValuePath().edges(); diff --git a/src/query/typed_value.hpp b/src/query/typed_value.hpp index d697f03ec..9f52e0387 100644 --- a/src/query/typed_value.hpp +++ b/src/query/typed_value.hpp @@ -9,10 +9,8 @@ #include <utility> #include <vector> +#include "query/db_accessor.hpp" #include "query/path.hpp" -#include "storage/common/types/property_value.hpp" -#include "storage/edge_accessor.hpp" -#include "storage/vertex_accessor.hpp" #include "utils/exceptions.hpp" #include "utils/memory.hpp" #include "utils/pmr/map.hpp" diff --git a/src/storage/common/types/types.hpp b/src/storage/common/types/types.hpp index b86aee9e1..0948e04c8 100644 --- a/src/storage/common/types/types.hpp +++ b/src/storage/common/types/types.hpp @@ -1,5 +1,14 @@ #pragma once +#ifdef MG_SINGLE_NODE_V2 +#include "storage/v2/id_types.hpp" +namespace storage { +using EdgeType = EdgeTypeId; +using Label = LabelId; +using Property = PropertyId; +} +#else + #include <atomic> #include <cstdint> #include <functional> @@ -247,3 +256,5 @@ struct hash<storage::Gid> { } }; } // namespace std + +#endif diff --git a/src/storage/edge_accessor.hpp b/src/storage/edge_accessor.hpp index 9b7cb0a97..92a01dac1 100644 --- a/src/storage/edge_accessor.hpp +++ b/src/storage/edge_accessor.hpp @@ -1,5 +1,10 @@ #pragma once +#ifdef MG_SINGLE_NODE_V2 +#include "storage/v2/edge_accessor.hpp" +using EdgeAccessor = storage::EdgeAccessor; +#endif + #ifdef MG_SINGLE_NODE #include "storage/single_node/edge_accessor.hpp" #endif diff --git a/src/storage/single_node/record_accessor.hpp b/src/storage/single_node/record_accessor.hpp index 2c8d9386c..db7986249 100644 --- a/src/storage/single_node/record_accessor.hpp +++ b/src/storage/single_node/record_accessor.hpp @@ -64,6 +64,7 @@ class RecordAccessor { /** * Erases the property for the given key. + * @throw RecordDeletedError * @throw utils::LockTimeoutException * @throw SerializationError */ @@ -71,6 +72,7 @@ class RecordAccessor { /** * Removes all the properties from this record. + * @throw RecordDeletedError * @throw utils::LockTimeoutException * @throw SerializationError */ diff --git a/src/storage/v2/edge_accessor.hpp b/src/storage/v2/edge_accessor.hpp index fc17152c4..9facf0e7d 100644 --- a/src/storage/v2/edge_accessor.hpp +++ b/src/storage/v2/edge_accessor.hpp @@ -47,6 +47,8 @@ class EdgeAccessor final { Gid Gid() const { return edge_->gid; } + bool IsCycle() const { return from_vertex_ == to_vertex_; } + bool operator==(const EdgeAccessor &other) const { return edge_ == other.edge_ && transaction_ == other.transaction_; } diff --git a/src/storage/v2/storage.cpp b/src/storage/v2/storage.cpp index 865b2d6c7..f14fd3f64 100644 --- a/src/storage/v2/storage.cpp +++ b/src/storage/v2/storage.cpp @@ -2,10 +2,15 @@ #include <memory> +#include <gflags/gflags.h> #include <glog/logging.h> #include "storage/v2/mvcc.hpp" +DEFINE_string( + durability_directory, "durability", + "Path to directory in which to save snapshots and write-ahead log files."); + namespace storage { auto AdvanceToVisibleVertex(utils::SkipList<Vertex>::Iterator it, diff --git a/src/storage/vertex_accessor.hpp b/src/storage/vertex_accessor.hpp index ef2718fcd..2b33fa41f 100644 --- a/src/storage/vertex_accessor.hpp +++ b/src/storage/vertex_accessor.hpp @@ -1,5 +1,10 @@ #pragma once +#ifdef MG_SINGLE_NODE_V2 +#include "storage/v2/vertex_accessor.hpp" +using VertexAccessor = storage::VertexAccessor; +#endif + #ifdef MG_SINGLE_NODE #include "storage/single_node/vertex_accessor.hpp" #endif diff --git a/tests/benchmark/expansion.cpp b/tests/benchmark/expansion.cpp index 9412786a1..64eb2d04d 100644 --- a/tests/benchmark/expansion.cpp +++ b/tests/benchmark/expansion.cpp @@ -44,9 +44,10 @@ class ExpansionBenchFixture : public benchmark::Fixture { BENCHMARK_DEFINE_F(ExpansionBenchFixture, Match)(benchmark::State &state) { auto query = "MATCH (s:Starting) return s"; auto dba = db_->Access(); + query::DbAccessor query_dba(&dba); while (state.KeepRunning()) { ResultStreamFaker<query::TypedValue> results; - interpreter()(query, dba, {}, false, utils::NewDeleteResource()) + interpreter()(query, &query_dba, {}, false, utils::NewDeleteResource()) .PullAll(results); } } @@ -59,9 +60,10 @@ BENCHMARK_REGISTER_F(ExpansionBenchFixture, Match) BENCHMARK_DEFINE_F(ExpansionBenchFixture, Expand)(benchmark::State &state) { auto query = "MATCH (s:Starting) WITH s MATCH (s)--(d) RETURN count(d)"; auto dba = db_->Access(); + query::DbAccessor query_dba(&dba); while (state.KeepRunning()) { ResultStreamFaker<query::TypedValue> results; - interpreter()(query, dba, {}, false, utils::NewDeleteResource()) + interpreter()(query, &query_dba, {}, false, utils::NewDeleteResource()) .PullAll(results); } } diff --git a/tests/benchmark/query/eval.cpp b/tests/benchmark/query/eval.cpp index b328aea4a..ccbaf8bbe 100644 --- a/tests/benchmark/query/eval.cpp +++ b/tests/benchmark/query/eval.cpp @@ -1,5 +1,6 @@ #include <benchmark/benchmark.h> +#include "query/db_accessor.hpp" #include "query/interpret/eval.hpp" #include "query/transaction_engine.hpp" @@ -27,6 +28,7 @@ static void MapLiteral(benchmark::State &state) { query::Frame frame(symbol_table.max_position(), memory.get()); database::GraphDb db; auto dba = db.Access(); + query::DbAccessor execution_dba(&dba); std::unordered_map<query::PropertyIx, query::Expression *> elements; for (int64_t i = 0; i < state.range(0); ++i) { elements.emplace(ast.GetPropertyIx("prop" + std::to_string(i)), @@ -35,9 +37,9 @@ static void MapLiteral(benchmark::State &state) { auto *expr = ast.Create<query::MapLiteral>(elements); query::EvaluationContext evaluation_context{memory.get()}; evaluation_context.properties = - query::NamesToProperties(ast.properties_, &dba); + query::NamesToProperties(ast.properties_, &execution_dba); query::ExpressionEvaluator evaluator(&frame, symbol_table, evaluation_context, - &dba, storage::View::NEW); + &execution_dba, storage::View::NEW); while (state.KeepRunning()) { benchmark::DoNotOptimize(expr->Accept(evaluator)); } @@ -67,8 +69,9 @@ static void AdditionOperator(benchmark::State &state) { expr, ast.Create<query::PrimitiveLiteral>(i)); } query::EvaluationContext evaluation_context{memory.get()}; + query::DbAccessor execution_dba(&dba); query::ExpressionEvaluator evaluator(&frame, symbol_table, evaluation_context, - &dba, storage::View::NEW); + &execution_dba, storage::View::NEW); while (state.KeepRunning()) { benchmark::DoNotOptimize(expr->Accept(evaluator)); } diff --git a/tests/benchmark/query/execution.cpp b/tests/benchmark/query/execution.cpp index f16899a8a..48b8bfb24 100644 --- a/tests/benchmark/query/execution.cpp +++ b/tests/benchmark/query/execution.cpp @@ -108,8 +108,9 @@ static void Distinct(benchmark::State &state) { auto query_string = "MATCH (s) RETURN DISTINCT s"; auto *cypher_query = ParseCypherQuery(query_string, &ast); auto symbol_table = query::MakeSymbolTable(cypher_query); - auto context = - query::plan::MakePlanningContext(&ast, &symbol_table, cypher_query, &dba); + query::DbAccessor execution_dba(&dba); + auto context = query::plan::MakePlanningContext(&ast, &symbol_table, + cypher_query, &execution_dba); auto plan_and_cost = query::plan::MakeLogicalPlan(&context, parameters, false); ResultStreamFaker<query::TypedValue> results; @@ -117,7 +118,7 @@ static void Distinct(benchmark::State &state) { TMemory per_pull_memory; query::EvaluationContext evaluation_context{per_pull_memory.get()}; while (state.KeepRunning()) { - query::ExecutionContext execution_context{&dba, symbol_table, + query::ExecutionContext execution_context{&execution_dba, symbol_table, evaluation_context}; TMemory memory; query::Frame frame(symbol_table.max_position(), memory.get()); @@ -171,13 +172,15 @@ static void ExpandVariable(benchmark::State &state) { TMemory per_pull_memory; query::EvaluationContext evaluation_context{per_pull_memory.get()}; while (state.KeepRunning()) { - query::ExecutionContext execution_context{&dba, symbol_table, + query::DbAccessor execution_dba(&dba); + query::ExecutionContext execution_context{&execution_dba, symbol_table, evaluation_context}; TMemory memory; query::Frame frame(symbol_table.max_position(), memory.get()); auto cursor = expand_variable.MakeCursor(memory.get()); for (const auto &v : dba.Vertices(dba.Label(kStartLabel), false)) { - frame[expand_variable.input_symbol_] = query::TypedValue(v); + frame[expand_variable.input_symbol_] = + query::TypedValue(query::VertexAccessor(v)); while (cursor->Pull(frame, execution_context)) per_pull_memory.Reset(); } } @@ -211,13 +214,15 @@ static void ExpandBfs(benchmark::State &state) { TMemory per_pull_memory; query::EvaluationContext evaluation_context{per_pull_memory.get()}; while (state.KeepRunning()) { - query::ExecutionContext execution_context{&dba, symbol_table, + query::DbAccessor execution_dba(&dba); + query::ExecutionContext execution_context{&execution_dba, symbol_table, evaluation_context}; TMemory memory; query::Frame frame(symbol_table.max_position(), memory.get()); auto cursor = expand_variable.MakeCursor(memory.get()); for (const auto &v : dba.Vertices(dba.Label(kStartLabel), false)) { - frame[expand_variable.input_symbol_] = query::TypedValue(v); + frame[expand_variable.input_symbol_] = + query::TypedValue(query::VertexAccessor(v)); while (cursor->Pull(frame, execution_context)) per_pull_memory.Reset(); } } @@ -253,15 +258,17 @@ static void ExpandShortest(benchmark::State &state) { TMemory per_pull_memory; query::EvaluationContext evaluation_context{per_pull_memory.get()}; while (state.KeepRunning()) { - query::ExecutionContext execution_context{&dba, symbol_table, + query::DbAccessor execution_dba(&dba); + query::ExecutionContext execution_context{&execution_dba, symbol_table, evaluation_context}; TMemory memory; query::Frame frame(symbol_table.max_position(), memory.get()); auto cursor = expand_variable.MakeCursor(memory.get()); for (const auto &v : dba.Vertices(dba.Label(kStartLabel), false)) { - frame[expand_variable.input_symbol_] = query::TypedValue(v); + frame[expand_variable.input_symbol_] = + query::TypedValue(query::VertexAccessor(v)); for (const auto &dest : dba.Vertices(false)) { - frame[dest_symbol] = query::TypedValue(dest); + frame[dest_symbol] = query::TypedValue(query::VertexAccessor(dest)); while (cursor->Pull(frame, execution_context)) per_pull_memory.Reset(); } } @@ -302,15 +309,17 @@ static void ExpandWeightedShortest(benchmark::State &state) { TMemory per_pull_memory; query::EvaluationContext evaluation_context{per_pull_memory.get()}; while (state.KeepRunning()) { - query::ExecutionContext execution_context{&dba, symbol_table, + query::DbAccessor execution_dba(&dba); + query::ExecutionContext execution_context{&execution_dba, symbol_table, evaluation_context}; TMemory memory; query::Frame frame(symbol_table.max_position(), memory.get()); auto cursor = expand_variable.MakeCursor(memory.get()); for (const auto &v : dba.Vertices(dba.Label(kStartLabel), false)) { - frame[expand_variable.input_symbol_] = query::TypedValue(v); + frame[expand_variable.input_symbol_] = + query::TypedValue(query::VertexAccessor(v)); for (const auto &dest : dba.Vertices(false)) { - frame[dest_symbol] = query::TypedValue(dest); + frame[dest_symbol] = query::TypedValue(query::VertexAccessor(dest)); while (cursor->Pull(frame, execution_context)) per_pull_memory.Reset(); } } @@ -352,7 +361,8 @@ static void Accumulate(benchmark::State &state) { TMemory per_pull_memory; query::EvaluationContext evaluation_context{per_pull_memory.get()}; while (state.KeepRunning()) { - query::ExecutionContext execution_context{&dba, symbol_table, + query::DbAccessor execution_dba(&dba); + query::ExecutionContext execution_context{&execution_dba, symbol_table, evaluation_context}; TMemory memory; query::Frame frame(symbol_table.max_position(), memory.get()); @@ -405,7 +415,8 @@ static void Aggregate(benchmark::State &state) { TMemory per_pull_memory; query::EvaluationContext evaluation_context{per_pull_memory.get()}; while (state.KeepRunning()) { - query::ExecutionContext execution_context{&dba, symbol_table, + query::DbAccessor execution_dba(&dba); + query::ExecutionContext execution_context{&execution_dba, symbol_table, evaluation_context}; TMemory memory; query::Frame frame(symbol_table.max_position(), memory.get()); @@ -459,7 +470,8 @@ static void OrderBy(benchmark::State &state) { TMemory per_pull_memory; query::EvaluationContext evaluation_context{per_pull_memory.get()}; while (state.KeepRunning()) { - query::ExecutionContext execution_context{&dba, symbol_table, + query::DbAccessor execution_dba(&dba); + query::ExecutionContext execution_context{&execution_dba, symbol_table, evaluation_context}; TMemory memory; query::Frame frame(symbol_table.max_position(), memory.get()); @@ -500,7 +512,8 @@ static void Unwind(benchmark::State &state) { TMemory per_pull_memory; query::EvaluationContext evaluation_context{per_pull_memory.get()}; while (state.KeepRunning()) { - query::ExecutionContext execution_context{&dba, symbol_table, + query::DbAccessor execution_dba(&dba); + query::ExecutionContext execution_context{&execution_dba, symbol_table, evaluation_context}; TMemory memory; query::Frame frame(symbol_table.max_position(), memory.get()); diff --git a/tests/benchmark/query/planner.cpp b/tests/benchmark/query/planner.cpp index 3187138e8..3dbad357b 100644 --- a/tests/benchmark/query/planner.cpp +++ b/tests/benchmark/query/planner.cpp @@ -42,8 +42,9 @@ static void BM_PlanChainedMatches(benchmark::State &state) { int num_matches = state.range(0); auto *query = AddChainedMatches(num_matches, storage); auto symbol_table = query::MakeSymbolTable(query); + query::DbAccessor exec_dba(&dba); auto ctx = query::plan::MakePlanningContext(&storage, &symbol_table, query, - &dba); + &exec_dba); state.ResumeTiming(); auto query_parts = query::plan::CollectQueryParts(symbol_table, storage, query); @@ -121,8 +122,9 @@ static void BM_PlanAndEstimateIndexedMatching(benchmark::State &state) { auto *query = AddIndexedMatches(index_count, label, prop, storage); auto symbol_table = query::MakeSymbolTable(query); state.ResumeTiming(); + query::DbAccessor exec_dba(&dba); auto ctx = query::plan::MakePlanningContext(&storage, &symbol_table, query, - &dba); + &exec_dba); auto query_parts = query::plan::CollectQueryParts(symbol_table, storage, query); if (query_parts.query_parts.size() == 0) { @@ -146,7 +148,8 @@ static void BM_PlanAndEstimateIndexedMatchingWithCachedCounts( int vertex_count = state.range(1); std::tie(label, prop) = CreateIndexedVertices(index_count, vertex_count, db); auto dba = db.Access(); - auto vertex_counts = query::plan::MakeVertexCountCache(&dba); + query::DbAccessor exec_dba(&dba); + auto vertex_counts = query::plan::MakeVertexCountCache(&exec_dba); query::Parameters parameters; while (state.KeepRunning()) { state.PauseTiming(); diff --git a/tests/manual/interactive_planning.cpp b/tests/manual/interactive_planning.cpp index 901c28860..b833400ac 100644 --- a/tests/manual/interactive_planning.cpp +++ b/tests/manual/interactive_planning.cpp @@ -133,9 +133,9 @@ class InteractiveDbAccessor { Timer &timer) : dba_(dba), vertices_count_(vertices_count), timer_(timer) {} - auto Label(const std::string &name) { return dba_->Label(name); } - auto Property(const std::string &name) { return dba_->Property(name); } - auto EdgeType(const std::string &name) { return dba_->EdgeType(name); } + auto NameToLabel(const std::string &name) { return dba_->Label(name); } + auto NameToProperty(const std::string &name) { return dba_->Property(name); } + auto NameToEdgeType(const std::string &name) { return dba_->EdgeType(name); } int64_t VerticesCount() { return vertices_count_; } @@ -368,7 +368,8 @@ DEFCOMMAND(Top) { for (int64_t i = 0; i < n_plans; ++i) { std::cout << "---- Plan #" << i << " ---- " << std::endl; std::cout << "cost: " << plans[i].cost << std::endl; - query::plan::PrettyPrint(dba, plans[i].final_plan.get()); + query::DbAccessor query_dba(&dba); + query::plan::PrettyPrint(query_dba, plans[i].final_plan.get()); std::cout << std::endl; } } @@ -381,7 +382,8 @@ DEFCOMMAND(Show) { const auto &plan = plans[plan_ix].final_plan; auto cost = plans[plan_ix].cost; std::cout << "Plan cost: " << cost << std::endl; - query::plan::PrettyPrint(dba, plan.get()); + query::DbAccessor query_dba(&dba); + query::plan::PrettyPrint(query_dba, plan.get()); } DEFCOMMAND(ShowUnoptimized) { @@ -390,7 +392,8 @@ DEFCOMMAND(ShowUnoptimized) { ss >> plan_ix; if (ss.fail() || !ss.eof() || plan_ix >= plans.size()) return; const auto &plan = plans[plan_ix].unoptimized_plan; - query::plan::PrettyPrint(dba, plan.get()); + query::DbAccessor query_dba(&dba); + query::plan::PrettyPrint(query_dba, plan.get()); } DEFCOMMAND(Help); diff --git a/tests/manual/single_query.cpp b/tests/manual/single_query.cpp index 49a4f3398..57a753217 100644 --- a/tests/manual/single_query.cpp +++ b/tests/manual/single_query.cpp @@ -13,9 +13,10 @@ int main(int argc, char *argv[]) { } database::GraphDb db; auto dba = db.Access(); + query::DbAccessor query_dba(&dba); ResultStreamFaker<query::TypedValue> stream; - auto results = - query::Interpreter()(argv[1], dba, {}, false, utils::NewDeleteResource()); + auto results = query::Interpreter()(argv[1], &query_dba, {}, false, + utils::NewDeleteResource()); stream.Header(results.header()); results.PullAll(stream); stream.Summary(results.summary()); diff --git a/tests/qa/tests/memgraph_V1/features/memgraph.feature b/tests/qa/tests/memgraph_V1/features/memgraph.feature index b73640906..8a13a5a74 100644 --- a/tests/qa/tests/memgraph_V1/features/memgraph.feature +++ b/tests/qa/tests/memgraph_V1/features/memgraph.feature @@ -31,7 +31,7 @@ Feature: Memgraph only tests (queries in which we choose to be incompatible with Given an empty graph When executing query: """ - CREATE(a:A), (b:B), (c:C), (a)-[:T]->(b) WITH a DETACH DELETE a WITH a MATCH()-[r:T]->() RETURN r + CREATE(a:A), (b:B), (c:C), (a)-[:T]->(b) WITH a DETACH DELETE a WITH a MATCH(a)-[r:T]->() RETURN r """ Then an error should be raised diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 199aad11f..b4913029a 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -6,7 +6,7 @@ function(add_unit_test test_cpp) # get exec name (remove extension from the abs path) get_filename_component(exec_name ${test_cpp} NAME_WE) set(target_name ${test_prefix}${exec_name}) - add_executable(${target_name} ${test_cpp}) + add_executable(${target_name} ${test_cpp} ${ARGN}) # OUTPUT_NAME sets the real name of a target when it is built and can be # used to help create two targets of the same name even though CMake # requires unique logical target names @@ -132,6 +132,37 @@ target_link_libraries(${test_prefix}query_plan_bag_semantics mg-single-node kvst add_unit_test(query_plan_create_set_remove_delete.cpp) target_link_libraries(${test_prefix}query_plan_create_set_remove_delete mg-single-node kvstore_dummy_lib) +# Storage V2 in query execution +define_add_lcp(add_lcp_query_plan_v2_create_set_remove_delete + lcp_query_plan_v2_create_set_remove_delete + generated_lcp_query_plan_v2_create_set_remove_delete_files) + +add_lcp_query_plan_v2_create_set_remove_delete( + ${CMAKE_SOURCE_DIR}/src/query/frontend/ast/ast.lcp) +add_lcp_query_plan_v2_create_set_remove_delete( + ${CMAKE_SOURCE_DIR}/src/query/frontend/semantic/symbol.lcp) +add_lcp_query_plan_v2_create_set_remove_delete( + ${CMAKE_SOURCE_DIR}/src/query/plan/operator.lcp) + +add_custom_target(generate_lcp_query_plan_v2_create_set_remove_delete DEPENDS + ${generated_lcp_query_plan_v2_create_set_remove_delete_files}) + +add_unit_test(query_plan_v2_create_set_remove_delete.cpp + ${lcp_query_plan_v2_create_set_remove_delete} + ${CMAKE_SOURCE_DIR}/src/query/common.cpp + # ${CMAKE_SOURCE_DIR}/src/query/frontend/ast/ast.lcp.cpp + ${CMAKE_SOURCE_DIR}/src/query/frontend/ast/pretty_print.cpp + ${CMAKE_SOURCE_DIR}/src/query/plan/operator.cpp + # ${CMAKE_SOURCE_DIR}/src/query/plan/operator.lcp.cpp + ${CMAKE_SOURCE_DIR}/src/query/typed_value.cpp) +target_compile_definitions(${test_prefix}query_plan_v2_create_set_remove_delete PUBLIC MG_SINGLE_NODE_V2) +target_link_libraries(${test_prefix}query_plan_v2_create_set_remove_delete glog cppitertools) +target_link_libraries(${test_prefix}query_plan_v2_create_set_remove_delete mg-storage-v2) +add_dependencies(${test_prefix}query_plan_v2_create_set_remove_delete + generate_lcp_query_plan_v2_create_set_remove_delete) + +# END Storage V2 in query execution + add_unit_test(query_plan_edge_cases.cpp) target_link_libraries(${test_prefix}query_plan_edge_cases mg-single-node kvstore_dummy_lib) diff --git a/tests/unit/bfs_common.hpp b/tests/unit/bfs_common.hpp index ef1477e2a..38e4fabb4 100644 --- a/tests/unit/bfs_common.hpp +++ b/tests/unit/bfs_common.hpp @@ -228,8 +228,8 @@ std::unique_ptr<query::plan::LogicalOperator> YieldVertices( std::vector<std::vector<query::TypedValue>> frames; frames.push_back(std::vector<query::TypedValue>{query::TypedValue()}); for (const auto &vertex : vertices) { - frames.emplace_back(std::vector<query::TypedValue>{ - query::TypedValue(VertexAccessor(vertex, *dba))}); + frames.emplace_back(std::vector<query::TypedValue>{query::TypedValue( + query::VertexAccessor(VertexAccessor(vertex, *dba)))}); } return std::make_unique<Yield>(input_op, std::vector<query::Symbol>{symbol}, frames); @@ -242,12 +242,12 @@ std::unique_ptr<query::plan::LogicalOperator> YieldEntities( std::shared_ptr<query::plan::LogicalOperator> input_op) { std::vector<std::vector<query::TypedValue>> frames; for (const auto &vertex : vertices) { - frames.emplace_back(std::vector<query::TypedValue>{ - query::TypedValue(VertexAccessor(vertex, *dba))}); + frames.emplace_back(std::vector<query::TypedValue>{query::TypedValue( + query::VertexAccessor(VertexAccessor(vertex, *dba)))}); } for (const auto &edge : edges) { frames.emplace_back(std::vector<query::TypedValue>{ - query::TypedValue(EdgeAccessor(edge, *dba))}); + query::TypedValue(query::EdgeAccessor(EdgeAccessor(edge, *dba)))}); } return std::make_unique<Yield>(input_op, std::vector<query::Symbol>{symbol}, frames); @@ -259,20 +259,30 @@ auto GetProp(const RecordAccessor<TRecord> &rec, std::string prop, return rec.PropsAt(dba->Property(prop)); } +inline auto GetProp(const query::VertexAccessor &rec, std::string prop, + database::GraphDbAccessor *dba) { + return GetProp(rec.impl_, prop, dba); +} + +inline auto GetProp(const query::EdgeAccessor &rec, std::string prop, + database::GraphDbAccessor *dba) { + return GetProp(rec.impl_, prop, dba); +} + // Checks if the given path is actually a path from source to sink and if all // of its edges exist in the given edge list. template <class TPathAllocator> -void CheckPath(database::GraphDbAccessor *dba, const VertexAccessor &source, - const VertexAccessor &sink, +void CheckPath(database::GraphDbAccessor *dba, const query::VertexAccessor &source, + const query::VertexAccessor &sink, const std::vector<query::TypedValue, TPathAllocator> &path, const std::vector<std::pair<int, int>> &edges) { - VertexAccessor curr = source; + auto curr = source; for (const auto &edge_tv : path) { ASSERT_TRUE(edge_tv.IsEdge()); auto edge = edge_tv.ValueEdge(); - ASSERT_TRUE(edge.from() == curr || edge.to() == curr); - VertexAccessor next = edge.from_is(curr) ? edge.to() : edge.from(); + ASSERT_TRUE(edge.From() == curr || edge.To() == curr); + auto next = edge.From() == curr ? edge.To() : edge.From(); int from = GetProp(curr, "id", dba).ValueInt(); int to = GetProp(next, "id", dba).ValueInt(); @@ -311,7 +321,8 @@ void BfsTest(Database *db, int lower_bound, int upper_bound, auto dba_ptr = db->Access(); auto &dba = *dba_ptr; query::AstStorage storage; - query::ExecutionContext context{dba_ptr.get()}; + query::DbAccessor execution_dba(&dba); + query::ExecutionContext context{&execution_dba}; query::Symbol blocked_sym = context.symbol_table.CreateSymbol("blocked", true); query::Symbol source_sym = context.symbol_table.CreateSymbol("source", true); @@ -343,8 +354,7 @@ void BfsTest(Database *db, int lower_bound, int upper_bound, // No filter lambda, nothing is ever blocked. input_op = std::make_shared<Yield>( nullptr, std::vector<query::Symbol>{blocked_sym}, - std::vector<std::vector<query::TypedValue>>{ - {query::TypedValue()}}); + std::vector<std::vector<query::TypedValue>>{{query::TypedValue()}}); filter_expr = nullptr; break; case FilterLambdaType::USE_FRAME: @@ -364,8 +374,8 @@ void BfsTest(Database *db, int lower_bound, int upper_bound, // We only block vertex #5 and run BFS. input_op = std::make_shared<Yield>( nullptr, std::vector<query::Symbol>{blocked_sym}, - std::vector<std::vector<query::TypedValue>>{ - {query::TypedValue(VertexAccessor(vertices[5], *dba_ptr))}}); + std::vector<std::vector<query::TypedValue>>{{query::TypedValue( + query::VertexAccessor(VertexAccessor(vertices[5], *dba_ptr)))}}); filter_expr = NEQ(PROPERTY_LOOKUP(inner_node, PROPERTY_PAIR("id")), PARAMETER_LOOKUP(0)); context.evaluation_context.parameters.Add(0, PropertyValue(5)); @@ -399,9 +409,9 @@ void BfsTest(Database *db, int lower_bound, int upper_bound, filter_expr}); context.evaluation_context.properties = - query::NamesToProperties(storage.properties_, &dba); + query::NamesToProperties(storage.properties_, &execution_dba); context.evaluation_context.labels = - query::NamesToLabels(storage.labels_, &dba); + query::NamesToLabels(storage.labels_, &execution_dba); std::vector<std::vector<query::TypedValue>> results; // An exception should be thrown on one of the pulls. diff --git a/tests/unit/bfs_single_node.cpp b/tests/unit/bfs_single_node.cpp index 3b9a13b5c..e0cff0e26 100644 --- a/tests/unit/bfs_single_node.cpp +++ b/tests/unit/bfs_single_node.cpp @@ -48,8 +48,8 @@ class SingleNodeDb : public Database { int u, v; std::string type; std::tie(u, v, type) = e; - VertexAccessor from(vertex_addr[u], *dba); - VertexAccessor to(vertex_addr[v], *dba); + ::VertexAccessor from(vertex_addr[u], *dba); + ::VertexAccessor to(vertex_addr[v], *dba); auto edge = dba->InsertEdge(from, to, dba->EdgeType(type)); edge.PropsSet(dba->Property("from"), PropertyValue(u)); edge.PropsSet(dba->Property("to"), PropertyValue(v)); diff --git a/tests/unit/bolt_encoder.cpp b/tests/unit/bolt_encoder.cpp index 4870708bf..d6d708958 100644 --- a/tests/unit/bolt_encoder.cpp +++ b/tests/unit/bolt_encoder.cpp @@ -189,9 +189,12 @@ TEST(BoltEncoder, VertexAndEdge) { // check everything std::vector<Value> vals; - vals.push_back(glue::ToBoltValue(query::TypedValue(va1), storage::View::NEW)); - vals.push_back(glue::ToBoltValue(query::TypedValue(va2), storage::View::NEW)); - vals.push_back(glue::ToBoltValue(query::TypedValue(ea), storage::View::NEW)); + vals.push_back(glue::ToBoltValue( + query::TypedValue(query::VertexAccessor(va1)), storage::View::NEW)); + vals.push_back(glue::ToBoltValue( + query::TypedValue(query::VertexAccessor(va2)), storage::View::NEW)); + vals.push_back(glue::ToBoltValue(query::TypedValue(query::EdgeAccessor(ea)), + storage::View::NEW)); bolt_encoder.MessageRecord(vals); // The vertexedge_encoded testdata has hardcoded zeros for IDs, diff --git a/tests/unit/database_dump.cpp b/tests/unit/database_dump.cpp index 50f3add6f..13dbf7553 100644 --- a/tests/unit/database_dump.cpp +++ b/tests/unit/database_dump.cpp @@ -184,7 +184,8 @@ class DatabaseEnvironment { void Execute(GraphDbAccessor *dba, const std::string &query) { CHECK(dba); ResultStreamFaker<query::TypedValue> results; - query::Interpreter()(query, *dba, {}, false, utils::NewDeleteResource()) + query::DbAccessor query_dba(dba); + query::Interpreter()(query, &query_dba, {}, false, utils::NewDeleteResource()) .PullAll(results); } @@ -227,7 +228,8 @@ EdgeAccessor CreateEdge(GraphDbAccessor *dba, VertexAccessor from, TEST(DumpTest, EmptyGraph) { DatabaseEnvironment db; auto dba = db.Access(); - CypherDumpGenerator dump(&dba); + query::DbAccessor query_dba(&dba); + CypherDumpGenerator dump(&query_dba); EXPECT_EQ(DumpNext(&dump), ""); } @@ -242,7 +244,8 @@ TEST(DumpTest, SingleVertex) { { auto dba = db.Access(); - CypherDumpGenerator dump(&dba); + query::DbAccessor query_dba(&dba); + CypherDumpGenerator dump(&query_dba); EXPECT_EQ(DumpNext(&dump), kCreateInternalIndex); EXPECT_EQ(DumpNext(&dump), "CREATE (:__mg_vertex__ {__mg_id__: 0});"); EXPECT_EQ(DumpNext(&dump), kDropInternalIndex); @@ -262,7 +265,8 @@ TEST(DumpTest, VertexWithSingleLabel) { { auto dba = db.Access(); - CypherDumpGenerator dump(&dba); + query::DbAccessor query_dba(&dba); + CypherDumpGenerator dump(&query_dba); EXPECT_EQ(DumpNext(&dump), kCreateInternalIndex); EXPECT_EQ(DumpNext(&dump), "CREATE (:__mg_vertex__:Label1 {__mg_id__: 0});"); @@ -283,7 +287,8 @@ TEST(DumpTest, VertexWithMultipleLabels) { { auto dba = db.Access(); - CypherDumpGenerator dump(&dba); + query::DbAccessor query_dba(&dba); + CypherDumpGenerator dump(&query_dba); EXPECT_EQ(DumpNext(&dump), kCreateInternalIndex); EXPECT_EQ(DumpNext(&dump), "CREATE (:__mg_vertex__:Label1:Label2 {__mg_id__: 0});"); @@ -304,7 +309,8 @@ TEST(DumpTest, VertexWithSingleProperty) { { auto dba = db.Access(); - CypherDumpGenerator dump(&dba); + query::DbAccessor query_dba(&dba); + CypherDumpGenerator dump(&query_dba); EXPECT_EQ(DumpNext(&dump), kCreateInternalIndex); EXPECT_EQ(DumpNext(&dump), "CREATE (:__mg_vertex__ {__mg_id__: 0, prop: 42});"); @@ -327,7 +333,8 @@ TEST(DumpTest, MultipleVertices) { { auto dba = db.Access(); - CypherDumpGenerator dump(&dba); + query::DbAccessor query_dba(&dba); + CypherDumpGenerator dump(&query_dba); EXPECT_EQ(DumpNext(&dump), kCreateInternalIndex); EXPECT_EQ(DumpNext(&dump), "CREATE (:__mg_vertex__ {__mg_id__: 0});"); EXPECT_EQ(DumpNext(&dump), "CREATE (:__mg_vertex__ {__mg_id__: 1});"); @@ -351,7 +358,8 @@ TEST(DumpTest, SingleEdge) { { auto dba = db.Access(); - CypherDumpGenerator dump(&dba); + query::DbAccessor query_dba(&dba); + CypherDumpGenerator dump(&query_dba); EXPECT_EQ(DumpNext(&dump), kCreateInternalIndex); EXPECT_EQ(DumpNext(&dump), "CREATE (:__mg_vertex__ {__mg_id__: 0});"); EXPECT_EQ(DumpNext(&dump), "CREATE (:__mg_vertex__ {__mg_id__: 1});"); @@ -380,7 +388,8 @@ TEST(DumpTest, MultipleEdges) { { auto dba = db.Access(); - CypherDumpGenerator dump(&dba); + query::DbAccessor query_dba(&dba); + CypherDumpGenerator dump(&query_dba); EXPECT_EQ(DumpNext(&dump), kCreateInternalIndex); EXPECT_EQ(DumpNext(&dump), "CREATE (:__mg_vertex__ {__mg_id__: 0});"); EXPECT_EQ(DumpNext(&dump), "CREATE (:__mg_vertex__ {__mg_id__: 1});"); @@ -413,7 +422,8 @@ TEST(DumpTest, EdgeWithProperties) { { auto dba = db.Access(); - CypherDumpGenerator dump(&dba); + query::DbAccessor query_dba(&dba); + CypherDumpGenerator dump(&query_dba); EXPECT_EQ(DumpNext(&dump), kCreateInternalIndex); EXPECT_EQ(DumpNext(&dump), "CREATE (:__mg_vertex__ {__mg_id__: 0});"); EXPECT_EQ(DumpNext(&dump), "CREATE (:__mg_vertex__ {__mg_id__: 1});"); @@ -439,7 +449,8 @@ TEST(DumpTest, IndicesKeys) { { auto dba = db.Access(); - CypherDumpGenerator dump(&dba); + query::DbAccessor query_dba(&dba); + CypherDumpGenerator dump(&query_dba); EXPECT_EQ(DumpNext(&dump), "CREATE INDEX ON :Label1(prop);"); EXPECT_EQ(DumpNext(&dump), "CREATE INDEX ON :Label2(prop);"); EXPECT_EQ(DumpNext(&dump), kCreateInternalIndex); @@ -467,7 +478,8 @@ TEST(DumpTest, UniqueConstraints) { { auto dba = db.Access(); - CypherDumpGenerator dump(&dba); + query::DbAccessor query_dba(&dba); + CypherDumpGenerator dump(&query_dba); EXPECT_EQ(DumpNext(&dump), kCreateInternalIndex); EXPECT_EQ(DumpNext(&dump), "CREATE CONSTRAINT ON (u:Label) ASSERT u.prop IS UNIQUE;"); @@ -498,7 +510,8 @@ TEST(DumpTest, CheckStateVertexWithMultipleProperties) { DatabaseEnvironment db_dump; { auto dba = db.Access(); - CypherDumpGenerator dump(&dba); + query::DbAccessor query_dba(&dba); + CypherDumpGenerator dump(&query_dba); std::string cmd; while (!(cmd = DumpNext(&dump)).empty()) { auto dba_dump = db_dump.Access(); @@ -540,7 +553,8 @@ TEST(DumpTest, CheckStateSimpleGraph) { DatabaseEnvironment db_dump; { auto dba = db.Access(); - CypherDumpGenerator dump(&dba); + query::DbAccessor query_dba(&dba); + CypherDumpGenerator dump(&query_dba); std::string cmd; while (!(cmd = DumpNext(&dump)).empty()) { auto dba_dump = db_dump.Access(); @@ -564,11 +578,11 @@ TEST(DumpTest, ExecuteDumpDatabase) { { auto dba = db.Access(); + query::DbAccessor query_dba(&dba); const std::string query = "DUMP DATABASE"; ResultStreamFaker<query::TypedValue> stream; - auto results = - query::Interpreter()(query, dba, {}, false, utils::NewDeleteResource()); - + auto results = query::Interpreter()(query, &query_dba, {}, false, + utils::NewDeleteResource()); stream.Header(results.header()); results.PullAll(stream); stream.Summary(results.summary()); diff --git a/tests/unit/database_transaction_timeout.cpp b/tests/unit/database_transaction_timeout.cpp index f824f0ff9..8c2f23ea8 100644 --- a/tests/unit/database_transaction_timeout.cpp +++ b/tests/unit/database_transaction_timeout.cpp @@ -12,8 +12,9 @@ TEST(TransactionTimeout, TransactionTimeout) { database::GraphDb db; query::Interpreter interpreter; auto interpret = [&](auto &dba, const std::string &query) { + query::DbAccessor query_dba(&dba); ResultStreamFaker<query::TypedValue> stream; - interpreter(query, dba, {}, false, utils::NewDeleteResource()) + interpreter(query, &query_dba, {}, false, utils::NewDeleteResource()) .PullAll(stream); }; { @@ -23,8 +24,7 @@ TEST(TransactionTimeout, TransactionTimeout) { { auto dba = db.Access(); std::this_thread::sleep_for(std::chrono::seconds(5)); - ASSERT_THROW(interpret(dba, "MATCH (n) RETURN n"), - query::HintedAbortError); + ASSERT_THROW(interpret(dba, "MATCH (n) RETURN n"), query::HintedAbortError); } { auto dba = db.Access(); diff --git a/tests/unit/interpreter.cpp b/tests/unit/interpreter.cpp index d1da8f035..2d51c3406 100644 --- a/tests/unit/interpreter.cpp +++ b/tests/unit/interpreter.cpp @@ -20,9 +20,10 @@ class InterpreterTest : public ::testing::Test { auto Interpret(const std::string &query, const std::map<std::string, PropertyValue> ¶ms = {}) { auto dba = db_.Access(); + query::DbAccessor query_dba(&dba); ResultStreamFaker<query::TypedValue> stream; - auto results = - interpreter_(query, dba, params, false, utils::NewDeleteResource()); + auto results = interpreter_(query, &query_dba, params, false, + utils::NewDeleteResource()); stream.Header(results.header()); results.PullAll(stream); stream.Summary(results.summary()); @@ -207,11 +208,12 @@ TEST_F(InterpreterTest, Bfs) { } auto dba = db_.Access(); + query::DbAccessor query_dba(&dba); ResultStreamFaker<query::TypedValue> stream; auto results = interpreter_( "MATCH (n {id: 0})-[r *bfs..5 (e, n | n.reachable and " "e.reachable)]->(m) RETURN r", - dba, {}, false, utils::NewDeleteResource()); + &query_dba, {}, false, utils::NewDeleteResource()); stream.Header(results.header()); results.PullAll(stream); stream.Summary(results.summary()); @@ -231,14 +233,14 @@ TEST_F(InterpreterTest, Bfs) { EXPECT_EQ(edges.size(), expected_level); // Check that starting node is correct. EXPECT_EQ( - edges[0].from().PropsAt(dba.Property(kId)).ValueInt(), + edges[0].impl_.from().PropsAt(dba.Property(kId)).ValueInt(), 0); for (int i = 1; i < static_cast<int>(edges.size()); ++i) { // Check that edges form a connected path. - EXPECT_EQ(edges[i - 1].to(), edges[i].from()); + EXPECT_EQ(edges[i - 1].To(), edges[i].From()); } auto matched_id = - edges.back().to().PropsAt(dba.Property(kId)).ValueInt(); + edges.back().impl_.to().PropsAt(dba.Property(kId)).ValueInt(); // Check that we didn't match that node already. EXPECT_TRUE(matched_ids.insert(matched_id).second); // Check that shortest path was found. @@ -254,7 +256,8 @@ TEST_F(InterpreterTest, Bfs) { TEST_F(InterpreterTest, CreateIndexInMulticommandTransaction) { ResultStreamFaker<query::TypedValue> stream; auto dba = db_.Access(); - ASSERT_THROW(interpreter_("CREATE INDEX ON :X(y)", dba, {}, true, + query::DbAccessor query_dba(&dba); + ASSERT_THROW(interpreter_("CREATE INDEX ON :X(y)", &query_dba, {}, true, utils::NewDeleteResource()) .PullAll(stream), query::IndexInMulticommandTxException); @@ -265,10 +268,11 @@ TEST_F(InterpreterTest, ShortestPath) { { ResultStreamFaker<query::TypedValue> stream; auto dba = db_.Access(); + query::DbAccessor query_dba(&dba); interpreter_( "CREATE (n:A {x: 1}), (m:B {x: 2}), (l:C {x: 1}), (n)-[:r1 {w: 1 " "}]->(m)-[:r2 {w: 2}]->(l), (n)-[:r3 {w: 4}]->(l)", - dba, {}, true, utils::NewDeleteResource()) + &query_dba, {}, true, utils::NewDeleteResource()) .PullAll(stream); dba.Commit(); @@ -276,9 +280,10 @@ TEST_F(InterpreterTest, ShortestPath) { ResultStreamFaker<query::TypedValue> stream; auto dba = db_.Access(); + query::DbAccessor query_dba(&dba); auto results = interpreter_("MATCH (n)-[e *wshortest 5 (e, n | e.w) ]->(m) return e", - dba, {}, false, utils::NewDeleteResource()); + &query_dba, {}, false, utils::NewDeleteResource()); stream.Header(results.header()); results.PullAll(stream); stream.Summary(results.summary()); @@ -315,15 +320,17 @@ TEST_F(InterpreterTest, UniqueConstraintTest) { ResultStreamFaker<query::TypedValue> stream; { auto dba = db_.Access(); - interpreter_("CREATE CONSTRAINT ON (n:A) ASSERT n.a, n.b IS UNIQUE;", dba, - {}, true, utils::NewDeleteResource()) + query::DbAccessor query_dba(&dba); + interpreter_("CREATE CONSTRAINT ON (n:A) ASSERT n.a, n.b IS UNIQUE;", + &query_dba, {}, true, utils::NewDeleteResource()) .PullAll(stream); dba.Commit(); } { auto dba = db_.Access(); - interpreter_("CREATE (:A{a:1, b:1})", dba, {}, true, + query::DbAccessor query_dba(&dba); + interpreter_("CREATE (:A{a:1, b:1})", &query_dba, {}, true, utils::NewDeleteResource()) .PullAll(stream); dba.Commit(); @@ -331,7 +338,8 @@ TEST_F(InterpreterTest, UniqueConstraintTest) { { auto dba = db_.Access(); - interpreter_("CREATE (:A{a:2, b:2})", dba, {}, true, + query::DbAccessor query_dba(&dba); + interpreter_("CREATE (:A{a:2, b:2})", &query_dba, {}, true, utils::NewDeleteResource()) .PullAll(stream); dba.Commit(); @@ -339,7 +347,8 @@ TEST_F(InterpreterTest, UniqueConstraintTest) { { auto dba = db_.Access(); - ASSERT_THROW(interpreter_("CREATE (:A{a:1, b:1})", dba, {}, true, + query::DbAccessor query_dba(&dba); + ASSERT_THROW(interpreter_("CREATE (:A{a:1, b:1})", &query_dba, {}, true, utils::NewDeleteResource()) .PullAll(stream), query::QueryRuntimeException); @@ -348,10 +357,11 @@ TEST_F(InterpreterTest, UniqueConstraintTest) { { auto dba = db_.Access(); - interpreter_("MATCH (n:A{a:2, b:2}) SET n.a=1", dba, {}, true, + query::DbAccessor query_dba(&dba); + interpreter_("MATCH (n:A{a:2, b:2}) SET n.a=1", &query_dba, {}, true, utils::NewDeleteResource()) .PullAll(stream); - interpreter_("CREATE (:A{a:2, b:2})", dba, {}, true, + interpreter_("CREATE (:A{a:2, b:2})", &query_dba, {}, true, utils::NewDeleteResource()) .PullAll(stream); dba.Commit(); @@ -359,10 +369,11 @@ TEST_F(InterpreterTest, UniqueConstraintTest) { { auto dba = db_.Access(); - interpreter_("MATCH (n:A{a:2, b:2}) DETACH DELETE n", dba, {}, true, + query::DbAccessor query_dba(&dba); + interpreter_("MATCH (n:A{a:2, b:2}) DETACH DELETE n", &query_dba, {}, true, utils::NewDeleteResource()) .PullAll(stream); - interpreter_("CREATE (n:A{a:2, b:2})", dba, {}, true, + interpreter_("CREATE (n:A{a:2, b:2})", &query_dba, {}, true, utils::NewDeleteResource()) .PullAll(stream); dba.Commit(); diff --git a/tests/unit/plan_pretty_print.cpp b/tests/unit/plan_pretty_print.cpp index 989c0cb83..ee0a8972b 100644 --- a/tests/unit/plan_pretty_print.cpp +++ b/tests/unit/plan_pretty_print.cpp @@ -39,7 +39,8 @@ class PrintToJsonTest : public ::testing::Test { } void Check(LogicalOperator *root, std::string expected) { - EXPECT_EQ(PlanToJson(dba, root), json::parse(expected)); + query::DbAccessor query_dba(&dba); + EXPECT_EQ(PlanToJson(query_dba, root), json::parse(expected)); } }; diff --git a/tests/unit/query_expression_evaluator.cpp b/tests/unit/query_expression_evaluator.cpp index 4c9faddb9..ad615be29 100644 --- a/tests/unit/query_expression_evaluator.cpp +++ b/tests/unit/query_expression_evaluator.cpp @@ -38,7 +38,9 @@ class ExpressionEvaluatorTest : public ::testing::Test { SymbolTable symbol_table; Frame frame{128}; - ExpressionEvaluator eval{&frame, symbol_table, ctx, &dba, storage::View::OLD}; + query::DbAccessor execution_dba{&dba}; + ExpressionEvaluator eval{&frame, symbol_table, ctx, &execution_dba, + storage::View::OLD}; Identifier *CreateIdentifierWithValue(std::string name, const TypedValue &value) { @@ -51,8 +53,8 @@ class ExpressionEvaluatorTest : public ::testing::Test { template <class TExpression> auto Eval(TExpression *expr) { - ctx.properties = NamesToProperties(storage.properties_, &dba); - ctx.labels = NamesToLabels(storage.labels_, &dba); + ctx.properties = NamesToProperties(storage.properties_, &execution_dba); + ctx.labels = NamesToLabels(storage.labels_, &execution_dba); auto value = expr->Accept(eval); EXPECT_EQ(value.GetMemoryResource(), &mem) << "ExpressionEvaluator must use the MemoryResource from " @@ -421,8 +423,10 @@ TEST_F(ExpressionEvaluatorTest, VertexAndEdgeIndexing) { v1.PropsSet(prop, PropertyValue(42)); e11.PropsSet(prop, PropertyValue(43)); - auto *vertex_id = CreateIdentifierWithValue("v1", TypedValue(v1)); - auto *edge_id = CreateIdentifierWithValue("e11", TypedValue(e11)); + auto *vertex_id = + CreateIdentifierWithValue("v1", TypedValue(query::VertexAccessor(v1))); + auto *edge_id = + CreateIdentifierWithValue("e11", TypedValue(query::EdgeAccessor(e11))); { // Legal indexing. auto *op1 = storage.Create<SubscriptOperator>( @@ -635,7 +639,7 @@ TEST_F(ExpressionEvaluatorTest, LabelsTest) { auto *identifier = storage.Create<Identifier>("n"); auto node_symbol = symbol_table.CreateSymbol("n", true); identifier->MapTo(node_symbol); - frame[node_symbol] = TypedValue(v1); + frame[node_symbol] = TypedValue(query::VertexAccessor(v1)); { auto *op = storage.Create<LabelsTest>( identifier, std::vector<LabelIx>{storage.GetLabelIx("DOG"), @@ -915,7 +919,7 @@ class ExpressionEvaluatorPropertyLookup : public ExpressionEvaluatorTest { TEST_F(ExpressionEvaluatorPropertyLookup, Vertex) { auto v1 = dba.InsertVertex(); v1.PropsSet(prop_age.second, PropertyValue(10)); - frame[symbol] = TypedValue(v1); + frame[symbol] = TypedValue(query::VertexAccessor(v1)); EXPECT_EQ(Value(prop_age).ValueInt(), 10); EXPECT_TRUE(Value(prop_height).IsNull()); } @@ -925,7 +929,7 @@ TEST_F(ExpressionEvaluatorPropertyLookup, Edge) { auto v2 = dba.InsertVertex(); auto e12 = dba.InsertEdge(v1, v2, dba.EdgeType("edge_type")); e12.PropsSet(prop_age.second, PropertyValue(10)); - frame[symbol] = TypedValue(e12); + frame[symbol] = TypedValue(query::EdgeAccessor(e12)); EXPECT_EQ(Value(prop_age).ValueInt(), 10); EXPECT_TRUE(Value(prop_height).IsNull()); } @@ -999,10 +1003,10 @@ TEST_F(FunctionTest, EndNode) { v1.add_label(dba.Label("label1")); auto v2 = dba.InsertVertex(); v2.add_label(dba.Label("label2")); - auto e = dba.InsertEdge(v1, v2, dba.EdgeType("t")); - ASSERT_TRUE(EvaluateFunction("ENDNODE", e) - .ValueVertex() - .has_label(dba.Label("label2"))); + query::EdgeAccessor e(dba.InsertEdge(v1, v2, dba.EdgeType("t"))); + ASSERT_TRUE(*EvaluateFunction("ENDNODE", e) + .ValueVertex() + .HasLabel(storage::View::NEW, dba.Label("label2"))); ASSERT_THROW(EvaluateFunction("ENDNODE", 2), QueryRuntimeException); } @@ -1035,10 +1039,12 @@ TEST_F(FunctionTest, Properties) { return properties; }; - ASSERT_THAT(prop_values_to_int(EvaluateFunction("PROPERTIES", v1)), + ASSERT_THAT(prop_values_to_int( + EvaluateFunction("PROPERTIES", query::VertexAccessor(v1))), UnorderedElementsAre(testing::Pair("height", 5), testing::Pair("age", 10))); - ASSERT_THAT(prop_values_to_int(EvaluateFunction("PROPERTIES", e)), + ASSERT_THAT(prop_values_to_int( + EvaluateFunction("PROPERTIES", query::EdgeAccessor(e))), UnorderedElementsAre(testing::Pair("height", 3), testing::Pair("age", 15))); ASSERT_THROW(EvaluateFunction("PROPERTIES", 2), QueryRuntimeException); @@ -1069,11 +1075,12 @@ TEST_F(FunctionTest, Size) { 3); ASSERT_THROW(EvaluateFunction("SIZE", 5), QueryRuntimeException); - auto v0 = dba.InsertVertex(); + query::VertexAccessor v0(dba.InsertVertex()); query::Path path(v0); EXPECT_EQ(EvaluateFunction("SIZE", path).ValueInt(), 0); - auto v1 = dba.InsertVertex(); - path.Expand(dba.InsertEdge(v0, v1, dba.EdgeType("type"))); + query::VertexAccessor v1(dba.InsertVertex()); + path.Expand(query::EdgeAccessor( + dba.InsertEdge(v0.impl_, v1.impl_, dba.EdgeType("type")))); path.Expand(v1); EXPECT_EQ(EvaluateFunction("SIZE", path).ValueInt(), 1); } @@ -1086,9 +1093,9 @@ TEST_F(FunctionTest, StartNode) { auto v2 = dba.InsertVertex(); v2.add_label(dba.Label("label2")); auto e = dba.InsertEdge(v1, v2, dba.EdgeType("t")); - ASSERT_TRUE(EvaluateFunction("STARTNODE", e) - .ValueVertex() - .has_label(dba.Label("label1"))); + ASSERT_TRUE(*EvaluateFunction("STARTNODE", query::EdgeAccessor(e)) + .ValueVertex() + .HasLabel(storage::View::NEW, dba.Label("label1"))); ASSERT_THROW(EvaluateFunction("STARTNODE", 2), QueryRuntimeException); } @@ -1100,21 +1107,25 @@ TEST_F(FunctionTest, Degree) { auto v3 = dba.InsertVertex(); auto e12 = dba.InsertEdge(v1, v2, dba.EdgeType("t")); dba.InsertEdge(v3, v2, dba.EdgeType("t")); - ASSERT_EQ(EvaluateFunction("DEGREE", v1).ValueInt(), 1); - ASSERT_EQ(EvaluateFunction("DEGREE", v2).ValueInt(), 2); - ASSERT_EQ(EvaluateFunction("DEGREE", v3).ValueInt(), 1); + ASSERT_EQ(EvaluateFunction("DEGREE", query::VertexAccessor(v1)).ValueInt(), + 1); + ASSERT_EQ(EvaluateFunction("DEGREE", query::VertexAccessor(v2)).ValueInt(), + 2); + ASSERT_EQ(EvaluateFunction("DEGREE", query::VertexAccessor(v3)).ValueInt(), + 1); ASSERT_THROW(EvaluateFunction("DEGREE", 2), QueryRuntimeException); - ASSERT_THROW(EvaluateFunction("DEGREE", e12), QueryRuntimeException); + ASSERT_THROW(EvaluateFunction("DEGREE", query::EdgeAccessor(e12)), + QueryRuntimeException); } TEST_F(FunctionTest, InDegree) { ASSERT_THROW(EvaluateFunction("INDEGREE"), QueryRuntimeException); ASSERT_TRUE(EvaluateFunction("INDEGREE", TypedValue()).IsNull()); - auto v1 = dba.InsertVertex(); - auto v2 = dba.InsertVertex(); - auto v3 = dba.InsertVertex(); - auto e12 = dba.InsertEdge(v1, v2, dba.EdgeType("t")); - dba.InsertEdge(v3, v2, dba.EdgeType("t")); + query::VertexAccessor v1(dba.InsertVertex()); + query::VertexAccessor v2(dba.InsertVertex()); + query::VertexAccessor v3(dba.InsertVertex()); + query::EdgeAccessor e12(dba.InsertEdge(v1.impl_, v2.impl_, dba.EdgeType("t"))); + dba.InsertEdge(v3.impl_, v2.impl_, dba.EdgeType("t")); ASSERT_EQ(EvaluateFunction("INDEGREE", v1).ValueInt(), 0); ASSERT_EQ(EvaluateFunction("INDEGREE", v2).ValueInt(), 2); ASSERT_EQ(EvaluateFunction("INDEGREE", v3).ValueInt(), 0); @@ -1125,11 +1136,12 @@ TEST_F(FunctionTest, InDegree) { TEST_F(FunctionTest, OutDegree) { ASSERT_THROW(EvaluateFunction("OUTDEGREE"), QueryRuntimeException); ASSERT_TRUE(EvaluateFunction("OUTDEGREE", TypedValue()).IsNull()); - auto v1 = dba.InsertVertex(); - auto v2 = dba.InsertVertex(); - auto v3 = dba.InsertVertex(); - auto e12 = dba.InsertEdge(v1, v2, dba.EdgeType("t")); - dba.InsertEdge(v3, v2, dba.EdgeType("t")); + query::VertexAccessor v1(dba.InsertVertex()); + query::VertexAccessor v2(dba.InsertVertex()); + query::VertexAccessor v3(dba.InsertVertex()); + query::EdgeAccessor e12( + dba.InsertEdge(v1.impl_, v2.impl_, dba.EdgeType("t"))); + dba.InsertEdge(v3.impl_, v2.impl_, dba.EdgeType("t")); ASSERT_EQ(EvaluateFunction("OUTDEGREE", v1).ValueInt(), 1); ASSERT_EQ(EvaluateFunction("OUTDEGREE", v2).ValueInt(), 0); ASSERT_EQ(EvaluateFunction("OUTDEGREE", v3).ValueInt(), 1); @@ -1180,7 +1192,7 @@ TEST_F(FunctionTest, Type) { v1.add_label(dba.Label("label1")); auto v2 = dba.InsertVertex(); v2.add_label(dba.Label("label2")); - auto e = dba.InsertEdge(v1, v2, dba.EdgeType("type1")); + query::EdgeAccessor e(dba.InsertEdge(v1, v2, dba.EdgeType("type1"))); ASSERT_EQ(EvaluateFunction("TYPE", e).ValueString(), "type1"); ASSERT_THROW(EvaluateFunction("TYPE", 2), QueryRuntimeException); } @@ -1192,7 +1204,8 @@ TEST_F(FunctionTest, Labels) { v.add_label(dba.Label("label1")); v.add_label(dba.Label("label2")); std::vector<std::string> labels; - auto _labels = EvaluateFunction("LABELS", v).ValueList(); + auto _labels = + EvaluateFunction("LABELS", query::VertexAccessor(v)).ValueList(); labels.reserve(_labels.size()); for (auto label : _labels) { labels.emplace_back(label.ValueString()); @@ -1213,19 +1226,21 @@ TEST_F(FunctionTest, NodesRelationships) { auto v3 = dba.InsertVertex(); auto e1 = dba.InsertEdge(v1, v2, dba.EdgeType("Type")); auto e2 = dba.InsertEdge(v2, v3, dba.EdgeType("Type")); - query::Path path(v1, e1, v2, e2, v3); + query::Path path{query::VertexAccessor(v1), query::EdgeAccessor(e1), + query::VertexAccessor(v2), query::EdgeAccessor(e2), + query::VertexAccessor(v3)}; auto _nodes = EvaluateFunction("NODES", path).ValueList(); - std::vector<VertexAccessor> nodes; + std::vector<::VertexAccessor> nodes; for (const auto &node : _nodes) { - nodes.push_back(node.ValueVertex()); + nodes.push_back(node.ValueVertex().impl_); } EXPECT_THAT(nodes, ElementsAre(v1, v2, v3)); auto _edges = EvaluateFunction("RELATIONSHIPS", path).ValueList(); - std::vector<EdgeAccessor> edges; + std::vector<::EdgeAccessor> edges; for (const auto &edge : _edges) { - edges.push_back(edge.ValueEdge()); + edges.push_back(edge.ValueEdge().impl_); } EXPECT_THAT(edges, ElementsAre(e1, e2)); } @@ -1273,10 +1288,12 @@ TEST_F(FunctionTest, Keys) { } return keys; }; - ASSERT_THAT(prop_keys_to_string(EvaluateFunction("KEYS", v1)), - UnorderedElementsAre("height", "age")); - ASSERT_THAT(prop_keys_to_string(EvaluateFunction("KEYS", e)), - UnorderedElementsAre("width", "age")); + ASSERT_THAT( + prop_keys_to_string(EvaluateFunction("KEYS", query::VertexAccessor(v1))), + UnorderedElementsAre("height", "age")); + ASSERT_THAT( + prop_keys_to_string(EvaluateFunction("KEYS", query::EdgeAccessor(e))), + UnorderedElementsAre("width", "age")); ASSERT_THROW(EvaluateFunction("KEYS", 2), QueryRuntimeException); } @@ -1494,9 +1511,10 @@ TEST_F(FunctionTest, Counter) { } TEST_F(FunctionTest, Id) { - auto va = dba.InsertVertex(); - auto ea = dba.InsertEdge(va, va, dba.EdgeType("edge")); - auto vb = dba.InsertVertex(); + query::VertexAccessor va(dba.InsertVertex()); + query::EdgeAccessor ea( + dba.InsertEdge(va.impl_, va.impl_, dba.EdgeType("edge"))); + query::VertexAccessor vb(dba.InsertVertex()); EXPECT_EQ(EvaluateFunction("ID", va).ValueInt(), 0); EXPECT_EQ(EvaluateFunction("ID", ea).ValueInt(), 0); EXPECT_EQ(EvaluateFunction("ID", vb).ValueInt(), 1); diff --git a/tests/unit/query_plan_accumulate_aggregate.cpp b/tests/unit/query_plan_accumulate_aggregate.cpp index 09803e3b9..13a678a76 100644 --- a/tests/unit/query_plan_accumulate_aggregate.cpp +++ b/tests/unit/query_plan_accumulate_aggregate.cpp @@ -65,7 +65,8 @@ TEST(QueryPlan, Accumulate) { auto m_p_ne = NEXPR("m.p", m_p)->MapTo(symbol_table.CreateSymbol("m_p_ne", true)); auto produce = MakeProduce(last_op, n_p_ne, m_p_ne); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); std::vector<int> results_data; for (const auto &row : results) @@ -95,7 +96,8 @@ TEST(QueryPlan, AccumulateAdvance) { auto accumulate = std::make_shared<Accumulate>( create, std::vector<Symbol>{node.symbol}, advance); auto match = MakeScanAll(storage, symbol_table, "m", accumulate); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(advance ? 1 : 0, PullAll(*match.op_, &context)); }; check(false); @@ -182,7 +184,8 @@ class QueryPlanAggregateOps : public ::testing::Test { auto produce = MakeAggregationProduce(n.op_, symbol_table, storage, aggregation_expressions, ops, group_bys, {}); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); return CollectProduce(*produce, &context); } }; @@ -327,7 +330,8 @@ TEST(QueryPlan, AggregateGroupByValues) { MakeAggregationProduce(n.op_, symbol_table, storage, {n_p}, {Aggregation::Op::COUNT}, {n_p}, {n.sym_}); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); ASSERT_EQ(results.size(), group_by_vals.size() - 2); std::unordered_set<TypedValue, TypedValue::Hash, TypedValue::BoolEqual> @@ -376,7 +380,8 @@ TEST(QueryPlan, AggregateMultipleGroupBy) { {Aggregation::Op::COUNT}, {n_p1, n_p2, n_p3}, {n.sym_}); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); EXPECT_EQ(results.size(), 2 * 3 * 5); } @@ -390,7 +395,8 @@ TEST(QueryPlan, AggregateNoInput) { auto two = LITERAL(2); auto produce = MakeAggregationProduce(nullptr, symbol_table, storage, {two}, {Aggregation::Op::COUNT}, {}, {}); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); EXPECT_EQ(1, results.size()); EXPECT_EQ(1, results[0].size()); @@ -422,7 +428,8 @@ TEST(QueryPlan, AggregateCountEdgeCases) { auto count = [&]() { auto produce = MakeAggregationProduce(n.op_, symbol_table, storage, {n_p}, {Aggregation::Op::COUNT}, {}, {}); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); if (results.size() == 0) return -1L; EXPECT_EQ(1, results.size()); @@ -440,8 +447,7 @@ TEST(QueryPlan, AggregateCountEdgeCases) { EXPECT_EQ(0, count()); // one vertex, property set - for (VertexAccessor va : dba.Vertices(false)) - va.PropsSet(prop, PropertyValue(42)); + for (auto va : dba.Vertices(false)) va.PropsSet(prop, PropertyValue(42)); dba.AdvanceCommand(); EXPECT_EQ(1, count()); @@ -451,8 +457,7 @@ TEST(QueryPlan, AggregateCountEdgeCases) { EXPECT_EQ(1, count()); // two vertices, both with property set - for (VertexAccessor va : dba.Vertices(false)) - va.PropsSet(prop, PropertyValue(42)); + for (auto va : dba.Vertices(false)) va.PropsSet(prop, PropertyValue(42)); dba.AdvanceCommand(); EXPECT_EQ(2, count()); } @@ -482,7 +487,8 @@ TEST(QueryPlan, AggregateFirstValueTypes) { auto aggregate = [&](Expression *expression, Aggregation::Op aggr_op) { auto produce = MakeAggregationProduce(n.op_, symbol_table, storage, {expression}, {aggr_op}, {}, {}); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); CollectProduce(*produce, &context); }; @@ -538,7 +544,8 @@ TEST(QueryPlan, AggregateTypes) { auto aggregate = [&](Expression *expression, Aggregation::Op aggr_op) { auto produce = MakeAggregationProduce(n.op_, symbol_table, storage, {expression}, {aggr_op}, {}, {}); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); CollectProduce(*produce, &context); }; @@ -596,7 +603,8 @@ TEST(QueryPlan, Unwind) { ->MapTo(symbol_table.CreateSymbol("y_ne", true)); auto produce = MakeProduce(unwind_1, x_ne, y_ne); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); ASSERT_EQ(4, results.size()); const std::vector<int> expected_x_card{3, 3, 3, 1}; diff --git a/tests/unit/query_plan_bag_semantics.cpp b/tests/unit/query_plan_bag_semantics.cpp index 83eea0531..9d55905dd 100644 --- a/tests/unit/query_plan_bag_semantics.cpp +++ b/tests/unit/query_plan_bag_semantics.cpp @@ -31,7 +31,8 @@ TEST(QueryPlan, Skip) { auto n = MakeScanAll(storage, symbol_table, "n1"); auto skip = std::make_shared<plan::Skip>(n.op_, LITERAL(2)); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(0, PullAll(*skip, &context)); dba.InsertVertex(); @@ -61,7 +62,8 @@ TEST(QueryPlan, Limit) { auto n = MakeScanAll(storage, symbol_table, "n1"); auto skip = std::make_shared<plan::Limit>(n.op_, LITERAL(2)); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(0, PullAll(*skip, &context)); dba.InsertVertex(); @@ -100,7 +102,8 @@ TEST(QueryPlan, CreateLimit) { auto c = std::make_shared<CreateNode>(n.op_, m); auto skip = std::make_shared<plan::Limit>(c, LITERAL(1)); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(1, PullAll(*skip, &context)); dba.AdvanceCommand(); EXPECT_EQ(3, CountIterable(dba.Vertices(false))); @@ -171,7 +174,8 @@ TEST(QueryPlan, OrderBy) { auto n_p_ne = NEXPR("n.p", n_p)->MapTo(symbol_table.CreateSymbol("n.p", true)); auto produce = MakeProduce(order_by, n_p_ne); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); ASSERT_EQ(values.size(), results.size()); for (int j = 0; j < results.size(); ++j) @@ -223,7 +227,8 @@ TEST(QueryPlan, OrderByMultiple) { auto n_p2_ne = NEXPR("n.p2", n_p2)->MapTo(symbol_table.CreateSymbol("n.p2", true)); auto produce = MakeProduce(order_by, n_p1_ne, n_p2_ne); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); ASSERT_EQ(N * N, results.size()); for (int j = 0; j < N * N; ++j) { @@ -277,7 +282,8 @@ TEST(QueryPlan, OrderByExceptions) { auto order_by = std::make_shared<plan::OrderBy>( n.op_, std::vector<SortItem>{{Ordering::ASC, n_p}}, std::vector<Symbol>{}); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_THROW(PullAll(*order_by, &context), QueryRuntimeException); } } diff --git a/tests/unit/query_plan_checker.hpp b/tests/unit/query_plan_checker.hpp index 7977e79a6..6b4f5081d 100644 --- a/tests/unit/query_plan_checker.hpp +++ b/tests/unit/query_plan_checker.hpp @@ -392,33 +392,43 @@ class FakeDbAccessor { label_property_index_.emplace_back(label, property, count); } - storage::Label Label(const std::string &name) { + storage::Label NameToLabel(const std::string &name) { auto found = labels_.find(name); if (found != labels_.end()) return found->second; return labels_.emplace(name, storage::Label(labels_.size())).first->second; } - storage::EdgeType EdgeType(const std::string &name) { + storage::Label Label(const std::string &name) { return NameToLabel(name); } + + storage::EdgeType NameToEdgeType(const std::string &name) { auto found = edge_types_.find(name); if (found != edge_types_.end()) return found->second; return edge_types_.emplace(name, storage::EdgeType(edge_types_.size())) .first->second; } - storage::Property Property(const std::string &name) { + storage::Property NameToProperty(const std::string &name) { auto found = properties_.find(name); if (found != properties_.end()) return found->second; return properties_.emplace(name, storage::Property(properties_.size())) .first->second; } - std::string PropertyName(storage::Property property) const { + storage::Property Property(const std::string &name) { + return NameToProperty(name); + } + + std::string PropertyToName(storage::Property property) const { for (const auto &kv : properties_) { if (kv.second == property) return kv.first; } LOG(FATAL) << "Unable to find property name"; } + std::string PropertyName(storage::Property property) const { + return PropertyToName(property); + } + private: std::unordered_map<std::string, storage::Label> labels_; std::unordered_map<std::string, storage::EdgeType> edge_types_; diff --git a/tests/unit/query_plan_common.hpp b/tests/unit/query_plan_common.hpp index c3d229efb..e98bd6086 100644 --- a/tests/unit/query_plan_common.hpp +++ b/tests/unit/query_plan_common.hpp @@ -19,7 +19,7 @@ using Bound = ScanAllByLabelPropertyRange::Bound; ExecutionContext MakeContext(const AstStorage &storage, const SymbolTable &symbol_table, - database::GraphDbAccessor *dba) { + query::DbAccessor *dba) { ExecutionContext context{dba}; context.symbol_table = symbol_table; context.evaluation_context.properties = diff --git a/tests/unit/query_plan_create_set_remove_delete.cpp b/tests/unit/query_plan_create_set_remove_delete.cpp index 4a73a4c84..8fc8f2e30 100644 --- a/tests/unit/query_plan_create_set_remove_delete.cpp +++ b/tests/unit/query_plan_create_set_remove_delete.cpp @@ -32,13 +32,14 @@ TEST(QueryPlan, CreateNodeWithAttributes) { node.properties.emplace_back(property.second, LITERAL(42)); auto create = std::make_shared<CreateNode>(nullptr, node); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); PullAll(*create, &context); dba.AdvanceCommand(); // count the number of vertices int vertex_count = 0; - for (VertexAccessor vertex : dba.Vertices(false)) { + for (auto vertex : dba.Vertices(false)) { vertex_count++; EXPECT_EQ(vertex.labels().size(), 1); EXPECT_EQ(*vertex.labels().begin(), label); @@ -77,13 +78,15 @@ TEST(QueryPlan, CreateReturn) { ->MapTo(symbol_table.CreateSymbol("named_expr_n_p", true)); auto produce = MakeProduce(create, named_expr_n, named_expr_n_p); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); EXPECT_EQ(1, results.size()); EXPECT_EQ(2, results[0].size()); EXPECT_EQ(TypedValue::Type::Vertex, results[0][0].type()); - EXPECT_EQ(1, results[0][0].ValueVertex().labels().size()); - EXPECT_EQ(label, results[0][0].ValueVertex().labels()[0]); + auto maybe_labels = results[0][0].ValueVertex().Labels(storage::View::OLD); + EXPECT_EQ(1, maybe_labels->size()); + EXPECT_EQ(label, (*maybe_labels)[0]); EXPECT_EQ(TypedValue::Type::Int, results[0][1].type()); EXPECT_EQ(42, results[0][1].ValueInt()); @@ -128,7 +131,8 @@ TEST(QueryPlan, CreateExpand) { auto create_op = std::make_shared<CreateNode>(nullptr, n); auto create_expand = std::make_shared<CreateExpand>(m, r, create_op, n.symbol, cycle); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); PullAll(*create_expand, &context); dba.AdvanceCommand(); @@ -141,7 +145,7 @@ TEST(QueryPlan, CreateExpand) { test_create_path(false, 2, 1); test_create_path(true, 1, 1); - for (VertexAccessor vertex : dba.Vertices(false)) { + for (auto vertex : dba.Vertices(false)) { EXPECT_EQ(vertex.labels().size(), 1); storage::Label label = vertex.labels()[0]; if (label == label_node_1) { @@ -155,7 +159,7 @@ TEST(QueryPlan, CreateExpand) { FAIL(); } - for (EdgeAccessor edge : dba.Edges(false)) { + for (auto edge : dba.Edges(false)) { EXPECT_EQ(edge.EdgeType(), edge_type); EXPECT_EQ(edge.PropsAt(property.second).ValueInt(), 3); } @@ -184,7 +188,8 @@ TEST(QueryPlan, MatchCreateNode) { auto create_node = std::make_shared<CreateNode>(n_scan_all.op_, m); EXPECT_EQ(CountIterable(dba.Vertices(false)), 3); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); PullAll(*create_node, &context); dba.AdvanceCommand(); EXPECT_EQ(CountIterable(dba.Vertices(false)), 6); @@ -227,7 +232,8 @@ TEST(QueryPlan, MatchCreateExpand) { auto create_expand = std::make_shared<CreateExpand>(m, r, n_scan_all.op_, n_scan_all.sym_, cycle); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); PullAll(*create_expand, &context); dba.AdvanceCommand(); @@ -246,7 +252,7 @@ TEST(QueryPlan, Delete) { auto dba = db.Access(); // make a fully-connected (one-direction, no cycles) with 4 nodes - std::vector<VertexAccessor> vertices; + std::vector<::VertexAccessor> vertices; for (int i = 0; i < 4; ++i) vertices.push_back(dba.InsertVertex()); auto type = dba.EdgeType("type"); for (int j = 0; j < 4; ++j) @@ -266,7 +272,8 @@ TEST(QueryPlan, Delete) { auto n_get = storage.Create<Identifier>("n")->MapTo(n.sym_); auto delete_op = std::make_shared<plan::Delete>( n.op_, std::vector<Expression *>{n_get}, false); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_THROW(PullAll(*delete_op, &context), QueryRuntimeException); dba.AdvanceCommand(); EXPECT_EQ(4, CountIterable(dba.Vertices(false))); @@ -280,7 +287,8 @@ TEST(QueryPlan, Delete) { auto delete_op = std::make_shared<plan::Delete>( n.op_, std::vector<Expression *>{n_get}, true); Frame frame(symbol_table.max_position()); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); delete_op->MakeCursor(utils::NewDeleteResource())->Pull(frame, context); dba.AdvanceCommand(); EXPECT_EQ(3, CountIterable(dba.Vertices(false))); @@ -296,7 +304,8 @@ TEST(QueryPlan, Delete) { auto r_get = storage.Create<Identifier>("r")->MapTo(r_m.edge_sym_); auto delete_op = std::make_shared<plan::Delete>( r_m.op_, std::vector<Expression *>{r_get}, false); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); PullAll(*delete_op, &context); dba.AdvanceCommand(); EXPECT_EQ(3, CountIterable(dba.Vertices(false))); @@ -309,7 +318,8 @@ TEST(QueryPlan, Delete) { auto n_get = storage.Create<Identifier>("n")->MapTo(n.sym_); auto delete_op = std::make_shared<plan::Delete>( n.op_, std::vector<Expression *>{n_get}, false); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); PullAll(*delete_op, &context); dba.AdvanceCommand(); EXPECT_EQ(0, CountIterable(dba.Vertices(false))); @@ -355,7 +365,8 @@ TEST(QueryPlan, DeleteTwiceDeleteBlockingEdge) { auto delete_op = std::make_shared<plan::Delete>( r_m.op_, std::vector<Expression *>{n_get, r_get, m_get}, detach); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(2, PullAll(*delete_op, &context)); dba.AdvanceCommand(); EXPECT_EQ(0, CountIterable(dba.Vertices(false))); @@ -395,7 +406,8 @@ TEST(QueryPlan, DeleteReturn) { ->MapTo(symbol_table.CreateSymbol("bla", true)); auto produce = MakeProduce(delete_op, n_p); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); EXPECT_EQ(4, results.size()); dba.AdvanceCommand(); @@ -412,7 +424,8 @@ TEST(QueryPlan, DeleteNull) { auto once = std::make_shared<Once>(); auto delete_op = std::make_shared<plan::Delete>( once, std::vector<Expression *>{LITERAL(TypedValue())}, false); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(1, PullAll(*delete_op, &context)); } @@ -420,16 +433,9 @@ TEST(QueryPlan, DeleteAdvance) { // test queries on empty DB: // CREATE (n) // MATCH (n) DELETE n WITH n ... - // this fails due to us advancing the command - // when processing the WITH clause - // - // note that Neo does not fail when the deleted - // record is not used in subsequent clauses, but - // we are not yet compatible with that + // this fails only if the deleted record `n` is actually used in subsequent + // clauses, which is compatible with Neo's behavior. database::GraphDb db; - auto dba = db.Access(); - dba.InsertVertex(); - dba.AdvanceCommand(); AstStorage storage; SymbolTable symbol_table; @@ -440,8 +446,28 @@ TEST(QueryPlan, DeleteAdvance) { n.op_, std::vector<Expression *>{n_get}, false); auto advance = std::make_shared<Accumulate>( delete_op, std::vector<Symbol>{n.sym_}, true); - auto context = MakeContext(storage, symbol_table, &dba); - EXPECT_THROW(PullAll(*advance, &context), ReconstructionException); + auto res_sym = symbol_table.CreateSymbol("res", true); + { + auto dba = db.Access(); + dba.InsertVertex(); + dba.AdvanceCommand(); + query::DbAccessor execution_dba(&dba); + auto produce = + MakeProduce(advance, NEXPR("res", LITERAL(42))->MapTo(res_sym)); + auto context = MakeContext(storage, symbol_table, &execution_dba); + EXPECT_EQ(1, PullAll(*produce, &context)); + dba.Abort(); + } + { + auto dba = db.Access(); + dba.InsertVertex(); + dba.AdvanceCommand(); + query::DbAccessor execution_dba(&dba); + auto n_prop = PROPERTY_LOOKUP(n_get, dba.Property("prop")); + auto produce = MakeProduce(advance, NEXPR("res", n_prop)->MapTo(res_sym)); + auto context = MakeContext(storage, symbol_table, &execution_dba); + EXPECT_THROW(PullAll(*produce, &context), ReconstructionException); + } } TEST(QueryPlan, SetProperty) { @@ -480,16 +506,17 @@ TEST(QueryPlan, SetProperty) { auto r_p = PROPERTY_LOOKUP(IDENT("r")->MapTo(r_m.edge_sym_), prop1); auto set_r_p = std::make_shared<plan::SetProperty>(set_n_p, prop1, r_p, literal); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(2, PullAll(*set_r_p, &context)); dba.AdvanceCommand(); EXPECT_EQ(CountIterable(dba.Edges(false)), 2); - for (EdgeAccessor edge : dba.Edges(false)) { + for (auto edge : dba.Edges(false)) { ASSERT_EQ(edge.PropsAt(prop1).type(), PropertyValue::Type::Int); EXPECT_EQ(edge.PropsAt(prop1).ValueInt(), 42); - VertexAccessor from = edge.from(); - VertexAccessor to = edge.to(); + auto from = edge.from(); + auto to = edge.to(); ASSERT_EQ(from.PropsAt(prop1).type(), PropertyValue::Type::Int); EXPECT_EQ(from.PropsAt(prop1).ValueInt(), 42); ASSERT_EQ(to.PropsAt(prop1).type(), PropertyValue::Type::Null); @@ -532,13 +559,14 @@ TEST(QueryPlan, SetProperties) { std::make_shared<plan::SetProperties>(r_m.op_, n.sym_, r_ident, op); auto set_m_to_r = std::make_shared<plan::SetProperties>( set_r_to_n, r_m.edge_sym_, m_ident, op); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(1, PullAll(*set_m_to_r, &context)); dba.AdvanceCommand(); EXPECT_EQ(CountIterable(dba.Edges(false)), 1); - for (EdgeAccessor edge : dba.Edges(false)) { - VertexAccessor from = edge.from(); + for (auto edge : dba.Edges(false)) { + auto from = edge.from(); EXPECT_EQ(from.Properties().size(), update ? 2 : 1); if (update) { ASSERT_EQ(from.PropsAt(prop_a).type(), PropertyValue::Type::Int); @@ -555,7 +583,7 @@ TEST(QueryPlan, SetProperties) { ASSERT_EQ(edge.PropsAt(prop_c).type(), PropertyValue::Type::Int); EXPECT_EQ(edge.PropsAt(prop_c).ValueInt(), 2); - VertexAccessor to = edge.to(); + auto to = edge.to(); EXPECT_EQ(to.Properties().size(), 1); ASSERT_EQ(to.PropsAt(prop_c).type(), PropertyValue::Type::Int); EXPECT_EQ(to.PropsAt(prop_c).ValueInt(), 2); @@ -583,10 +611,11 @@ TEST(QueryPlan, SetLabels) { auto n = MakeScanAll(storage, symbol_table, "n"); auto label_set = std::make_shared<plan::SetLabels>( n.op_, n.sym_, std::vector<storage::Label>{label2, label3}); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(2, PullAll(*label_set, &context)); - for (VertexAccessor vertex : dba.Vertices(false)) { + for (auto vertex : dba.Vertices(false)) { vertex.SwitchNew(); EXPECT_EQ(3, vertex.labels().size()); EXPECT_TRUE(vertex.has_label(label2)); @@ -631,15 +660,16 @@ TEST(QueryPlan, RemoveProperty) { auto r_p = PROPERTY_LOOKUP(IDENT("r")->MapTo(r_m.edge_sym_), prop1); auto set_r_p = std::make_shared<plan::RemoveProperty>(set_n_p, prop1, r_p); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(2, PullAll(*set_r_p, &context)); dba.AdvanceCommand(); EXPECT_EQ(CountIterable(dba.Edges(false)), 2); - for (EdgeAccessor edge : dba.Edges(false)) { + for (auto edge : dba.Edges(false)) { EXPECT_EQ(edge.PropsAt(prop1).type(), PropertyValue::Type::Null); - VertexAccessor from = edge.from(); - VertexAccessor to = edge.to(); + auto from = edge.from(); + auto to = edge.to(); EXPECT_EQ(from.PropsAt(prop1).type(), PropertyValue::Type::Null); EXPECT_EQ(from.PropsAt(prop2).type(), PropertyValue::Type::Int); EXPECT_EQ(to.PropsAt(prop1).type(), PropertyValue::Type::Int); @@ -668,10 +698,11 @@ TEST(QueryPlan, RemoveLabels) { auto n = MakeScanAll(storage, symbol_table, "n"); auto label_remove = std::make_shared<plan::RemoveLabels>( n.op_, n.sym_, std::vector<storage::Label>{label1, label2}); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(2, PullAll(*label_remove, &context)); - for (VertexAccessor vertex : dba.Vertices(false)) { + for (auto vertex : dba.Vertices(false)) { vertex.SwitchNew(); EXPECT_EQ(1, vertex.labels().size()); EXPECT_FALSE(vertex.has_label(label1)); @@ -713,7 +744,8 @@ TEST(QueryPlan, NodeFilterSet) { auto add = ADD(set_prop, LITERAL(1)); auto set = std::make_shared<plan::SetProperty>(node_filter, prop.second, set_prop, add); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(2, PullAll(*set, &context)); dba.AdvanceCommand(); v1.Reconstruct(); @@ -752,7 +784,8 @@ TEST(QueryPlan, FilterRemove) { auto rem_prop = PROPERTY_LOOKUP(IDENT("n")->MapTo(scan_all.sym_), prop); auto rem = std::make_shared<plan::RemoveProperty>(filter, prop.second, rem_prop); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(2, PullAll(*rem, &context)); dba.AdvanceCommand(); v1.Reconstruct(); @@ -776,7 +809,8 @@ TEST(QueryPlan, SetRemove) { scan_all.op_, scan_all.sym_, std::vector<storage::Label>{label1, label2}); auto rem = std::make_shared<plan::RemoveLabels>( set, scan_all.sym_, std::vector<storage::Label>{label1, label2}); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(1, PullAll(*rem, &context)); dba.AdvanceCommand(); v.Reconstruct(); @@ -819,7 +853,8 @@ TEST(QueryPlan, Merge) { std::make_shared<Once>(), prop.second, n_p, LITERAL(2)); auto merge = std::make_shared<plan::Merge>(n.op_, m_set, n_set); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); ASSERT_EQ(3, PullAll(*merge, &context)); dba.AdvanceCommand(); v1.Reconstruct(); @@ -848,7 +883,8 @@ TEST(QueryPlan, MergeNoInput) { auto merge = std::make_shared<plan::Merge>(nullptr, create, create); EXPECT_EQ(0, CountIterable(dba.Vertices(false))); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(1, PullAll(*merge, &context)); dba.AdvanceCommand(); EXPECT_EQ(1, CountIterable(dba.Vertices(false))); @@ -867,7 +903,8 @@ TEST(QueryPlan, SetPropertyOnNull) { auto once = std::make_shared<Once>(); auto set_op = std::make_shared<plan::SetProperty>(once, prop.second, n_prop, literal); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(1, PullAll(*set_op, &context)); } @@ -884,7 +921,8 @@ TEST(QueryPlan, SetPropertiesOnNull) { auto set_op = std::make_shared<plan::SetProperties>( optional, n.sym_, n_ident, plan::SetProperties::Op::REPLACE); EXPECT_EQ(0, CountIterable(dba.Vertices(false))); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(1, PullAll(*set_op, &context)); } @@ -901,7 +939,8 @@ TEST(QueryPlan, SetLabelsOnNull) { auto set_op = std::make_shared<plan::SetLabels>( optional, n.sym_, std::vector<storage::Label>{label}); EXPECT_EQ(0, CountIterable(dba.Vertices(false))); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(1, PullAll(*set_op, &context)); } @@ -917,7 +956,8 @@ TEST(QueryPlan, RemovePropertyOnNull) { auto once = std::make_shared<Once>(); auto remove_op = std::make_shared<plan::RemoveProperty>(once, prop.second, n_prop); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(1, PullAll(*remove_op, &context)); } @@ -934,7 +974,8 @@ TEST(QueryPlan, RemoveLabelsOnNull) { auto remove_op = std::make_shared<plan::RemoveLabels>( optional, n.sym_, std::vector<storage::Label>{label}); EXPECT_EQ(0, CountIterable(dba.Vertices(false))); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(1, PullAll(*remove_op, &context)); } @@ -956,7 +997,8 @@ TEST(QueryPlan, DeleteSetProperty) { auto n_prop = PROPERTY_LOOKUP(IDENT("n")->MapTo(n.sym_), prop); auto set_op = std::make_shared<plan::SetProperty>(delete_op, prop.second, n_prop, LITERAL(42)); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_THROW(PullAll(*set_op, &context), QueryRuntimeException); } @@ -982,7 +1024,8 @@ TEST(QueryPlan, DeleteSetPropertiesFromMap) { {plan::SetProperties::Op::REPLACE, plan::SetProperties::Op::UPDATE}) { auto set_op = std::make_shared<plan::SetProperties>(delete_op, n.sym_, rhs, op_type); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_THROW(PullAll(*set_op, &context), QueryRuntimeException); } } @@ -1009,7 +1052,8 @@ TEST(QueryPlan, DeleteSetPropertiesFromVertex) { {plan::SetProperties::Op::REPLACE, plan::SetProperties::Op::UPDATE}) { auto set_op = std::make_shared<plan::SetProperties>(delete_op, n.sym_, rhs, op_type); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_THROW(PullAll(*set_op, &context), QueryRuntimeException); } } @@ -1030,7 +1074,8 @@ TEST(QueryPlan, DeleteRemoveLabels) { n.op_, std::vector<Expression *>{n_get}, false); std::vector<storage::Label> labels{dba.Label("label")}; auto rem_op = std::make_shared<plan::RemoveLabels>(delete_op, n.sym_, labels); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_THROW(PullAll(*rem_op, &context), QueryRuntimeException); } @@ -1052,6 +1097,7 @@ TEST(QueryPlan, DeleteRemoveProperty) { auto n_prop = PROPERTY_LOOKUP(IDENT("n")->MapTo(n.sym_), prop); auto rem_op = std::make_shared<plan::RemoveProperty>(delete_op, prop.second, n_prop); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_THROW(PullAll(*rem_op, &context), QueryRuntimeException); } diff --git a/tests/unit/query_plan_edge_cases.cpp b/tests/unit/query_plan_edge_cases.cpp index d6953743b..92f2b3ef9 100644 --- a/tests/unit/query_plan_edge_cases.cpp +++ b/tests/unit/query_plan_edge_cases.cpp @@ -39,8 +39,9 @@ class QueryExecution : public testing::Test { /** Executes the query and returns the results. * Does NOT commit the transaction */ auto Execute(const std::string &query) { + query::DbAccessor query_dba(&*dba_); ResultStreamFaker<query::TypedValue> stream; - auto results = query::Interpreter()(query, *dba_, {}, false, + auto results = query::Interpreter()(query, &query_dba, {}, false, utils::NewDeleteResource()); stream.Header(results.header()); results.PullAll(stream); diff --git a/tests/unit/query_plan_match_filter_return.cpp b/tests/unit/query_plan_match_filter_return.cpp index 5f48b56f3..f82dd85b0 100644 --- a/tests/unit/query_plan_match_filter_return.cpp +++ b/tests/unit/query_plan_match_filter_return.cpp @@ -37,7 +37,8 @@ class MatchReturnFixture : public testing::Test { std::vector<Path> PathResults(std::shared_ptr<Produce> &op) { std::vector<Path> res; - auto context = MakeContext(storage, symbol_table, &dba_); + query::DbAccessor execution_dba(&dba_); + auto context = MakeContext(storage, symbol_table, &execution_dba); for (const auto &row : CollectProduce(*op, &context)) res.emplace_back(row[0].ValuePath()); return res; @@ -55,7 +56,8 @@ TEST_F(MatchReturnFixture, MatchReturn) { NEXPR("n", IDENT("n")->MapTo(scan_all.sym_)) ->MapTo(symbol_table.CreateSymbol("named_expression_1", true)); auto produce = MakeProduce(scan_all.op_, output); - auto context = MakeContext(storage, symbol_table, &dba_); + query::DbAccessor execution_dba(&dba_); + auto context = MakeContext(storage, symbol_table, &execution_dba); return PullAll(*produce, &context); }; @@ -83,7 +85,8 @@ TEST_F(MatchReturnFixture, MatchReturnPath) { auto results = PathResults(produce); ASSERT_EQ(results.size(), 2); std::vector<query::Path> expected_paths; - for (const auto &v : dba_.Vertices(false)) expected_paths.emplace_back(v); + for (const auto &v : dba_.Vertices(false)) + expected_paths.emplace_back(query::VertexAccessor(v)); ASSERT_EQ(expected_paths.size(), 2); EXPECT_TRUE(std::is_permutation(expected_paths.begin(), expected_paths.end(), results.begin())); @@ -109,7 +112,8 @@ TEST(QueryPlan, MatchReturnCartesian) { NEXPR("m", IDENT("m")->MapTo(m.sym_)) ->MapTo(symbol_table.CreateSymbol("named_expression_2", true)); auto produce = MakeProduce(m.op_, return_n, return_m); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); EXPECT_EQ(results.size(), 4); // ensure the result ordering is OK: @@ -134,7 +138,8 @@ TEST(QueryPlan, StandaloneReturn) { auto produce = MakeProduce(std::shared_ptr<LogicalOperator>(nullptr), output); output->MapTo(symbol_table.CreateSymbol("named_expression_1", true)); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); EXPECT_EQ(results.size(), 1); EXPECT_EQ(results[0].size(), 1); @@ -187,7 +192,8 @@ TEST(QueryPlan, NodeFilterLabelsAndProperties) { ->MapTo(symbol_table.CreateSymbol("named_expression_1", true)); auto produce = MakeProduce(node_filter, output); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(1, PullAll(*produce, &context)); // test that filtering works with old records @@ -242,7 +248,8 @@ TEST(QueryPlan, NodeFilterMultipleLabels) { ->MapTo(symbol_table.CreateSymbol("named_expression_1", true)); auto produce = MakeProduce(node_filter, output); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); EXPECT_EQ(results.size(), 2); } @@ -257,8 +264,8 @@ TEST(QueryPlan, Cartesian) { return vertex; }; - std::vector<VertexAccessor> vertices{add_vertex("v1"), add_vertex("v2"), - add_vertex("v3")}; + std::vector<::VertexAccessor> vertices{add_vertex("v1"), add_vertex("v2"), + add_vertex("v3")}; dba.AdvanceCommand(); AstStorage storage; @@ -280,13 +287,14 @@ TEST(QueryPlan, Cartesian) { auto produce = MakeProduce(cartesian_op, return_n, return_m); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); EXPECT_EQ(results.size(), 9); for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { - EXPECT_EQ(results[3 * i + j][0].ValueVertex(), vertices[j]); - EXPECT_EQ(results[3 * i + j][1].ValueVertex(), vertices[i]); + EXPECT_EQ(results[3 * i + j][0].ValueVertex().impl_, vertices[j]); + EXPECT_EQ(results[3 * i + j][1].ValueVertex().impl_, vertices[i]); } } } @@ -313,7 +321,8 @@ TEST(QueryPlan, CartesianEmptySet) { std::make_shared<Cartesian>(n.op_, left_symbols, m.op_, right_symbols); auto produce = MakeProduce(cartesian_op, return_n, return_m); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); EXPECT_EQ(results.size(), 0); } @@ -327,8 +336,8 @@ TEST(QueryPlan, CartesianThreeWay) { return vertex; }; - std::vector<VertexAccessor> vertices{add_vertex("v1"), add_vertex("v2"), - add_vertex("v3")}; + std::vector<::VertexAccessor> vertices{add_vertex("v1"), add_vertex("v2"), + add_vertex("v3")}; dba.AdvanceCommand(); AstStorage storage; @@ -358,16 +367,17 @@ TEST(QueryPlan, CartesianThreeWay) { l.op_, l_symbols); auto produce = MakeProduce(cartesian_op_2, return_n, return_m, return_l); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); EXPECT_EQ(results.size(), 27); int id = 0; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { for (int k = 0; k < 3; ++k) { - EXPECT_EQ(results[id][0].ValueVertex(), vertices[k]); - EXPECT_EQ(results[id][1].ValueVertex(), vertices[j]); - EXPECT_EQ(results[id][2].ValueVertex(), vertices[i]); + EXPECT_EQ(results[id][0].ValueVertex().impl_, vertices[k]); + EXPECT_EQ(results[id][1].ValueVertex().impl_, vertices[j]); + EXPECT_EQ(results[id][2].ValueVertex().impl_, vertices[i]); ++id; } } @@ -382,12 +392,12 @@ class ExpandFixture : public testing::Test { SymbolTable symbol_table; // make a V-graph (v3)<-[r2]-(v1)-[r1]->(v2) - VertexAccessor v1 = dba_.InsertVertex(); - VertexAccessor v2 = dba_.InsertVertex(); - VertexAccessor v3 = dba_.InsertVertex(); + ::VertexAccessor v1 = dba_.InsertVertex(); + ::VertexAccessor v2 = dba_.InsertVertex(); + ::VertexAccessor v3 = dba_.InsertVertex(); storage::EdgeType edge_type = dba_.EdgeType("Edge"); - EdgeAccessor r1 = dba_.InsertEdge(v1, v2, edge_type); - EdgeAccessor r2 = dba_.InsertEdge(v1, v3, edge_type); + ::EdgeAccessor r1 = dba_.InsertEdge(v1, v2, edge_type); + ::EdgeAccessor r2 = dba_.InsertEdge(v1, v3, edge_type); void SetUp() override { v1.add_label(dba_.Label("l1")); @@ -409,7 +419,8 @@ TEST_F(ExpandFixture, Expand) { NEXPR("m", IDENT("m")->MapTo(r_m.node_sym_)) ->MapTo(symbol_table.CreateSymbol("named_expression_1", true)); auto produce = MakeProduce(r_m.op_, output); - auto context = MakeContext(storage, symbol_table, &dba_); + query::DbAccessor execution_dba(&dba_); + auto context = MakeContext(storage, symbol_table, &execution_dba); return PullAll(*produce, &context); }; @@ -445,9 +456,13 @@ TEST_F(ExpandFixture, ExpandPath) { ->MapTo(symbol_table.CreateSymbol("named_expression_1", true)); auto produce = MakeProduce(path, output); - std::vector<query::Path> expected_paths{query::Path(v1, r2, v3), - query::Path(v1, r1, v2)}; - auto context = MakeContext(storage, symbol_table, &dba_); + std::vector<query::Path> expected_paths{ + query::Path(query::VertexAccessor(v1), query::EdgeAccessor(r2), + query::VertexAccessor(v3)), + query::Path(query::VertexAccessor(v1), query::EdgeAccessor(r1), + query::VertexAccessor(v2))}; + query::DbAccessor execution_dba(&dba_); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); ASSERT_EQ(results.size(), 2); std::vector<query::Path> results_paths; @@ -491,11 +506,11 @@ class QueryPlanExpandVariable : public testing::Test { void SetUp() { // create the graph int chain_length = 3; - std::vector<VertexAccessor> layer; + std::vector<::VertexAccessor> layer; for (int from_layer_ind = -1; from_layer_ind < chain_length - 1; from_layer_ind++) { - std::vector<VertexAccessor> new_layer{dba_.InsertVertex(), - dba_.InsertVertex()}; + std::vector<::VertexAccessor> new_layer{dba_.InsertVertex(), + dba_.InsertVertex()}; auto label = dba_.Label(std::to_string(from_layer_ind + 1)); labels.push_back(label); for (size_t v_to_ind = 0; v_to_ind < new_layer.size(); v_to_ind++) { @@ -582,7 +597,8 @@ class QueryPlanExpandVariable : public testing::Test { auto GetListResults(std::shared_ptr<LogicalOperator> input_op, Symbol symbol) { Frame frame(symbol_table.max_position()); auto cursor = input_op->MakeCursor(utils::NewDeleteResource()); - auto context = MakeContext(storage, symbol_table, &dba_); + query::DbAccessor execution_dba(&dba_); + auto context = MakeContext(storage, symbol_table, &execution_dba); std::vector<utils::pmr::vector<TypedValue>> results; while (cursor->Pull(frame, context)) results.emplace_back(frame[symbol].ValueList()); @@ -595,7 +611,8 @@ class QueryPlanExpandVariable : public testing::Test { auto GetPathResults(std::shared_ptr<LogicalOperator> input_op, Symbol symbol) { Frame frame(symbol_table.max_position()); auto cursor = input_op->MakeCursor(utils::NewDeleteResource()); - auto context = MakeContext(storage, symbol_table, &dba_); + query::DbAccessor execution_dba(&dba_); + auto context = MakeContext(storage, symbol_table, &execution_dba); std::vector<Path> results; while (cursor->Pull(frame, context)) results.emplace_back(frame[symbol].ValuePath()); @@ -776,7 +793,10 @@ TEST_F(QueryPlanExpandVariable, NamedPath) { for (const auto &v : dba_.Vertices(labels[0], false)) for (const auto &e1 : v.out()) for (const auto &e2 : e1.to().out()) - expected_paths.emplace_back(v, e1, e1.to(), e2, e2.to()); + expected_paths.emplace_back( + query::VertexAccessor(v), query::EdgeAccessor(e1), + query::VertexAccessor(e1.to()), query::EdgeAccessor(e2), + query::VertexAccessor(e2.to())); ASSERT_EQ(expected_paths.size(), 8); auto results = GetPathResults(create_path, path_symbol); @@ -798,8 +818,8 @@ struct hash<std::pair<int, int>> { class QueryPlanExpandWeightedShortestPath : public testing::Test { public: struct ResultType { - std::vector<EdgeAccessor> path; - VertexAccessor vertex; + std::vector<::EdgeAccessor> path; + ::VertexAccessor vertex; double total_weight; }; @@ -813,10 +833,10 @@ class QueryPlanExpandWeightedShortestPath : public testing::Test { // make 5 vertices because we'll need to compare against them exactly // v[0] has `prop` with the value 0 - std::vector<VertexAccessor> v; + std::vector<::VertexAccessor> v; // make some edges too, in a map (from, to) vertex indices - std::unordered_map<std::pair<int, int>, EdgeAccessor> e; + std::unordered_map<std::pair<int, int>, ::EdgeAccessor> e; AstStorage storage; SymbolTable symbol_table; @@ -837,7 +857,7 @@ class QueryPlanExpandWeightedShortestPath : public testing::Test { } auto add_edge = [&](int from, int to, double weight) { - EdgeAccessor edge = dba.InsertEdge(v[from], v[to], edge_type); + auto edge = dba.InsertEdge(v[from], v[to], edge_type); edge.PropsSet(prop.second, PropertyValue(weight)); e.emplace(std::make_pair(from, to), edge); }; @@ -894,13 +914,14 @@ class QueryPlanExpandWeightedShortestPath : public testing::Test { Frame frame(symbol_table.max_position()); auto cursor = last_op->MakeCursor(utils::NewDeleteResource()); std::vector<ResultType> results; - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); while (cursor->Pull(frame, context)) { - results.push_back(ResultType{std::vector<EdgeAccessor>(), - frame[node_sym].ValueVertex(), + results.push_back(ResultType{std::vector<::EdgeAccessor>(), + frame[node_sym].ValueVertex().impl_, frame[total_weight].ValueDouble()}); for (const TypedValue &edge : frame[edge_list_sym].ValueList()) - results.back().path.emplace_back(edge.ValueEdge()); + results.back().path.emplace_back(edge.ValueEdge().impl_); } return results; @@ -1168,13 +1189,14 @@ TEST(QueryPlan, ExpandOptional) { auto m_ne = NEXPR("m", IDENT("m")->MapTo(r_m.node_sym_)) ->MapTo(symbol_table.CreateSymbol("m", true)); auto produce = MakeProduce(optional, n_ne, r_ne, m_ne); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); ASSERT_EQ(4, results.size()); int v1_is_n_count = 0; for (auto &row : results) { ASSERT_EQ(row[0].type(), TypedValue::Type::Vertex); - VertexAccessor &va = row[0].ValueVertex(); + auto &va = row[0].ValueVertex().impl_; auto va_p = va.PropsAt(prop); ASSERT_EQ(va_p.type(), PropertyValue::Type::Int); if (va_p.ValueInt() == 1) { @@ -1204,7 +1226,8 @@ TEST(QueryPlan, OptionalMatchEmptyDB) { auto optional = std::make_shared<plan::Optional>(nullptr, n.op_, std::vector<Symbol>{n.sym_}); auto produce = MakeProduce(optional, n_ne); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); ASSERT_EQ(1, results.size()); EXPECT_EQ(results[0][0].type(), TypedValue::Type::Null); @@ -1232,7 +1255,8 @@ TEST(QueryPlan, OptionalMatchEmptyDBExpandFromNode) { auto m_ne = NEXPR("m", IDENT("m")->MapTo(r_m.node_sym_)) ->MapTo(symbol_table.CreateSymbol("m", true)); auto produce = MakeProduce(r_m.op_, m_ne); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); EXPECT_EQ(0, results.size()); } @@ -1280,7 +1304,8 @@ TEST(QueryPlan, OptionalMatchThenExpandToMissingNode) { auto m_ne = NEXPR("m", IDENT("m")->MapTo(m.sym_)) ->MapTo(symbol_table.CreateSymbol("m", true)); auto produce = MakeProduce(expand, m_ne); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); EXPECT_EQ(0, results.size()); } @@ -1316,7 +1341,8 @@ TEST(QueryPlan, ExpandExistingNode) { NEXPR("n", IDENT("n")->MapTo(n.sym_)) ->MapTo(symbol_table.CreateSymbol("named_expression_1", true)); auto produce = MakeProduce(r_n.op_, output); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); EXPECT_EQ(results.size(), expected_result_count); }; @@ -1342,7 +1368,8 @@ TEST(QueryPlan, ExpandBothCycleEdgeCase) { auto r_ = MakeExpand(storage, symbol_table, n.op_, n.sym_, "r", EdgeAtom::Direction::BOTH, {}, "_", false, storage::View::OLD); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(1, PullAll(*r_.op_, &context)); } @@ -1357,10 +1384,10 @@ TEST(QueryPlan, EdgeFilter) { std::vector<storage::EdgeType> edge_types; for (int j = 0; j < 2; ++j) edge_types.push_back(dba.EdgeType("et" + std::to_string(j))); - std::vector<VertexAccessor> vertices; + std::vector<::VertexAccessor> vertices; for (int i = 0; i < 7; ++i) vertices.push_back(dba.InsertVertex()); auto prop = PROPERTY_PAIR("property"); - std::vector<EdgeAccessor> edges; + std::vector<::EdgeAccessor> edges; for (int i = 0; i < 6; ++i) { edges.push_back( dba.InsertEdge(vertices[0], vertices[i + 1], edge_types[i % 2])); @@ -1403,7 +1430,8 @@ TEST(QueryPlan, EdgeFilter) { NEXPR("m", IDENT("m")->MapTo(r_m.node_sym_)) ->MapTo(symbol_table.CreateSymbol("named_expression_1", true)); auto produce = MakeProduce(edge_filter, output); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); return PullAll(*produce, &context); }; @@ -1443,7 +1471,8 @@ TEST(QueryPlan, EdgeFilterMultipleTypes) { NEXPR("m", IDENT("m")->MapTo(r_m.node_sym_)) ->MapTo(symbol_table.CreateSymbol("named_expression_1", true)); auto produce = MakeProduce(r_m.op_, output); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); EXPECT_EQ(results.size(), 2); } @@ -1470,7 +1499,8 @@ TEST(QueryPlan, Filter) { NEXPR("x", IDENT("n")->MapTo(n.sym_)) ->MapTo(symbol_table.CreateSymbol("named_expression_1", true)); auto produce = MakeProduce(f, output); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(CollectProduce(*produce, &context).size(), 2); } @@ -1502,7 +1532,8 @@ TEST(QueryPlan, EdgeUniquenessFilter) { if (edge_uniqueness) last_op = std::make_shared<EdgeUniquenessFilter>( last_op, r2_n3.edge_sym_, std::vector<Symbol>{r1_n2.edge_sym_}); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); return PullAll(*last_op, &context); }; @@ -1535,7 +1566,8 @@ TEST(QueryPlan, Distinct) { auto x_ne = NEXPR("x", x_expr); x_ne->MapTo(symbol_table.CreateSymbol("x_ne", true)); auto produce = MakeProduce(distinct, x_ne); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); ASSERT_EQ(output.size(), results.size()); auto output_it = output.begin(); @@ -1582,12 +1614,13 @@ TEST(QueryPlan, ScanAllByLabel) { auto output = NEXPR("n", IDENT("n")->MapTo(scan_all_by_label.sym_)) ->MapTo(symbol_table.CreateSymbol("n", true)); auto produce = MakeProduce(scan_all_by_label.op_, output); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); ASSERT_EQ(results.size(), 1); auto result_row = results[0]; ASSERT_EQ(result_row.size(), 1); - EXPECT_EQ(result_row[0].ValueVertex(), labeled_vertex); + EXPECT_EQ(result_row[0].ValueVertex().impl_, labeled_vertex); } TEST(QueryPlan, ScanAllByLabelProperty) { @@ -1636,12 +1669,14 @@ TEST(QueryPlan, ScanAllByLabelProperty) { auto output = NEXPR("n", IDENT("n")->MapTo(scan_all.sym_)) ->MapTo(symbol_table.CreateSymbol("n", true)); auto produce = MakeProduce(scan_all.op_, output); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); ASSERT_EQ(results.size(), expected.size()); for (size_t i = 0; i < expected.size(); i++) { TypedValue equal = - TypedValue(results[i][0].ValueVertex().PropsAt(prop)) == expected[i]; + TypedValue(results[i][0].ValueVertex().impl_.PropsAt(prop)) == + expected[i]; ASSERT_EQ(equal.type(), TypedValue::Type::Bool); EXPECT_TRUE(equal.ValueBool()); } @@ -1712,12 +1747,13 @@ TEST(QueryPlan, ScanAllByLabelPropertyEqualityNoError) { auto output = NEXPR("n", IDENT("n")->MapTo(scan_all.sym_)) ->MapTo(symbol_table.CreateSymbol("n", true)); auto produce = MakeProduce(scan_all.op_, output); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); ASSERT_EQ(results.size(), 1); const auto &row = results[0]; ASSERT_EQ(row.size(), 1); - auto vertex = row[0].ValueVertex(); + auto vertex = row[0].ValueVertex().impl_; TypedValue value(vertex.PropsAt(prop)); TypedValue::BoolEqual eq; EXPECT_TRUE(eq(value, TypedValue(42))); @@ -1747,7 +1783,8 @@ TEST(QueryPlan, ScanAllByLabelPropertyValueError) { ident_m->MapTo(scan_all.sym_); auto scan_index = MakeScanAllByLabelPropertyValue( storage, symbol_table, "n", label, prop, "prop", ident_m, scan_all.op_); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_THROW(PullAll(*scan_index.op_, &context), QueryRuntimeException); } @@ -1778,7 +1815,8 @@ TEST(QueryPlan, ScanAllByLabelPropertyRangeError) { auto scan_index = MakeScanAllByLabelPropertyRange( storage, symbol_table, "n", label, prop, "prop", Bound{ident_m, Bound::Type::INCLUSIVE}, std::nullopt, scan_all.op_); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_THROW(PullAll(*scan_index.op_, &context), QueryRuntimeException); } { @@ -1786,7 +1824,8 @@ TEST(QueryPlan, ScanAllByLabelPropertyRangeError) { auto scan_index = MakeScanAllByLabelPropertyRange( storage, symbol_table, "n", label, prop, "prop", std::nullopt, Bound{ident_m, Bound::Type::INCLUSIVE}, scan_all.op_); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_THROW(PullAll(*scan_index.op_, &context), QueryRuntimeException); } { @@ -1795,7 +1834,8 @@ TEST(QueryPlan, ScanAllByLabelPropertyRangeError) { storage, symbol_table, "n", label, prop, "prop", Bound{ident_m, Bound::Type::INCLUSIVE}, Bound{ident_m, Bound::Type::INCLUSIVE}, scan_all.op_); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_THROW(PullAll(*scan_index.op_, &context), QueryRuntimeException); } } @@ -1829,7 +1869,8 @@ TEST(QueryPlan, ScanAllByLabelPropertyEqualNull) { auto output = NEXPR("n", IDENT("n")->MapTo(scan_all.sym_)) ->MapTo(symbol_table.CreateSymbol("n", true)); auto produce = MakeProduce(scan_all.op_, output); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); EXPECT_EQ(results.size(), 0); } @@ -1864,7 +1905,8 @@ TEST(QueryPlan, ScanAllByLabelPropertyRangeNull) { auto output = NEXPR("n", IDENT("n")->MapTo(scan_all.sym_)) ->MapTo(symbol_table.CreateSymbol("n", true)); auto produce = MakeProduce(scan_all.op_, output); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); EXPECT_EQ(results.size(), 0); } @@ -1898,7 +1940,8 @@ TEST(QueryPlan, ScanAllByLabelPropertyNoValueInIndexContinuation) { auto scan_all = MakeScanAllByLabelPropertyValue( storage, symbol_table, "n", label, prop, "prop", x_expr, unwind); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(PullAll(*scan_all.op_, &context), 1); } @@ -1939,7 +1982,8 @@ TEST(QueryPlan, ScanAllEqualsScanAllByLabelProperty) { NEXPR("n", IDENT("n")->MapTo(scan_all_by_label_property_value.sym_)) ->MapTo(symbol_table.CreateSymbol("named_expression_1", true)); auto produce = MakeProduce(scan_all_by_label_property_value.op_, output); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(PullAll(*produce, &context), prop_count); }; @@ -1957,7 +2001,8 @@ TEST(QueryPlan, ScanAllEqualsScanAllByLabelProperty) { NEXPR("n", IDENT("n")->MapTo(scan_all.sym_)) ->MapTo(symbol_table.CreateSymbol("named_expression_1", true)); auto produce = MakeProduce(filter, output); - auto context = MakeContext(storage, symbol_table, &dba); + query::DbAccessor execution_dba(&dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); EXPECT_EQ(PullAll(*produce, &context), prop_count); }; diff --git a/tests/unit/query_plan_v2_create_set_remove_delete.cpp b/tests/unit/query_plan_v2_create_set_remove_delete.cpp new file mode 100644 index 000000000..2975d5be0 --- /dev/null +++ b/tests/unit/query_plan_v2_create_set_remove_delete.cpp @@ -0,0 +1,119 @@ +#include <gtest/gtest.h> + +#include "query_plan_common.hpp" + +#include "query/frontend/semantic/symbol_table.hpp" +#include "query/plan/operator.hpp" +#include "storage/v2/storage.hpp" + +TEST(QueryPlan, CreateNodeWithAttributes) { + storage::Storage db; + auto dba = db.Access(); + + auto label = storage::Label::FromInt(42); + auto property = storage::Property::FromInt(1); + + query::AstStorage ast; + query::SymbolTable symbol_table; + + query::plan::NodeCreationInfo node; + node.symbol = symbol_table.CreateSymbol("n", true); + node.labels.emplace_back(label); + node.properties.emplace_back(property, ast.Create<PrimitiveLiteral>(42)); + + query::plan::CreateNode create_node(nullptr, node); + DbAccessor execution_dba(&dba); + auto context = MakeContext(ast, symbol_table, &execution_dba); + Frame frame(context.symbol_table.max_position()); + auto cursor = create_node.MakeCursor(utils::NewDeleteResource()); + int count = 0; + while (cursor->Pull(frame, context)) { + ++count; + const auto &node_value = frame[node.symbol]; + EXPECT_EQ(node_value.type(), TypedValue::Type::Vertex); + const auto &v = node_value.ValueVertex(); + EXPECT_TRUE(*v.HasLabel(storage::View::NEW, label)); + EXPECT_EQ(v.GetProperty(storage::View::NEW, property)->ValueInt(), 42); + EXPECT_EQ(CountIterable(*v.InEdges(storage::View::NEW)), 0); + EXPECT_EQ(CountIterable(*v.OutEdges(storage::View::NEW)), 0); + // Invokes LOG(FATAL) instead of erroring out. + // EXPECT_TRUE(v.HasLabel(label, storage::View::OLD).IsError()); + } + EXPECT_EQ(count, 1); +} + +TEST(QueryPlan, ScanAllEmpty) { + query::AstStorage ast; + query::SymbolTable symbol_table; + storage::Storage db; + auto dba = db.Access(); + DbAccessor execution_dba(&dba); + auto node_symbol = symbol_table.CreateSymbol("n", true); + { + query::plan::ScanAll scan_all(nullptr, node_symbol, storage::View::OLD); + auto context = MakeContext(ast, symbol_table, &execution_dba); + Frame frame(context.symbol_table.max_position()); + auto cursor = scan_all.MakeCursor(utils::NewDeleteResource()); + int count = 0; + while (cursor->Pull(frame, context)) ++count; + EXPECT_EQ(count, 0); + } + { + query::plan::ScanAll scan_all(nullptr, node_symbol, storage::View::NEW); + auto context = MakeContext(ast, symbol_table, &execution_dba); + Frame frame(context.symbol_table.max_position()); + auto cursor = scan_all.MakeCursor(utils::NewDeleteResource()); + int count = 0; + while (cursor->Pull(frame, context)) ++count; + EXPECT_EQ(count, 0); + } +} + +TEST(QueryPlan, ScanAll) { + storage::Storage db; + { + auto dba = db.Access(); + for (int i = 0; i < 42; ++i) dba.CreateVertex(); + EXPECT_FALSE(dba.Commit().HasError()); + } + query::AstStorage ast; + query::SymbolTable symbol_table; + auto dba = db.Access(); + DbAccessor execution_dba(&dba); + auto node_symbol = symbol_table.CreateSymbol("n", true); + query::plan::ScanAll scan_all(nullptr, node_symbol); + auto context = MakeContext(ast, symbol_table, &execution_dba); + Frame frame(context.symbol_table.max_position()); + auto cursor = scan_all.MakeCursor(utils::NewDeleteResource()); + int count = 0; + while (cursor->Pull(frame, context)) ++count; + EXPECT_EQ(count, 42); +} + +TEST(QueryPlan, ScanAllByLabel) { + storage::Storage db; + auto label = db.NameToLabel("label"); + { + auto dba = db.Access(); + // Add some unlabeled vertices + for (int i = 0; i < 12; ++i) dba.CreateVertex(); + // Add labeled vertices + for (int i = 0; i < 42; ++i) { + auto v = dba.CreateVertex(); + ASSERT_TRUE(v.AddLabel(label).HasValue()); + } + EXPECT_FALSE(dba.Commit().HasError()); + } + auto dba = db.Access(); + query::AstStorage ast; + query::SymbolTable symbol_table; + auto node_symbol = symbol_table.CreateSymbol("n", true); + DbAccessor execution_dba(&dba); + query::plan::ScanAllByLabel scan_all(nullptr, node_symbol, label); + auto context = MakeContext(ast, symbol_table, &execution_dba); + Frame frame(context.symbol_table.max_position()); + auto cursor = scan_all.MakeCursor(utils::NewDeleteResource()); + int count = 0; + while (cursor->Pull(frame, context)) ++count; + EXPECT_EQ(count, 42); +} diff --git a/tests/unit/query_variable_start_planner.cpp b/tests/unit/query_variable_start_planner.cpp index 050a32e5e..af2d74e18 100644 --- a/tests/unit/query_variable_start_planner.cpp +++ b/tests/unit/query_variable_start_planner.cpp @@ -61,8 +61,9 @@ void CheckPlansProduce( database::GraphDbAccessor *dba, std::function<void(const std::vector<std::vector<TypedValue>> &)> check) { auto symbol_table = query::MakeSymbolTable(query); + query::DbAccessor execution_dba(dba); auto planning_context = - MakePlanningContext(&storage, &symbol_table, query, dba); + MakePlanningContext(&storage, &symbol_table, query, &execution_dba); auto query_parts = CollectQueryParts(symbol_table, storage, query); EXPECT_TRUE(query_parts.query_parts.size() > 0); auto single_query_parts = query_parts.query_parts.at(0).single_query_parts; @@ -72,7 +73,7 @@ void CheckPlansProduce( for (const auto &plan : plans) { auto *produce = dynamic_cast<Produce *>(plan.get()); ASSERT_TRUE(produce); - auto context = MakeContext(storage, symbol_table, dba); + auto context = MakeContext(storage, symbol_table, &execution_dba); auto results = CollectProduce(*produce, &context); check(results); } @@ -94,7 +95,7 @@ TEST(TestVariableStartPlanner, MatchReturn) { // We have 2 nodes `n` and `m` from which we could start, so expect 2 plans. CheckPlansProduce(2, query, storage, &dba, [&](const auto &results) { // We expect to produce only a single (v1) node. - AssertRows(results, {{TypedValue(v1)}}); + AssertRows(results, {{TypedValue(query::VertexAccessor(v1))}}); }); } @@ -118,7 +119,7 @@ TEST(TestVariableStartPlanner, MatchTripletPatternReturn) { // We have 3 nodes: `n`, `m` and `l` from which we could start. CheckPlansProduce(3, query, storage, &dba, [&](const auto &results) { // We expect to produce only a single (v1) node. - AssertRows(results, {{TypedValue(v1)}}); + AssertRows(results, {{TypedValue(query::VertexAccessor(v1))}}); }); } { @@ -129,7 +130,7 @@ TEST(TestVariableStartPlanner, MatchTripletPatternReturn) { PATTERN(NODE("m"), EDGE("e", Direction::OUT), NODE("l"))), RETURN("n"))); CheckPlansProduce(3, query, storage, &dba, [&](const auto &results) { - AssertRows(results, {{TypedValue(v1)}}); + AssertRows(results, {{TypedValue(query::VertexAccessor(v1))}}); }); } } @@ -156,8 +157,10 @@ TEST(TestVariableStartPlanner, MatchOptionalMatchReturn) { // We expect to produce 2 rows: // * (v1), (v3) // * (v2), null - AssertRows(results, {{TypedValue(v1), TypedValue(v3)}, - {TypedValue(v2), TypedValue()}}); + AssertRows(results, + {{TypedValue(query::VertexAccessor(v1)), + TypedValue(query::VertexAccessor(v3))}, + {TypedValue(query::VertexAccessor(v2)), TypedValue()}}); }); } @@ -165,11 +168,11 @@ TEST(TestVariableStartPlanner, MatchOptionalMatchMergeReturn) { database::GraphDb db; auto dba = db.Access(); // Graph (v1) -[:r]-> (v2) - auto v1 = dba.InsertVertex(); - auto v2 = dba.InsertVertex(); + query::VertexAccessor v1(dba.InsertVertex()); + query::VertexAccessor v2(dba.InsertVertex()); auto r_type_name = "r"; auto r_type = dba.EdgeType(r_type_name); - dba.InsertEdge(v1, v2, r_type); + dba.InsertEdge(v1.impl_, v2.impl_, r_type); dba.AdvanceCommand(); // Test MATCH (n) -[r]-> (m) OPTIONAL MATCH (m) -[e]-> (l) // MERGE (u) -[q:r]-> (v) RETURN n, m, l, u, v @@ -193,9 +196,9 @@ TEST(TestVariableStartPlanner, MatchWithMatchReturn) { database::GraphDb db; auto dba = db.Access(); // Graph (v1) -[:r]-> (v2) - auto v1 = dba.InsertVertex(); - auto v2 = dba.InsertVertex(); - dba.InsertEdge(v1, v2, dba.EdgeType("r")); + query::VertexAccessor v1(dba.InsertVertex()); + query::VertexAccessor v2(dba.InsertVertex()); + dba.InsertEdge(v1.impl_, v2.impl_, dba.EdgeType("r")); dba.AdvanceCommand(); // Test MATCH (n) -[r]-> (m) WITH n MATCH (m) -[r]-> (l) RETURN n, m, l AstStorage storage; @@ -219,8 +222,8 @@ TEST(TestVariableStartPlanner, MatchVariableExpand) { auto v1 = dba.InsertVertex(); auto v2 = dba.InsertVertex(); auto v3 = dba.InsertVertex(); - auto r1 = dba.InsertEdge(v1, v2, dba.EdgeType("r1")); - auto r2 = dba.InsertEdge(v2, v3, dba.EdgeType("r2")); + query::EdgeAccessor r1(dba.InsertEdge(v1, v2, dba.EdgeType("r1"))); + query::EdgeAccessor r2(dba.InsertEdge(v2, v3, dba.EdgeType("r2"))); dba.AdvanceCommand(); // Test MATCH (n) -[r*]-> (m) RETURN r AstStorage storage; @@ -249,8 +252,8 @@ TEST(TestVariableStartPlanner, MatchVariableExpandReferenceNode) { v2.PropsSet(id, PropertyValue(2)); auto v3 = dba.InsertVertex(); v3.PropsSet(id, PropertyValue(3)); - auto r1 = dba.InsertEdge(v1, v2, dba.EdgeType("r1")); - auto r2 = dba.InsertEdge(v2, v3, dba.EdgeType("r2")); + query::EdgeAccessor r1(dba.InsertEdge(v1, v2, dba.EdgeType("r1"))); + query::EdgeAccessor r2(dba.InsertEdge(v2, v3, dba.EdgeType("r2"))); dba.AdvanceCommand(); // Test MATCH (n) -[r*..n.id]-> (m) RETURN r AstStorage storage; @@ -277,8 +280,8 @@ TEST(TestVariableStartPlanner, MatchVariableExpandBoth) { v1.PropsSet(id, PropertyValue(1)); auto v2 = dba.InsertVertex(); auto v3 = dba.InsertVertex(); - auto r1 = dba.InsertEdge(v1, v2, dba.EdgeType("r1")); - auto r2 = dba.InsertEdge(v2, v3, dba.EdgeType("r2")); + query::EdgeAccessor r1(dba.InsertEdge(v1, v2, dba.EdgeType("r1"))); + query::EdgeAccessor r2(dba.InsertEdge(v2, v3, dba.EdgeType("r2"))); dba.AdvanceCommand(); // Test MATCH (n {id:1}) -[r*]- (m) RETURN r AstStorage storage; @@ -308,7 +311,7 @@ TEST(TestVariableStartPlanner, MatchBfs) { v2.PropsSet(id, PropertyValue(2)); auto v3 = dba.InsertVertex(); v3.PropsSet(id, PropertyValue(3)); - auto r1 = dba.InsertEdge(v1, v2, dba.EdgeType("r1")); + query::EdgeAccessor r1(dba.InsertEdge(v1, v2, dba.EdgeType("r1"))); dba.InsertEdge(v2, v3, dba.EdgeType("r2")); dba.AdvanceCommand(); // Test MATCH (n) -[r *bfs..10](r, n | n.id <> 3)]-> (m) RETURN r diff --git a/tests/unit/typed_value.cpp b/tests/unit/typed_value.cpp index 4630cc879..69f9dd49e 100644 --- a/tests/unit/typed_value.cpp +++ b/tests/unit/typed_value.cpp @@ -37,9 +37,11 @@ class AllTypesFixture : public testing::Test { {"d", TypedValue(0.5)}, {"e", TypedValue()}}); auto vertex = dba_.InsertVertex(); - values_.emplace_back(vertex); - values_.emplace_back(dba_.InsertEdge(vertex, vertex, dba_.EdgeType("et"))); - values_.emplace_back(query::Path(dba_.InsertVertex())); + values_.emplace_back(query::VertexAccessor(vertex)); + values_.emplace_back(query::EdgeAccessor( + dba_.InsertEdge(vertex, vertex, dba_.EdgeType("et")))); + values_.emplace_back( + query::Path(query::VertexAccessor(dba_.InsertVertex()))); } };