2023-03-27 21:46:00 +08:00
|
|
|
// Copyright 2023 Memgraph Ltd.
|
2021-10-03 18:07:04 +08:00
|
|
|
//
|
|
|
|
// Use of this software is governed by the Business Source License
|
|
|
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
|
|
|
// License, and you may not use this file except in compliance with the Business Source License.
|
|
|
|
//
|
|
|
|
// As of the Change Date specified in that file, in accordance with
|
|
|
|
// the Business Source License, use of this software will be governed
|
|
|
|
// by the Apache License, Version 2.0, included in the file
|
|
|
|
// licenses/APL.txt.
|
|
|
|
|
2017-03-22 23:38:43 +08:00
|
|
|
#pragma once
|
|
|
|
|
2023-03-27 21:46:00 +08:00
|
|
|
#include <unordered_set>
|
|
|
|
|
2017-06-21 17:29:13 +08:00
|
|
|
#include <gflags/gflags.h>
|
|
|
|
|
2021-07-22 22:22:08 +08:00
|
|
|
#include "query/auth_checker.hpp"
|
2021-06-30 17:19:13 +08:00
|
|
|
#include "query/config.hpp"
|
2017-03-22 23:38:43 +08:00
|
|
|
#include "query/context.hpp"
|
2021-04-15 16:49:40 +08:00
|
|
|
#include "query/cypher_query_interpreter.hpp"
|
2019-09-11 22:10:53 +08:00
|
|
|
#include "query/db_accessor.hpp"
|
2020-10-16 18:49:33 +08:00
|
|
|
#include "query/exceptions.hpp"
|
2017-12-22 20:39:31 +08:00
|
|
|
#include "query/frontend/ast/ast.hpp"
|
2019-01-16 18:30:17 +08:00
|
|
|
#include "query/frontend/ast/cypher_main_visitor.hpp"
|
2017-06-15 00:53:02 +08:00
|
|
|
#include "query/frontend/stripped.hpp"
|
2017-04-13 16:01:16 +08:00
|
|
|
#include "query/interpret/frame.hpp"
|
2021-11-15 20:51:13 +08:00
|
|
|
#include "query/metadata.hpp"
|
2017-09-19 22:58:22 +08:00
|
|
|
#include "query/plan/operator.hpp"
|
2021-01-19 19:08:38 +08:00
|
|
|
#include "query/plan/read_write_type_checker.hpp"
|
2019-11-12 17:47:02 +08:00
|
|
|
#include "query/stream.hpp"
|
2021-10-27 15:06:02 +08:00
|
|
|
#include "query/stream/streams.hpp"
|
2021-04-15 16:49:40 +08:00
|
|
|
#include "query/trigger.hpp"
|
2020-10-16 18:49:33 +08:00
|
|
|
#include "query/typed_value.hpp"
|
2021-06-14 21:47:57 +08:00
|
|
|
#include "storage/v2/isolation_level.hpp"
|
2021-03-10 02:55:58 +08:00
|
|
|
#include "utils/event_counter.hpp"
|
2021-01-21 22:47:56 +08:00
|
|
|
#include "utils/logging.hpp"
|
2019-10-10 17:23:33 +08:00
|
|
|
#include "utils/memory.hpp"
|
2021-09-30 01:14:39 +08:00
|
|
|
#include "utils/settings.hpp"
|
2019-08-20 15:33:31 +08:00
|
|
|
#include "utils/skip_list.hpp"
|
2019-01-07 16:18:52 +08:00
|
|
|
#include "utils/spin_lock.hpp"
|
2023-03-27 21:46:00 +08:00
|
|
|
#include "utils/synchronized.hpp"
|
2021-04-20 17:09:35 +08:00
|
|
|
#include "utils/thread_pool.hpp"
|
2017-07-15 01:33:45 +08:00
|
|
|
#include "utils/timer.hpp"
|
2019-10-07 23:31:25 +08:00
|
|
|
#include "utils/tsc.hpp"
|
2017-03-22 23:38:43 +08:00
|
|
|
|
2021-03-10 02:55:58 +08:00
|
|
|
namespace EventCounter {
|
|
|
|
extern const Event FailedQuery;
|
|
|
|
} // namespace EventCounter
|
|
|
|
|
2022-02-22 20:33:45 +08:00
|
|
|
namespace memgraph::query {
|
2017-03-22 23:38:43 +08:00
|
|
|
|
2022-03-31 19:52:43 +08:00
|
|
|
inline constexpr size_t kExecutionMemoryBlockSize = 1UL * 1024UL * 1024UL;
|
2019-10-10 17:23:33 +08:00
|
|
|
|
2020-01-15 20:58:41 +08:00
|
|
|
class AuthQueryHandler {
|
|
|
|
public:
|
|
|
|
AuthQueryHandler() = default;
|
|
|
|
virtual ~AuthQueryHandler() = default;
|
|
|
|
|
|
|
|
AuthQueryHandler(const AuthQueryHandler &) = delete;
|
|
|
|
AuthQueryHandler(AuthQueryHandler &&) = delete;
|
|
|
|
AuthQueryHandler &operator=(const AuthQueryHandler &) = delete;
|
|
|
|
AuthQueryHandler &operator=(AuthQueryHandler &&) = delete;
|
|
|
|
|
|
|
|
/// Return false if the user already exists.
|
|
|
|
/// @throw QueryRuntimeException if an error ocurred.
|
2021-02-18 22:32:43 +08:00
|
|
|
virtual bool CreateUser(const std::string &username, const std::optional<std::string> &password) = 0;
|
2020-01-15 20:58:41 +08:00
|
|
|
|
|
|
|
/// Return false if the user does not exist.
|
|
|
|
/// @throw QueryRuntimeException if an error ocurred.
|
|
|
|
virtual bool DropUser(const std::string &username) = 0;
|
|
|
|
|
|
|
|
/// @throw QueryRuntimeException if an error ocurred.
|
2021-02-18 22:32:43 +08:00
|
|
|
virtual void SetPassword(const std::string &username, const std::optional<std::string> &password) = 0;
|
2020-01-15 20:58:41 +08:00
|
|
|
|
|
|
|
/// Return false if the role already exists.
|
|
|
|
/// @throw QueryRuntimeException if an error ocurred.
|
|
|
|
virtual bool CreateRole(const std::string &rolename) = 0;
|
|
|
|
|
|
|
|
/// Return false if the role does not exist.
|
|
|
|
/// @throw QueryRuntimeException if an error ocurred.
|
|
|
|
virtual bool DropRole(const std::string &rolename) = 0;
|
|
|
|
|
|
|
|
/// @throw QueryRuntimeException if an error ocurred.
|
|
|
|
virtual std::vector<TypedValue> GetUsernames() = 0;
|
|
|
|
|
|
|
|
/// @throw QueryRuntimeException if an error ocurred.
|
|
|
|
virtual std::vector<TypedValue> GetRolenames() = 0;
|
|
|
|
|
|
|
|
/// @throw QueryRuntimeException if an error ocurred.
|
2021-02-18 22:32:43 +08:00
|
|
|
virtual std::optional<std::string> GetRolenameForUser(const std::string &username) = 0;
|
2020-01-15 20:58:41 +08:00
|
|
|
|
|
|
|
/// @throw QueryRuntimeException if an error ocurred.
|
2021-02-18 22:32:43 +08:00
|
|
|
virtual std::vector<TypedValue> GetUsernamesForRole(const std::string &rolename) = 0;
|
2020-01-15 20:58:41 +08:00
|
|
|
|
|
|
|
/// @throw QueryRuntimeException if an error ocurred.
|
2021-02-18 22:32:43 +08:00
|
|
|
virtual void SetRole(const std::string &username, const std::string &rolename) = 0;
|
2020-01-15 20:58:41 +08:00
|
|
|
|
|
|
|
/// @throw QueryRuntimeException if an error ocurred.
|
|
|
|
virtual void ClearRole(const std::string &username) = 0;
|
|
|
|
|
2021-02-18 22:32:43 +08:00
|
|
|
virtual std::vector<std::vector<TypedValue>> GetPrivileges(const std::string &user_or_role) = 0;
|
2020-01-15 20:58:41 +08:00
|
|
|
|
|
|
|
/// @throw QueryRuntimeException if an error ocurred.
|
2022-08-22 20:11:43 +08:00
|
|
|
virtual void GrantPrivilege(
|
2022-09-14 07:10:28 +08:00
|
|
|
const std::string &user_or_role, const std::vector<AuthQuery::Privilege> &privileges
|
|
|
|
#ifdef MG_ENTERPRISE
|
|
|
|
,
|
|
|
|
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
|
2022-08-22 20:11:43 +08:00
|
|
|
&label_privileges,
|
2022-09-14 07:10:28 +08:00
|
|
|
|
|
|
|
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
|
|
|
|
&edge_type_privileges
|
|
|
|
#endif
|
|
|
|
) = 0;
|
2020-01-15 20:58:41 +08:00
|
|
|
|
|
|
|
/// @throw QueryRuntimeException if an error ocurred.
|
2022-09-14 18:39:23 +08:00
|
|
|
virtual void DenyPrivilege(const std::string &user_or_role, const std::vector<AuthQuery::Privilege> &privileges) = 0;
|
2022-08-02 18:51:22 +08:00
|
|
|
|
|
|
|
/// @throw QueryRuntimeException if an error ocurred.
|
2022-08-22 20:11:43 +08:00
|
|
|
virtual void RevokePrivilege(
|
2022-09-14 07:10:28 +08:00
|
|
|
const std::string &user_or_role, const std::vector<AuthQuery::Privilege> &privileges
|
|
|
|
#ifdef MG_ENTERPRISE
|
|
|
|
,
|
|
|
|
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
|
2022-08-22 20:11:43 +08:00
|
|
|
&label_privileges,
|
2022-09-14 07:10:28 +08:00
|
|
|
|
|
|
|
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
|
|
|
|
&edge_type_privileges
|
|
|
|
#endif
|
|
|
|
) = 0;
|
2020-01-15 20:58:41 +08:00
|
|
|
};
|
|
|
|
|
2019-10-30 21:05:47 +08:00
|
|
|
enum class QueryHandlerResult { COMMIT, ABORT, NOTHING };
|
|
|
|
|
2020-10-01 19:58:25 +08:00
|
|
|
class ReplicationQueryHandler {
|
|
|
|
public:
|
|
|
|
ReplicationQueryHandler() = default;
|
2020-12-11 17:47:19 +08:00
|
|
|
virtual ~ReplicationQueryHandler() = default;
|
2020-10-01 19:58:25 +08:00
|
|
|
|
2021-05-27 01:57:08 +08:00
|
|
|
ReplicationQueryHandler(const ReplicationQueryHandler &) = default;
|
|
|
|
ReplicationQueryHandler &operator=(const ReplicationQueryHandler &) = default;
|
2020-12-11 17:47:19 +08:00
|
|
|
|
2021-05-27 01:57:08 +08:00
|
|
|
ReplicationQueryHandler(ReplicationQueryHandler &&) = default;
|
|
|
|
ReplicationQueryHandler &operator=(ReplicationQueryHandler &&) = default;
|
2020-10-01 19:58:25 +08:00
|
|
|
|
|
|
|
struct Replica {
|
|
|
|
std::string name;
|
2020-11-26 17:19:16 +08:00
|
|
|
std::string socket_address;
|
2020-10-01 19:58:25 +08:00
|
|
|
ReplicationQuery::SyncMode sync_mode;
|
|
|
|
std::optional<double> timeout;
|
2022-06-23 16:22:57 +08:00
|
|
|
uint64_t current_timestamp_of_replica;
|
|
|
|
uint64_t current_number_of_timestamp_behind_master;
|
2022-06-20 18:28:42 +08:00
|
|
|
ReplicationQuery::ReplicaState state;
|
2020-10-01 19:58:25 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/// @throw QueryRuntimeException if an error ocurred.
|
2021-02-18 22:32:43 +08:00
|
|
|
virtual void SetReplicationRole(ReplicationQuery::ReplicationRole replication_role, std::optional<int64_t> port) = 0;
|
2020-10-01 19:58:25 +08:00
|
|
|
|
|
|
|
/// @throw QueryRuntimeException if an error ocurred.
|
2020-11-23 21:24:34 +08:00
|
|
|
virtual ReplicationQuery::ReplicationRole ShowReplicationRole() const = 0;
|
2020-10-01 19:58:25 +08:00
|
|
|
|
|
|
|
/// @throw QueryRuntimeException if an error ocurred.
|
2021-02-18 22:32:43 +08:00
|
|
|
virtual void RegisterReplica(const std::string &name, const std::string &socket_address,
|
2022-07-05 15:40:50 +08:00
|
|
|
ReplicationQuery::SyncMode sync_mode,
|
2022-05-21 10:29:17 +08:00
|
|
|
const std::chrono::seconds replica_check_frequency) = 0;
|
2020-10-01 19:58:25 +08:00
|
|
|
|
|
|
|
/// @throw QueryRuntimeException if an error ocurred.
|
2020-12-17 18:25:21 +08:00
|
|
|
virtual void DropReplica(const std::string &replica_name) = 0;
|
2020-10-01 19:58:25 +08:00
|
|
|
|
|
|
|
/// @throw QueryRuntimeException if an error ocurred.
|
|
|
|
virtual std::vector<Replica> ShowReplicas() const = 0;
|
|
|
|
};
|
|
|
|
|
2019-10-17 20:48:04 +08:00
|
|
|
/**
|
|
|
|
* A container for data related to the preparation of a query.
|
|
|
|
*/
|
|
|
|
struct PreparedQuery {
|
|
|
|
std::vector<std::string> header;
|
|
|
|
std::vector<AuthQuery::Privilege> privileges;
|
2021-02-18 22:32:43 +08:00
|
|
|
std::function<std::optional<QueryHandlerResult>(AnyStream *stream, std::optional<int> n)> query_handler;
|
2021-01-19 19:08:38 +08:00
|
|
|
plan::ReadWriteTypeChecker::RWType rw_type;
|
2019-10-17 20:48:04 +08:00
|
|
|
};
|
|
|
|
|
2023-03-27 21:46:00 +08:00
|
|
|
class Interpreter;
|
|
|
|
|
2019-10-23 21:12:12 +08:00
|
|
|
/**
|
|
|
|
* Holds data shared between multiple `Interpreter` instances (which might be
|
|
|
|
* running concurrently).
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
struct InterpreterContext {
|
2021-06-30 17:19:13 +08:00
|
|
|
explicit InterpreterContext(storage::Storage *db, InterpreterConfig config,
|
2021-11-11 19:17:05 +08:00
|
|
|
const std::filesystem::path &data_directory);
|
2019-10-10 17:23:33 +08:00
|
|
|
|
|
|
|
storage::Storage *db;
|
|
|
|
|
[E129-MG <-T0982-MG] implement edge type filtering (#489)
* GRANT, REVOKE, DENY and access_checker DONE
* Added AccessChecker to ExecutionContext
* grammar expanded; (#462)
* current
* T0954 mg expand user and role to hold permissions on labels (#465)
* added FineGrainedAccessPermissions class to model
* expanded user and role with fine grained access permissions
* fixed grammar
* [E129 < T0953-MG] GRANT, DENY, REVOKE added in interpreter and mainVisitor (#464)
* GRANT, DENY, REVOKE added in interpreter and mainVisitor
* Commented labelPermissons
* remove labelsPermission adding
* Fixed
* Removed extra lambda
* fixed
* [E129<-T0955-MG] Expand ExecutionContext with label related information (#467)
* added
* Added FineGrainedAccessChecker to Context
* fixed
* Added filtering
* testing
* Added edge filtering to storage, need to add filtering in simple Expand in operator.cpp
* Removed storage changes
* MATCH filtering working
* EdgeTypeFiltering working, just need to test everything again
* Removed FineGrainedAccessChecker
* Removed Expand Path
* Fix
* Tested FineGrainedAccessHandler, need to test AuthChecker
* Added integration test for lba
* Fixed merge conflicts
* PR fix
* fixed
* PR fix
* Fix test
* removed .vscode, .cache, .githooks
* githooks
* added tests
* fixed build
* Changed ast.lcp and User pointer to value in context.hpp
* Fixed test
* Remove denies on grant all
* AuthChecker
* Pr fix, auth_checker still not fixed
* Create mg-glue and extract UserBasedAuthChecker from AuthChecker
* Build fixed, need to fix test
* e2e tests
* e2e test working
* Added unit test, e2e and FineGrainedChecker
* Mege E129, auth_checker tests
* Fixed test
* e2e fix
Co-authored-by: Boris Taševski <36607228+BorisTasevski@users.noreply.github.com>
Co-authored-by: josipmrden <josip.mrden@external-basf.com>
Co-authored-by: János Benjamin Antal <benjamin.antal@memgraph.io>
2022-08-16 21:57:23 +08:00
|
|
|
// ANTLR has singleton instance that is shared between threads. It is
|
|
|
|
// protected by locks inside of ANTLR. Unfortunately, they are not protected
|
|
|
|
// in a very good way. Once we have ANTLR version without race conditions we
|
|
|
|
// can remove this lock. This will probably never happen since ANTLR
|
|
|
|
// developers introduce more bugs in each version. Fortunately, we have
|
|
|
|
// cache so this lock probably won't impact performance much...
|
|
|
|
utils::SpinLock antlr_lock;
|
2019-11-25 22:08:16 +08:00
|
|
|
std::optional<double> tsc_frequency{utils::GetTSCFrequency()};
|
|
|
|
std::atomic<bool> is_shutting_down{false};
|
2019-10-23 21:12:12 +08:00
|
|
|
|
2020-01-15 20:58:41 +08:00
|
|
|
AuthQueryHandler *auth{nullptr};
|
2022-03-09 22:53:33 +08:00
|
|
|
AuthChecker *auth_checker{nullptr};
|
2019-10-23 21:12:12 +08:00
|
|
|
|
|
|
|
utils::SkipList<QueryCacheEntry> ast_cache;
|
|
|
|
utils::SkipList<PlanCacheEntry> plan_cache;
|
2021-04-15 16:49:40 +08:00
|
|
|
|
2021-06-30 16:01:51 +08:00
|
|
|
TriggerStore trigger_store;
|
2021-05-24 15:31:18 +08:00
|
|
|
utils::ThreadPool after_commit_trigger_pool{1};
|
2021-06-30 17:19:13 +08:00
|
|
|
|
|
|
|
const InterpreterConfig config;
|
2021-06-22 14:43:19 +08:00
|
|
|
|
2022-03-09 22:53:33 +08:00
|
|
|
query::stream::Streams streams;
|
2023-03-27 21:46:00 +08:00
|
|
|
utils::Synchronized<std::unordered_set<Interpreter *>, utils::SpinLock> interpreters;
|
2019-10-23 21:12:12 +08:00
|
|
|
};
|
2019-10-07 23:31:25 +08:00
|
|
|
|
2019-11-25 22:08:16 +08:00
|
|
|
/// Function that is used to tell all active interpreters that they should stop
|
|
|
|
/// their ongoing execution.
|
2021-02-18 22:32:43 +08:00
|
|
|
inline void Shutdown(InterpreterContext *context) { context->is_shutting_down.store(true, std::memory_order_release); }
|
2019-11-25 22:08:16 +08:00
|
|
|
|
2019-10-17 20:48:04 +08:00
|
|
|
class Interpreter final {
|
2019-10-23 21:12:12 +08:00
|
|
|
public:
|
2019-10-07 23:31:25 +08:00
|
|
|
explicit Interpreter(InterpreterContext *interpreter_context);
|
2017-12-22 20:39:31 +08:00
|
|
|
Interpreter(const Interpreter &) = delete;
|
|
|
|
Interpreter &operator=(const Interpreter &) = delete;
|
|
|
|
Interpreter(Interpreter &&) = delete;
|
|
|
|
Interpreter &operator=(Interpreter &&) = delete;
|
2019-10-17 20:48:04 +08:00
|
|
|
~Interpreter() { Abort(); }
|
2019-10-10 17:23:33 +08:00
|
|
|
|
2020-10-16 18:49:33 +08:00
|
|
|
struct PrepareResult {
|
|
|
|
std::vector<std::string> headers;
|
2022-03-09 22:53:33 +08:00
|
|
|
std::vector<query::AuthQuery::Privilege> privileges;
|
2020-10-16 18:49:33 +08:00
|
|
|
std::optional<int> qid;
|
|
|
|
};
|
|
|
|
|
2023-03-27 21:46:00 +08:00
|
|
|
std::optional<std::string> username_;
|
|
|
|
bool in_explicit_transaction_{false};
|
|
|
|
bool expect_rollback_{false};
|
|
|
|
|
2017-12-22 20:39:31 +08:00
|
|
|
/**
|
2019-10-17 20:48:04 +08:00
|
|
|
* Prepare a query for execution.
|
|
|
|
*
|
2020-10-16 18:49:33 +08:00
|
|
|
* Preparing a query means to preprocess the query and save it for
|
|
|
|
* future calls of `Pull`.
|
2019-10-17 20:48:04 +08:00
|
|
|
*
|
2022-03-09 22:53:33 +08:00
|
|
|
* @throw query::QueryException
|
2017-12-22 20:39:31 +08:00
|
|
|
*/
|
2021-07-22 22:22:08 +08:00
|
|
|
PrepareResult Prepare(const std::string &query, const std::map<std::string, storage::PropertyValue> ¶ms,
|
|
|
|
const std::string *username);
|
2019-10-10 17:23:33 +08:00
|
|
|
|
2019-10-17 20:48:04 +08:00
|
|
|
/**
|
|
|
|
* Execute the last prepared query and stream *all* of the results into the
|
|
|
|
* given stream.
|
|
|
|
*
|
2019-10-18 22:27:47 +08:00
|
|
|
* It is not possible to prepare a query once and execute it multiple times,
|
|
|
|
* i.e. `Prepare` has to be called before *every* call to `PullAll`.
|
|
|
|
*
|
2019-10-17 20:48:04 +08:00
|
|
|
* TStream should be a type implementing the `Stream` concept, i.e. it should
|
|
|
|
* contain the member function `void Result(const std::vector<TypedValue> &)`.
|
|
|
|
* The provided vector argument is valid only for the duration of the call to
|
|
|
|
* `Result`. The stream should make an explicit copy if it wants to use it
|
|
|
|
* further.
|
|
|
|
*
|
|
|
|
* @throw utils::BasicException
|
2022-03-09 22:53:33 +08:00
|
|
|
* @throw query::QueryException
|
2019-10-17 20:48:04 +08:00
|
|
|
*/
|
2019-10-10 17:23:33 +08:00
|
|
|
template <typename TStream>
|
2020-10-16 18:49:33 +08:00
|
|
|
std::map<std::string, TypedValue> PullAll(TStream *result_stream) {
|
|
|
|
return Pull(result_stream);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Execute a prepared query and stream result into the given stream.
|
|
|
|
*
|
|
|
|
* TStream should be a type implementing the `Stream` concept, i.e. it should
|
|
|
|
* contain the member function `void Result(const std::vector<TypedValue> &)`.
|
|
|
|
* The provided vector argument is valid only for the duration of the call to
|
|
|
|
* `Result`. The stream should make an explicit copy if it wants to use it
|
|
|
|
* further.
|
|
|
|
*
|
|
|
|
* @param n If set, amount of rows to be pulled from result,
|
|
|
|
* otherwise all the rows are pulled.
|
|
|
|
* @param qid If set, id of the query from which the result should be pulled,
|
|
|
|
* otherwise the last query should be used.
|
|
|
|
*
|
|
|
|
* @throw utils::BasicException
|
2022-03-09 22:53:33 +08:00
|
|
|
* @throw query::QueryException
|
2020-10-16 18:49:33 +08:00
|
|
|
*/
|
|
|
|
template <typename TStream>
|
2021-02-18 22:32:43 +08:00
|
|
|
std::map<std::string, TypedValue> Pull(TStream *result_stream, std::optional<int> n = {},
|
2020-10-16 18:49:33 +08:00
|
|
|
std::optional<int> qid = {});
|
|
|
|
|
|
|
|
void BeginTransaction();
|
|
|
|
|
2023-03-27 21:46:00 +08:00
|
|
|
/*
|
|
|
|
Returns transaction id or empty if the db_accessor is not initialized.
|
|
|
|
*/
|
|
|
|
std::optional<uint64_t> GetTransactionId() const;
|
|
|
|
|
2020-10-16 18:49:33 +08:00
|
|
|
void CommitTransaction();
|
|
|
|
|
|
|
|
void RollbackTransaction();
|
2019-10-10 17:23:33 +08:00
|
|
|
|
2021-06-14 21:47:57 +08:00
|
|
|
void SetNextTransactionIsolationLevel(storage::IsolationLevel isolation_level);
|
|
|
|
void SetSessionIsolationLevel(storage::IsolationLevel isolation_level);
|
|
|
|
|
2023-03-27 21:46:00 +08:00
|
|
|
std::vector<TypedValue> GetQueries();
|
|
|
|
|
2019-10-17 20:48:04 +08:00
|
|
|
/**
|
|
|
|
* Abort the current multicommand transaction.
|
|
|
|
*/
|
2019-10-10 17:23:33 +08:00
|
|
|
void Abort();
|
2017-03-22 23:38:43 +08:00
|
|
|
|
2023-03-27 21:46:00 +08:00
|
|
|
std::atomic<TransactionStatus> transaction_status_{TransactionStatus::IDLE};
|
|
|
|
|
2017-06-08 00:28:31 +08:00
|
|
|
private:
|
2020-10-16 18:49:33 +08:00
|
|
|
struct QueryExecution {
|
|
|
|
std::optional<PreparedQuery> prepared_query;
|
2021-09-30 01:14:39 +08:00
|
|
|
utils::MonotonicBufferResource execution_memory{kExecutionMemoryBlockSize};
|
|
|
|
utils::ResourceWithOutOfMemoryException execution_memory_with_exception{&execution_memory};
|
2021-05-19 00:42:19 +08:00
|
|
|
|
2020-10-16 18:49:33 +08:00
|
|
|
std::map<std::string, TypedValue> summary;
|
2021-11-15 20:51:13 +08:00
|
|
|
std::vector<Notification> notifications;
|
2020-10-16 18:49:33 +08:00
|
|
|
|
|
|
|
explicit QueryExecution() = default;
|
|
|
|
QueryExecution(const QueryExecution &) = delete;
|
|
|
|
QueryExecution(QueryExecution &&) = default;
|
|
|
|
QueryExecution &operator=(const QueryExecution &) = delete;
|
|
|
|
QueryExecution &operator=(QueryExecution &&) = default;
|
|
|
|
|
|
|
|
~QueryExecution() {
|
|
|
|
// We should always release the execution memory AFTER we
|
|
|
|
// destroy the prepared query which is using that instance
|
|
|
|
// of execution memory.
|
|
|
|
prepared_query.reset();
|
2021-09-30 01:14:39 +08:00
|
|
|
execution_memory.Release();
|
2020-10-16 18:49:33 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Interpreter supports multiple prepared queries at the same time.
|
|
|
|
// The client can reference a specific query for pull using an arbitrary qid
|
|
|
|
// which is in our case the index of the query in the vector.
|
|
|
|
// To simplify the handling of the qid we avoid modifying the vector if it
|
|
|
|
// affects the position of the currently running queries in any way.
|
|
|
|
// For example, we cannot delete the prepared query from the vector because
|
|
|
|
// every prepared query after the deleted one will be moved by one place
|
|
|
|
// making their qid not equal to the their index inside the vector.
|
|
|
|
// To avoid this, we use unique_ptr with which we manualy control construction
|
|
|
|
// and deletion of a single query execution, i.e. when a query finishes,
|
|
|
|
// we reset the corresponding unique_ptr.
|
|
|
|
std::vector<std::unique_ptr<QueryExecution>> query_executions_;
|
2023-03-27 21:46:00 +08:00
|
|
|
// all queries that are run as part of the current transaction
|
|
|
|
utils::Synchronized<std::vector<std::string>, utils::SpinLock> transaction_queries_;
|
2020-10-16 18:49:33 +08:00
|
|
|
|
2019-10-07 23:31:25 +08:00
|
|
|
InterpreterContext *interpreter_context_;
|
2018-03-15 22:00:43 +08:00
|
|
|
|
2021-04-23 20:19:42 +08:00
|
|
|
// This cannot be std::optional because we need to move this accessor later on into a lambda capture
|
|
|
|
// which is assigned to std::function. std::function requires every object to be copyable, so we
|
|
|
|
// move this unique_ptr into a shrared_ptr.
|
|
|
|
std::unique_ptr<storage::Storage::Accessor> db_accessor_;
|
2019-10-10 17:23:33 +08:00
|
|
|
std::optional<DbAccessor> execution_db_accessor_;
|
2021-05-13 21:38:48 +08:00
|
|
|
std::optional<TriggerContextCollector> trigger_context_collector_;
|
2019-10-10 17:23:33 +08:00
|
|
|
|
2021-06-14 21:47:57 +08:00
|
|
|
std::optional<storage::IsolationLevel> interpreter_isolation_level;
|
|
|
|
std::optional<storage::IsolationLevel> next_transaction_isolation_level;
|
|
|
|
|
2019-10-30 21:05:47 +08:00
|
|
|
PreparedQuery PrepareTransactionQuery(std::string_view query_upper);
|
2019-10-10 17:23:33 +08:00
|
|
|
void Commit();
|
|
|
|
void AdvanceCommand();
|
2020-10-16 18:49:33 +08:00
|
|
|
void AbortCommand(std::unique_ptr<QueryExecution> *query_execution);
|
2021-06-14 21:47:57 +08:00
|
|
|
std::optional<storage::IsolationLevel> GetIsolationLevelOverride();
|
2020-10-16 18:49:33 +08:00
|
|
|
|
|
|
|
size_t ActiveQueryExecutions() {
|
|
|
|
return std::count_if(query_executions_.begin(), query_executions_.end(),
|
2021-02-18 22:32:43 +08:00
|
|
|
[](const auto &execution) { return execution && execution->prepared_query; });
|
2020-10-16 18:49:33 +08:00
|
|
|
}
|
2017-06-08 00:28:31 +08:00
|
|
|
};
|
2017-04-26 22:12:39 +08:00
|
|
|
|
2023-03-27 21:46:00 +08:00
|
|
|
class TransactionQueueQueryHandler {
|
|
|
|
public:
|
|
|
|
TransactionQueueQueryHandler() = default;
|
|
|
|
virtual ~TransactionQueueQueryHandler() = default;
|
|
|
|
|
|
|
|
TransactionQueueQueryHandler(const TransactionQueueQueryHandler &) = default;
|
|
|
|
TransactionQueueQueryHandler &operator=(const TransactionQueueQueryHandler &) = default;
|
|
|
|
|
|
|
|
TransactionQueueQueryHandler(TransactionQueueQueryHandler &&) = default;
|
|
|
|
TransactionQueueQueryHandler &operator=(TransactionQueueQueryHandler &&) = default;
|
|
|
|
|
|
|
|
static std::vector<std::vector<TypedValue>> ShowTransactions(const std::unordered_set<Interpreter *> &interpreters,
|
|
|
|
const std::optional<std::string> &username,
|
|
|
|
bool hasTransactionManagementPrivilege);
|
|
|
|
|
|
|
|
static std::vector<std::vector<TypedValue>> KillTransactions(
|
|
|
|
InterpreterContext *interpreter_context, const std::vector<std::string> &maybe_kill_transaction_ids,
|
|
|
|
const std::optional<std::string> &username, bool hasTransactionManagementPrivilege);
|
|
|
|
};
|
|
|
|
|
2019-10-17 20:48:04 +08:00
|
|
|
template <typename TStream>
|
2021-02-18 22:32:43 +08:00
|
|
|
std::map<std::string, TypedValue> Interpreter::Pull(TStream *result_stream, std::optional<int> n,
|
2020-10-16 18:49:33 +08:00
|
|
|
std::optional<int> qid) {
|
2021-02-18 22:32:43 +08:00
|
|
|
MG_ASSERT(in_explicit_transaction_ || !qid, "qid can be only used in explicit transaction!");
|
2020-10-16 18:49:33 +08:00
|
|
|
|
2023-03-27 21:46:00 +08:00
|
|
|
const int qid_value = qid ? *qid : static_cast<int>(query_executions_.size() - 1);
|
2020-10-16 18:49:33 +08:00
|
|
|
if (qid_value < 0 || qid_value >= query_executions_.size()) {
|
2021-02-18 22:32:43 +08:00
|
|
|
throw InvalidArgumentsException("qid", "Query with specified ID does not exist!");
|
2020-10-16 18:49:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (n && n < 0) {
|
2021-02-18 22:32:43 +08:00
|
|
|
throw InvalidArgumentsException("n", "Cannot fetch negative number of results!");
|
2020-10-16 18:49:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
auto &query_execution = query_executions_[qid_value];
|
2019-10-17 20:48:04 +08:00
|
|
|
|
2021-02-18 22:32:43 +08:00
|
|
|
MG_ASSERT(query_execution && query_execution->prepared_query, "Query already finished executing!");
|
2020-10-16 18:49:33 +08:00
|
|
|
|
|
|
|
// Each prepared query has its own summary so we need to somehow preserve
|
|
|
|
// it after it finishes executing because it gets destroyed alongside
|
|
|
|
// the prepared query and its execution memory.
|
|
|
|
std::optional<std::map<std::string, TypedValue>> maybe_summary;
|
2019-10-17 20:48:04 +08:00
|
|
|
try {
|
|
|
|
// Wrap the (statically polymorphic) stream type into a common type which
|
|
|
|
// the handler knows.
|
2020-10-16 18:49:33 +08:00
|
|
|
AnyStream stream{result_stream, &query_execution->execution_memory};
|
2021-02-18 22:32:43 +08:00
|
|
|
const auto maybe_res = query_execution->prepared_query->query_handler(&stream, n);
|
2020-10-16 18:49:33 +08:00
|
|
|
// Stream is using execution memory of the query_execution which
|
|
|
|
// can be deleted after its execution so the stream should be cleared
|
|
|
|
// first.
|
|
|
|
stream.~AnyStream();
|
|
|
|
|
|
|
|
// If the query finished executing, we have received a value which tells
|
|
|
|
// us what to do after.
|
|
|
|
if (maybe_res) {
|
|
|
|
// Save its summary
|
|
|
|
maybe_summary.emplace(std::move(query_execution->summary));
|
2021-11-15 20:51:13 +08:00
|
|
|
if (!query_execution->notifications.empty()) {
|
|
|
|
std::vector<TypedValue> notifications;
|
|
|
|
notifications.reserve(query_execution->notifications.size());
|
|
|
|
for (const auto ¬ification : query_execution->notifications) {
|
|
|
|
notifications.emplace_back(notification.ConvertToMap());
|
|
|
|
}
|
|
|
|
maybe_summary->insert_or_assign("notifications", std::move(notifications));
|
|
|
|
}
|
2020-10-16 18:49:33 +08:00
|
|
|
if (!in_explicit_transaction_) {
|
|
|
|
switch (*maybe_res) {
|
|
|
|
case QueryHandlerResult::COMMIT:
|
|
|
|
Commit();
|
|
|
|
break;
|
|
|
|
case QueryHandlerResult::ABORT:
|
|
|
|
Abort();
|
|
|
|
break;
|
|
|
|
case QueryHandlerResult::NOTHING:
|
|
|
|
// The only cases in which we have nothing to do are those where
|
|
|
|
// we're either in an explicit transaction or the query is such that
|
|
|
|
// a transaction wasn't started on a call to `Prepare()`.
|
2021-01-21 22:47:56 +08:00
|
|
|
MG_ASSERT(in_explicit_transaction_ || !db_accessor_);
|
2020-10-16 18:49:33 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
// As the transaction is done we can clear all the executions
|
2021-01-13 02:10:32 +08:00
|
|
|
// NOTE: we cannot clear query_execution inside the Abort and Commit
|
|
|
|
// methods as we will delete summary contained in them which we need
|
|
|
|
// after our query finished executing.
|
2020-10-16 18:49:33 +08:00
|
|
|
query_executions_.clear();
|
2023-03-27 21:46:00 +08:00
|
|
|
transaction_queries_->clear();
|
2020-10-16 18:49:33 +08:00
|
|
|
} else {
|
|
|
|
// We can only clear this execution as some of the queries
|
|
|
|
// in the transaction can be in unfinished state
|
|
|
|
query_execution.reset(nullptr);
|
2019-10-17 20:48:04 +08:00
|
|
|
}
|
|
|
|
}
|
2019-10-30 21:05:47 +08:00
|
|
|
} catch (const ExplicitTransactionUsageException &) {
|
2020-10-16 18:49:33 +08:00
|
|
|
query_execution.reset(nullptr);
|
2019-10-30 21:05:47 +08:00
|
|
|
throw;
|
2019-10-17 20:48:04 +08:00
|
|
|
} catch (const utils::BasicException &) {
|
2021-03-10 02:55:58 +08:00
|
|
|
EventCounter::IncrementCounter(EventCounter::FailedQuery);
|
2020-10-16 18:49:33 +08:00
|
|
|
AbortCommand(&query_execution);
|
2019-10-17 20:48:04 +08:00
|
|
|
throw;
|
|
|
|
}
|
2019-10-18 22:27:47 +08:00
|
|
|
|
2020-10-16 18:49:33 +08:00
|
|
|
if (maybe_summary) {
|
|
|
|
// return the execution summary
|
|
|
|
maybe_summary->insert_or_assign("has_more", false);
|
|
|
|
return std::move(*maybe_summary);
|
|
|
|
}
|
2019-10-17 20:48:04 +08:00
|
|
|
|
2020-10-16 18:49:33 +08:00
|
|
|
// don't return the execution summary as it's not finished
|
|
|
|
return {{"has_more", TypedValue(true)}};
|
|
|
|
}
|
2022-02-22 20:33:45 +08:00
|
|
|
} // namespace memgraph::query
|