userver: userver/storages/postgres/query_queue.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
query_queue.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/storages/postgres/query_queue.hpp
4/// @brief An utility to execute multiple queries in a single network
5/// round-trip.
6
7#include <userver/storages/postgres/options.hpp>
8#include <userver/storages/postgres/query.hpp>
9#include <userver/storages/postgres/result_set.hpp>
10
11#include <userver/storages/postgres/detail/connection_ptr.hpp>
12#include <userver/storages/postgres/detail/query_parameters.hpp>
13
14#include <userver/utils/any_movable.hpp>
15#include <userver/utils/fast_pimpl.hpp>
16
17USERVER_NAMESPACE_BEGIN
18
19namespace storages::postgres {
20
21/// @brief A container to enqueue queries in FIFO order and execute them all
22/// within a single network round-trip.
23///
24/// Acquired from storages::postgres::Cluster, one is expected to `Push`
25/// some queries into the queue and then `Collect` them into vector of results.
26///
27/// From a client point of view `Collect` is transactional: either all the
28/// queries succeed or `Collect` rethrows the first error encountered. However,
29/// this is *NOT* the case for the server: server treats all the provided
30/// queries independently and is likely to execute subsequent queries even
31/// after prior failures.
32///
33/// @warning If an explicit transaction ("BEGIN") or a modifying query is added
34/// into the queue the behavior is unspecified. *Don't do that*.
35///
36/// @note Queries may or may not be sent to the server prior to `Collect` call.
37///
38/// @note Requires both pipelining and prepared statements to be enabled in the
39/// driver, UINVARIANTS (that is, throws in release builds and aborts in debug
40/// ones) that on construction.
41class QueryQueue final {
42 public:
43 QueryQueue(CommandControl default_cc, detail::ConnectionPtr&& conn);
44
45 QueryQueue(QueryQueue&&) noexcept;
46 QueryQueue& operator=(QueryQueue&&) noexcept;
47
48 QueryQueue(const QueryQueue&) = delete;
49 QueryQueue& operator=(const QueryQueue&) = delete;
50
51 ~QueryQueue();
52
53 /// Reserve internal storage to hold this amount of queries.
54 void Reserve(std::size_t size);
55
56 /// Add a query into the queue with specified command-control.
57 /// CommandControl is used as following: 'execute' is used as a timeout for
58 /// preparing the statement (if needed), 'statement' is used as a statement
59 /// timeout for later execution.
60 template <typename... Args>
61 void Push(CommandControl cc, const Query& query, const Args&... args);
62
63 /// Add a query into the queue with default command-control.
64 template <typename... Args>
65 void Push(const Query& query, const Args&... args);
66
67 /// Collect results of all the queued queries, with specified timeout.
68 /// Either returns a vector of N `ResultSet`s, where N is the number of
69 /// queries enqueued, or rethrow the first error encountered, be that a query
70 /// execution error or a timeout.
72
73 /// Collect results of all the queued queries, with default timeout.
74 /// Either returns a vector of N `ResultSet`s, where N is the number of
75 /// queries enqueued, or rethrow the first error encountered, be that a query
76 /// execution error or a timeout.
77 [[nodiscard]] std::vector<ResultSet> Collect();
78
79 private:
80 struct ParamsHolder final {
81 // We only need to know what's here at construction (and at construction we
82 // do know), after that we just need to preserve lifetime.
83 USERVER_NAMESPACE::utils::AnyMovable any_params{};
84 // This here knows what's there actually is in params.
85 detail::QueryParameters params_proxy;
86 };
87
88 const UserTypes& GetConnectionUserTypes() const;
89
90 void DoPush(CommandControl cc, const Query& query, ParamsHolder&& params);
91
92 void ValidateUsage() const;
93
94 CommandControl default_cc_;
95 detail::ConnectionPtr conn_;
96
97 struct QueriesStorage;
98 USERVER_NAMESPACE::utils::FastPimpl<QueriesStorage, 48, 8> queries_storage_;
99};
100
101template <typename... Args>
102void QueryQueue::Push(CommandControl cc, const Query& query,
103 const Args&... args) {
104 ParamsHolder holder{};
105 auto& params = holder.any_params
106 .Emplace<detail::StaticQueryParameters<sizeof...(args)>>();
107 params.Write(GetConnectionUserTypes(), args...);
108 holder.params_proxy = detail::QueryParameters{params};
109 DoPush(cc, query, std::move(holder));
110}
111
112template <typename... Args>
113void QueryQueue::Push(const Query& query, const Args&... args) {
114 Push(default_cc_, query, args...);
115}
116
117} // namespace storages::postgres
118
119USERVER_NAMESPACE_END