userver
C++ Async Framework
Toggle main menu visibility
Loading...
Searching...
No Matches
transaction.hpp
Go to the documentation of this file.
1
#
pragma
once
2
3
/// @file userver/storages/postgres/transaction.hpp
4
/// @brief @copybrief storages::postgres::Transaction
5
6
#
include
<
memory
>
7
#
include
<
string
>
8
#
include
<
string_view
>
9
10
#
include
<
userver
/
storages
/
postgres
/
detail
/
connection_ptr
.
hpp
>
11
#
include
<
userver
/
storages
/
postgres
/
detail
/
query_parameters
.
hpp
>
12
#
include
<
userver
/
storages
/
postgres
/
detail
/
time_types
.
hpp
>
13
#
include
<
userver
/
storages
/
postgres
/
options
.
hpp
>
14
#
include
<
userver
/
storages
/
postgres
/
parameter_store
.
hpp
>
15
#
include
<
userver
/
storages
/
postgres
/
portal
.
hpp
>
16
#
include
<
userver
/
storages
/
postgres
/
postgres_fwd
.
hpp
>
17
#
include
<
userver
/
storages
/
postgres
/
query
.
hpp
>
18
#
include
<
userver
/
storages
/
postgres
/
result_set
.
hpp
>
19
#
include
<
userver
/
utils
/
trx_tracker
.
hpp
>
20
21
USERVER_NAMESPACE_BEGIN
22
23
namespace
storages::
postgres
{
24
25
/// @brief PostgreSQL transaction.
26
///
27
/// RAII wrapper for running transactions on PostgreSQL connections. Should be
28
/// retrieved by calling storages::postgres::Cluster::Begin().
29
///
30
/// Non-copyable.
31
///
32
/// If the transaction is not explicitly finished (either committed or rolled back)
33
/// it will roll itself back in the destructor.
34
///
35
/// @par Usage synopsis
36
/// @code
37
/// auto trx = someCluster.Begin(/* transaction options */);
38
/// auto res = trx.Execute("select col1, col2 from schema.table");
39
/// DoSomething(res);
40
/// res = trx.Execute("update schema.table set col1 = $1 where col2 = $2", v1, v2);
41
/// // If in the above lines an exception is thrown, then the transaction is
42
/// // rolled back in the destructor of trx.
43
/// trx.Commit();
44
/// @endcode
45
class
Transaction
{
46
public
:
47
//@{
48
/** @name Shortcut transaction options constants */
49
/// Read-write read committed transaction
50
static
constexpr
TransactionOptions
RW
{};
// NOLINT(readability-identifier-naming)
51
/// Read-only read committed transaction
52
static
constexpr
TransactionOptions
RO
{
TransactionOptions
::kReadOnly};
// NOLINT(readability-identifier-naming)
53
/// Read-only serializable deferrable transaction
54
// clang-format off
55
static
constexpr
TransactionOptions
Deferrable
{
// NOLINT(readability-identifier-naming)
56
TransactionOptions
::
Deferrable
(
)
57
};
58
/// Read-write repeatable read transaction
59
static
constexpr
TransactionOptions
RepeatableReadRW
{
// NOLINT(readability-identifier-naming)
60
storages
::
postgres
::
IsolationLevel
::
kRepeatableRead
61
};
62
/// Read-write serializable transaction
63
static
constexpr
TransactionOptions
SerializableRW
{
// NOLINT(readability-identifier-naming)
64
storages
::
postgres
::
IsolationLevel
::
kSerializable
65
};
66
/// Read-only repeatable read transaction
67
static
constexpr
TransactionOptions
RepeatableReadRO
{
// NOLINT(readability-identifier-naming)
68
storages
::
postgres
::
IsolationLevel
::
kRepeatableRead
,
69
TransactionOptions
::kReadOnly
70
};
71
/// Read-only serializable transaction
72
static
constexpr
TransactionOptions
SerializableRO
{
// NOLINT(readability-identifier-naming)
73
storages
::
postgres
::
IsolationLevel
::
kSerializable
,
74
TransactionOptions
::kReadOnly
75
};
76
// clang-format on
77
//@}
78
79
static
constexpr
std::size_t kDefaultRowsInChunk = 1024;
80
81
/// @cond
82
explicit
Transaction(
83
detail::ConnectionPtr&& conn,
84
const
TransactionOptions
& =
RW
,
85
OptionalCommandControl
trx_cmd_ctl = {},
86
detail::SteadyClock::time_point trx_start_time = detail::SteadyClock::now()
87
);
88
89
void
SetName(std::string name);
90
/// @endcond
91
92
Transaction(
Transaction
&&)
noexcept
;
93
Transaction
& operator=(
Transaction
&&)
noexcept
;
94
95
Transaction(
const
Transaction
&) =
delete
;
96
Transaction
& operator=(
const
Transaction
&) =
delete
;
97
98
~Transaction();
99
/// @name Query execution
100
/// @{
101
/// Execute statement with arbitrary parameters.
102
///
103
/// Suspends coroutine for execution.
104
///
105
/// @note You may write a query in `.sql` file and generate a header file with Query from it.
106
/// See @ref scripts/docs/en/userver/sql_files.md for more information.
107
///
108
/// @snippet storages/postgres/tests/landing_test.cpp TransacExec
109
template
<
typename
... Args>
110
ResultSet
Execute(
const
Query& query,
const
Args&... args) {
111
return
Execute(
OptionalCommandControl
{}, query, args...);
112
}
113
114
/// Execute statement with arbitrary parameters and per-statement command
115
/// control.
116
///
117
/// Suspends coroutine for execution.
118
///
119
/// @note You may write a query in `.sql` file and generate a header file with Query from it.
120
/// See @ref scripts/docs/en/userver/sql_files.md for more information.
121
///
122
/// @warning Do NOT create a query string manually by embedding arguments!
123
/// It leads to vulnerabilities and bad performance. Either pass arguments
124
/// separately, or use storages::postgres::ParameterScope.
125
template
<
typename
... Args>
126
ResultSet
Execute
(
OptionalCommandControl
statement_cmd_ctl,
const
Query& query,
const
Args&... args) {
127
detail::StaticQueryParameters<
sizeof
...(args)> params;
128
params.Write(GetConnectionUserTypes(), args...);
129
return
DoExecute(query, detail::QueryParameters{params}, statement_cmd_ctl);
130
}
131
132
/// Execute statement with stored parameters.
133
///
134
/// Suspends coroutine for execution.
135
///
136
/// @note You may write a query in `.sql` file and generate a header file with Query from it.
137
/// See @ref scripts/docs/en/userver/sql_files.md for more information.
138
///
139
/// @warning Do NOT create a query string manually by embedding arguments!
140
/// It leads to vulnerabilities and bad performance. Either pass arguments
141
/// separately, or use storages::postgres::ParameterScope.
142
ResultSet
Execute
(
const
Query& query,
const
ParameterStore
& store) {
143
return
Execute
(
OptionalCommandControl
{}
,
query
,
store
)
;
144
}
145
146
/// Execute statement with stored parameters and per-statement command
147
/// control.
148
///
149
/// Suspends coroutine for execution.
150
///
151
/// @note You may write a query in `.sql` file and generate a header file with Query from it.
152
/// See @ref scripts/docs/en/userver/sql_files.md for more information.
153
///
154
/// @warning Do NOT create a query string manually by embedding arguments!
155
/// It leads to vulnerabilities and bad performance. Either pass arguments
156
/// separately, or use storages::postgres::ParameterScope.
157
ResultSet
Execute
(
OptionalCommandControl
statement_cmd_ctl,
const
Query& query,
const
ParameterStore
& store);
158
159
/// Execute statement that uses an array of arguments transforming that array
160
/// into N arrays of corresponding fields and executing the statement
161
/// with these arrays values.
162
/// Basically, a column-wise Execute.
163
///
164
/// Useful for statements that unnest their arguments to avoid the need to
165
/// increase timeouts due to data amount growth, but providing an explicit
166
/// mapping from `Container::value_type` to PG type is infeasible for some
167
/// reason (otherwise, use Execute).
168
///
169
/// @note You may write a query in `.sql` file and generate a header file with Query from it.
170
/// See @ref scripts/docs/en/userver/sql_files.md for more information.
171
///
172
/// @snippet storages/postgres/tests/arrays_pgtest.cpp ExecuteDecomposeTrx
173
template
<
typename
Container>
174
ResultSet
ExecuteDecompose
(
const
Query& query,
const
Container& args);
175
176
/// Execute statement that uses an array of arguments transforming that array
177
/// into N arrays of corresponding fields and executing the statement
178
/// with these arrays values.
179
/// Basically, a column-wise Execute.
180
///
181
/// Useful for statements that unnest their arguments to avoid the need to
182
/// increase timeouts due to data amount growth, but providing an explicit
183
/// mapping from `Container::value_type` to PG type is infeasible for some
184
/// reason (otherwise, use Execute).
185
///
186
/// @note You may write a query in `.sql` file and generate a header file with Query from it.
187
/// See @ref scripts/docs/en/userver/sql_files.md for more information.
188
///
189
/// @snippet storages/postgres/tests/arrays_pgtest.cpp ExecuteDecomposeTrx
190
template
<
typename
Container>
191
ResultSet
ExecuteDecompose
(
OptionalCommandControl
statement_cmd_ctl,
const
Query& query,
const
Container& args);
192
193
/// Execute statement that uses an array of arguments splitting that array in
194
/// chunks and executing the statement with a chunk of arguments.
195
///
196
/// Useful for statements that unnest their arguments to avoid the need to
197
/// increase timeouts due to data amount growth.
198
///
199
/// @note You may write a query in `.sql` file and generate a header file with Query from it.
200
/// See @ref scripts/docs/en/userver/sql_files.md for more information.
201
template
<
typename
Container>
202
void
ExecuteBulk
(
const
Query& query,
const
Container& args, std::size_t chunk_rows = kDefaultRowsInChunk);
203
204
/// Execute statement that uses an array of arguments splitting that array in
205
/// chunks and executing the statement with a chunk of arguments.
206
///
207
/// Useful for statements that unnest their arguments to avoid the need to
208
/// increase timeouts due to data amount growth.
209
///
210
/// @note You may write a query in `.sql` file and generate a header file with Query from it.
211
/// See @ref scripts/docs/en/userver/sql_files.md for more information.
212
template
<
typename
Container>
213
void
ExecuteBulk
(
214
OptionalCommandControl
statement_cmd_ctl,
215
const
Query& query,
216
const
Container& args,
217
std::size_t chunk_rows = kDefaultRowsInChunk
218
);
219
220
/// Execute statement that uses an array of arguments transforming that array
221
/// into N arrays of corresponding fields and executing the statement
222
/// with a chunk of each of these arrays values.
223
/// Basically, a column-wise ExecuteBulk.
224
///
225
/// Useful for statements that unnest their arguments to avoid the need to
226
/// increase timeouts due to data amount growth, but providing an explicit
227
/// mapping from `Container::value_type` to PG type is infeasible for some
228
/// reason (otherwise, use ExecuteBulk).
229
///
230
/// @note You may write a query in `.sql` file and generate a header file with Query from it.
231
/// See @ref scripts/docs/en/userver/sql_files.md for more information.
232
///
233
/// @snippet storages/postgres/tests/arrays_pgtest.cpp ExecuteDecomposeBulk
234
template
<
typename
Container>
235
void
ExecuteDecomposeBulk
(
const
Query& query,
const
Container& args, std::size_t chunk_rows = kDefaultRowsInChunk);
236
237
/// Execute statement that uses an array of arguments transforming that array
238
/// into N arrays of corresponding fields and executing the statement
239
/// with a chunk of each of these arrays values.
240
/// Basically, a column-wise ExecuteBulk.
241
///
242
/// Useful for statements that unnest their arguments to avoid the need to
243
/// increase timeouts due to data amount growth, but providing an explicit
244
/// mapping from `Container::value_type` to PG type is infeasible for some
245
/// reason (otherwise, use ExecuteBulk).
246
///
247
/// @note You may write a query in `.sql` file and generate a header file with Query from it.
248
/// See @ref scripts/docs/en/userver/sql_files.md for more information.
249
///
250
/// @snippet storages/postgres/tests/arrays_pgtest.cpp ExecuteDecomposeBulk
251
template
<
typename
Container>
252
void
ExecuteDecomposeBulk
(
253
OptionalCommandControl
statement_cmd_ctl,
254
const
Query& query,
255
const
Container& args,
256
std::size_t chunk_rows = kDefaultRowsInChunk
257
);
258
259
/// @brief Create a portal for fetching results of a statement with arbitrary
260
/// parameters.
261
///
262
/// @note You may write a query in `.sql` file and generate a header file with Query from it.
263
/// See @ref scripts/docs/en/userver/sql_files.md for more information.
264
template
<
typename
... Args>
265
Portal
MakePortal
(
const
Query& query,
const
Args&... args) {
266
return
MakePortal(
OptionalCommandControl
{}, query, args...);
267
}
268
269
/// @brief Create a portal for fetching results of a statement with arbitrary
270
/// parameters and per-statement command control.
271
///
272
/// @note You may write a query in `.sql` file and generate a header file with Query from it.
273
/// See @ref scripts/docs/en/userver/sql_files.md for more information.
274
template
<
typename
... Args>
275
Portal
MakePortal
(
OptionalCommandControl
statement_cmd_ctl,
const
Query& query,
const
Args&... args) {
276
detail::StaticQueryParameters<
sizeof
...(args)> params;
277
params.Write(GetConnectionUserTypes(), args...);
278
return
MakePortal(PortalName{}, query, detail::QueryParameters{params}, statement_cmd_ctl);
279
}
280
281
/// @brief Create a portal for fetching results of a statement with stored
282
/// parameters.
283
///
284
/// @note You may write a query in `.sql` file and generate a header file with Query from it.
285
/// See @ref scripts/docs/en/userver/sql_files.md for more information.
286
Portal
MakePortal
(
const
Query& query,
const
ParameterStore
& store) {
287
return
MakePortal
(
OptionalCommandControl
{}
,
query
,
store
)
;
288
}
289
290
/// @brief Create a portal for fetching results of a statement with stored parameters
291
/// and per-statement command control.
292
///
293
/// @note You may write a query in `.sql` file and generate a header file with Query from it.
294
/// See @ref scripts/docs/en/userver/sql_files.md for more information.
295
Portal
MakePortal
(
OptionalCommandControl
statement_cmd_ctl,
const
Query& query,
const
ParameterStore
& store);
296
297
/// Set a connection parameter
298
/// https://www.postgresql.org/docs/current/sql-set.html
299
/// The parameter is set for this transaction only
300
void
SetParameter
(std::string_view param_name, std::string_view value);
301
//@}
302
303
/// Commit the transaction
304
/// Suspends coroutine until command complete.
305
/// After Commit or Rollback is called, the transaction is not usable any
306
/// more.
307
void
Commit
();
308
/// Rollback the transaction
309
/// Suspends coroutine until command complete.
310
/// After Commit or Rollback is called, the transaction is not usable any
311
/// more.
312
void
Rollback
();
313
314
/// Used in tests
315
OptionalCommandControl
GetConnTransactionCommandControlDebug
()
const
;
316
TimeoutDuration GetConnStatementTimeoutDebug()
const
;
317
318
private
:
319
ResultSet
DoExecute(
320
const
Query& query,
321
const
detail::QueryParameters& params,
322
OptionalCommandControl
statement_cmd_ctl
323
);
324
Portal
MakePortal(
325
const
PortalName&,
326
const
Query& query,
327
const
detail::QueryParameters& params,
328
OptionalCommandControl
statement_cmd_ctl
329
);
330
331
const
UserTypes
& GetConnectionUserTypes()
const
;
332
333
std::string name_;
334
detail::ConnectionPtr conn_;
335
USERVER_NAMESPACE::
utils
::
trx_tracker
::TransactionLock trx_lock_;
336
};
337
338
template
<
typename
Container>
339
ResultSet
Transaction
::
ExecuteDecompose
(
const
Query& query,
const
Container& args) {
340
return
io
::DecomposeContainerByColumns(args).Perform([&query,
this
](
const
auto
&... args) {
341
return
this
->Execute(query, args...);
342
});
343
}
344
345
template
<
typename
Container>
346
ResultSet
Transaction
::
ExecuteDecompose
(
347
OptionalCommandControl
statement_cmd_ctl,
348
const
Query& query,
349
const
Container& args
350
) {
351
return
io
::DecomposeContainerByColumns(args).Perform([&query, &statement_cmd_ctl,
this
](
const
auto
&... args) {
352
return
this
->Execute(statement_cmd_ctl, query, args...);
353
});
354
}
355
356
template
<
typename
Container>
357
void
Transaction
::
ExecuteBulk
(
const
Query& query,
const
Container& args, std::size_t chunk_rows) {
358
auto
split =
io
::SplitContainer(args, chunk_rows);
359
for
(
auto
&& chunk : split) {
360
Execute(query, chunk);
361
}
362
}
363
364
template
<
typename
Container>
365
void
Transaction
::
ExecuteBulk
(
366
OptionalCommandControl
statement_cmd_ctl,
367
const
Query& query,
368
const
Container& args,
369
std::size_t chunk_rows
370
) {
371
auto
split =
io
::SplitContainer(args, chunk_rows);
372
for
(
auto
&& chunk : split) {
373
Execute(statement_cmd_ctl, query, chunk);
374
}
375
}
376
377
template
<
typename
Container>
378
void
Transaction
::
ExecuteDecomposeBulk
(
const
Query& query,
const
Container& args, std::size_t chunk_rows) {
379
io
::SplitContainerByColumns(args, chunk_rows).Perform([&query,
this
](
const
auto
&... args) {
380
this
->Execute(query, args...);
381
});
382
}
383
384
template
<
typename
Container>
385
void
Transaction
::
ExecuteDecomposeBulk
(
386
OptionalCommandControl
statement_cmd_ctl,
387
const
Query& query,
388
const
Container& args,
389
std::size_t chunk_rows
390
) {
391
io
::SplitContainerByColumns(args, chunk_rows).Perform([&query, &statement_cmd_ctl,
this
](
const
auto
&... args) {
392
this
->Execute(statement_cmd_ctl, query, args...);
393
});
394
}
395
396
}
// namespace storages::postgres
397
398
USERVER_NAMESPACE_END
userver
storages
postgres
transaction.hpp
Generated on
for userver by
Doxygen
1.17.0