libpqxx 7.7.0
transaction_base.hxx
1/* Common code and definitions for the transaction classes.
2 *
3 * pqxx::transaction_base defines the interface for any abstract class that
4 * represents a database transaction.
5 *
6 * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/transaction_base instead.
7 *
8 * Copyright (c) 2000-2022, Jeroen T. Vermeulen.
9 *
10 * See COPYING for copyright license. If you did not receive a file called
11 * COPYING with this source code, please notify the distributor of this
12 * mistake, or contact the author.
13 */
14#ifndef PQXX_H_TRANSACTION_BASE
15#define PQXX_H_TRANSACTION_BASE
16
17#include <string_view>
18#include <utility>
19
20/* End-user programs need not include this file, unless they define their own
21 * transaction classes. This is not something the typical program should want
22 * to do.
23 *
24 * However, reading this file is worthwhile because it defines the public
25 * interface for the available transaction classes such as transaction and
26 * nontransaction.
27 */
28
29#include "pqxx/connection.hxx"
30#include "pqxx/internal/concat.hxx"
31#include "pqxx/internal/encoding_group.hxx"
32#include "pqxx/isolation.hxx"
33#include "pqxx/result.hxx"
34#include "pqxx/row.hxx"
35#include "pqxx/stream_from.hxx"
36
38{
39class transaction_subtransaction;
40class transaction_sql_cursor;
41class transaction_stream_to;
42class transaction_transaction_focus;
43} // namespace pqxx::internal::gate
44
45
46namespace pqxx
47{
48using namespace std::literals;
49
50
51class transaction_focus;
52
53
67
72class PQXX_LIBEXPORT PQXX_NOVTABLE transaction_base
73{
74public:
75 transaction_base() = delete;
80
81 virtual ~transaction_base() = 0;
82
84
97 void commit();
98
100
103 void abort();
104
116 template<typename... ARGS> [[nodiscard]] auto esc(ARGS &&...args) const
117 {
118 return conn().esc(std::forward<ARGS>(args)...);
119 }
120
122
133 template<typename... ARGS> [[nodiscard]] auto esc_raw(ARGS &&...args) const
134 {
135 return conn().esc_raw(std::forward<ARGS>(args)...);
136 }
137
139
142 [[nodiscard, deprecated("Use unesc_bin() instead.")]] std::string
143 unesc_raw(zview text) const
144 {
145#include "pqxx/internal/ignore-deprecated-pre.hxx"
146 return conn().unesc_raw(text);
147#include "pqxx/internal/ignore-deprecated-post.hxx"
148 }
149
151
154 [[nodiscard]] std::basic_string<std::byte> unesc_bin(zview text)
155 {
156 return conn().unesc_bin(text);
157 }
158
160
163 [[nodiscard, deprecated("Use unesc_bin() instead.")]] std::string
164 unesc_raw(char const *text) const
165 {
166#include "pqxx/internal/ignore-deprecated-pre.hxx"
167 return conn().unesc_raw(text);
168#include "pqxx/internal/ignore-deprecated-post.hxx"
169 }
170
172
175 [[nodiscard]] std::basic_string<std::byte> unesc_bin(char const text[])
176 {
177 return conn().unesc_bin(text);
178 }
179
181
182 template<typename T> [[nodiscard]] std::string quote(T const &t) const
183 {
184 return conn().quote(t);
185 }
186
187 [[deprecated(
188 "Use std::basic_string<std::byte> instead of binarystring.")]] std::string
189 quote(binarystring const &t) const
190 {
191 return conn().quote(t.bytes_view());
192 }
193
195 [[deprecated("Use quote(std::basic_string_view<std::byte>).")]] std::string
196 quote_raw(unsigned char const bin[], std::size_t len) const
197 {
198 return quote(binary_cast(bin, len));
199 }
200
202 [[deprecated("Use quote(std::basic_string_view<std::byte>).")]] std::string
203 quote_raw(zview bin) const;
204
205#if defined(PQXX_HAVE_CONCEPTS)
207
208 template<binary DATA>
209 [[nodiscard]] std::string quote_raw(DATA const &data) const
210 {
211 return conn().quote_raw(data);
212 }
213#endif
214
216 [[nodiscard]] std::string quote_name(std::string_view identifier) const
217 {
218 return conn().quote_name(identifier);
219 }
220
222 [[nodiscard]] std::string
223 esc_like(std::string_view bin, char escape_char = '\\') const
224 {
225 return conn().esc_like(bin, escape_char);
226 }
228
248
250
255 result
256 exec(std::string_view query, std::string_view desc = std::string_view{});
257
259
265 std::stringstream const &query, std::string_view desc = std::string_view{})
266 {
267 return exec(query.str(), desc);
268 }
269
271
276 result exec0(zview query, std::string_view desc = std::string_view{})
277 {
278 return exec_n(0, query, desc);
279 }
280
282
288 row exec1(zview query, std::string_view desc = std::string_view{})
289 {
290 return exec_n(1, query, desc).front();
291 }
292
294
299 result exec_n(
300 result::size_type rows, zview query,
301 std::string_view desc = std::string_view{});
302
304
307 template<typename TYPE>
308 TYPE query_value(zview query, std::string_view desc = std::string_view{})
309 {
310 row const r{exec1(query, desc)};
311 if (std::size(r) != 1)
312 throw usage_error{internal::concat(
313 "Queried single value from result with ", std::size(r), " columns.")};
314 return r[0].as<TYPE>();
315 }
316
318
366 template<typename... TYPE>
367 [[nodiscard]] auto stream(std::string_view query) &
368 {
369 // Tricky: std::make_unique() supports constructors but not RVO functions.
370 return pqxx::internal::owning_stream_input_iteration<TYPE...>{
371 std::unique_ptr<stream_from>{
372 new stream_from{stream_from::query(*this, query)}}};
373 }
374
405 template<typename... Args> result exec_params(zview query, Args &&...args)
406 {
407 params pp(args...);
408 return internal_exec_params(query, pp.make_c_params());
409 }
410
411 // Execute parameterised statement, expect a single-row result.
414 template<typename... Args> row exec_params1(zview query, Args &&...args)
415 {
416 return exec_params_n(1, query, std::forward<Args>(args)...).front();
417 }
418
419 // Execute parameterised statement, expect a result with zero rows.
422 template<typename... Args> result exec_params0(zview query, Args &&...args)
423 {
424 return exec_params_n(0, query, std::forward<Args>(args)...);
425 }
426
427 // Execute parameterised statement, expect exactly a given number of rows.
430 template<typename... Args>
431 result exec_params_n(std::size_t rows, zview query, Args &&...args)
432 {
433 auto const r{exec_params(query, std::forward<Args>(args)...)};
434 check_rowcount_params(rows, std::size(r));
435 return r;
436 }
438
470
472 template<typename... Args>
473 result exec_prepared(zview statement, Args &&...args)
474 {
475 params pp(args...);
476 return internal_exec_prepared(statement, pp.make_c_params());
477 }
478
480
482 template<typename... Args>
483 row exec_prepared1(zview statement, Args &&...args)
484 {
485 return exec_prepared_n(1, statement, std::forward<Args>(args)...).front();
486 }
487
489
491 template<typename... Args>
492 result exec_prepared0(zview statement, Args &&...args)
493 {
494 return exec_prepared_n(0, statement, std::forward<Args>(args)...);
495 }
496
498
501 template<typename... Args>
502 result
503 exec_prepared_n(result::size_type rows, zview statement, Args &&...args)
504 {
505 auto const r{exec_prepared(statement, std::forward<Args>(args)...)};
506 check_rowcount_prepared(statement, rows, std::size(r));
507 return r;
508 }
509
511
517 void process_notice(char const msg[]) const { m_conn.process_notice(msg); }
519 void process_notice(zview msg) const { m_conn.process_notice(msg); }
521
523 [[nodiscard]] connection &conn() const { return m_conn; }
524
526
536 void set_variable(std::string_view var, std::string_view value);
537
539
542 std::string get_variable(std::string_view);
543
545 [[nodiscard]] std::string_view name() const &noexcept { return m_name; }
546
547protected:
549
553 connection &c, std::string_view tname,
554 std::shared_ptr<std::string> rollback_cmd) :
555 m_conn{c}, m_name{tname}, m_rollback_cmd{rollback_cmd}
556 {}
557
559
564 transaction_base(connection &c, std::string_view tname);
565
567 explicit transaction_base(connection &c);
568
570 void register_transaction();
571
573 void close() noexcept;
574
576 virtual void do_commit() = 0;
577
579
582 virtual void do_abort();
583
585 void set_rollback_cmd(std::shared_ptr<std::string> cmd)
586 {
587 m_rollback_cmd = cmd;
588 }
589
591 result direct_exec(std::string_view, std::string_view desc = ""sv);
592 result
593 direct_exec(std::shared_ptr<std::string>, std::string_view desc = ""sv);
594
595private:
596 enum class status
597 {
598 active,
599 aborted,
600 committed,
601 in_doubt
602 };
603
604 PQXX_PRIVATE void check_pending_error();
605
606 template<typename T> bool parm_is_null(T *p) const noexcept
607 {
608 return p == nullptr;
609 }
610 template<typename T> bool parm_is_null(T) const noexcept { return false; }
611
612 result
613 internal_exec_prepared(zview statement, internal::c_params const &args);
614
615 result internal_exec_params(zview query, internal::c_params const &args);
616
618 void check_rowcount_prepared(
619 zview statement, result::size_type expected_rows,
620 result::size_type actual_rows);
621
623 void
624 check_rowcount_params(std::size_t expected_rows, std::size_t actual_rows);
625
627 [[nodiscard]] std::string description() const;
628
629 friend class pqxx::internal::gate::transaction_transaction_focus;
630 PQXX_PRIVATE void register_focus(transaction_focus *);
631 PQXX_PRIVATE void unregister_focus(transaction_focus *) noexcept;
632 PQXX_PRIVATE void register_pending_error(zview) noexcept;
633 PQXX_PRIVATE void register_pending_error(std::string &&) noexcept;
634
635 connection &m_conn;
636
638
641 transaction_focus const *m_focus = nullptr;
642
643 status m_status = status::active;
644 bool m_registered = false;
645 std::string m_name;
646 std::string m_pending_error;
647
649 std::shared_ptr<std::string> m_rollback_cmd;
650
651 // C++20: constinit.
652 static constexpr std::string_view s_type_name{"transaction"sv};
653};
654
655
656// C++20: Can borrowed_range help?
658template<>
659std::string_view transaction_base::query_value<std::string_view>(
660 zview query, std::string_view desc) = delete;
662template<>
663zview transaction_base::query_value<zview>(
664 zview query, std::string_view desc) = delete;
665
666} // namespace pqxx
667
668
669namespace pqxx::internal
670{
672template<pqxx::isolation_level isolation, pqxx::write_policy rw>
673extern const zview begin_cmd;
674
675// C++20: constinit.
676// These are not static members, so "constexpr" does not imply "inline".
677template<>
678inline constexpr zview begin_cmd<read_committed, write_policy::read_write>{
679 "BEGIN"_zv};
680template<>
681inline constexpr zview begin_cmd<read_committed, write_policy::read_only>{
682 "BEGIN READ ONLY"_zv};
683template<>
684inline constexpr zview begin_cmd<repeatable_read, write_policy::read_write>{
685 "BEGIN ISOLATION LEVEL REPEATABLE READ"_zv};
686template<>
687inline constexpr zview begin_cmd<repeatable_read, write_policy::read_only>{
688 "BEGIN ISOLATION LEVEL REPEATABLE READ READ ONLY"_zv};
689template<>
690inline constexpr zview begin_cmd<serializable, write_policy::read_write>{
691 "BEGIN ISOLATION LEVEL SERIALIZABLE"_zv};
692template<>
693inline constexpr zview begin_cmd<serializable, write_policy::read_only>{
694 "BEGIN ISOLATION LEVEL SERIALIZABLE READ ONLY"_zv};
695} // namespace pqxx::internal
696#endif
auto esc(ARGS &&...args) const
Escape string for use as SQL string literal in this transaction.
Definition: transaction_base.hxx:116
The home of all libpqxx classes, functions, templates, etc.
Definition: array.hxx:23
std::basic_string_view< std::byte > binary_cast(TYPE const &data)
Cast binary data to a type that libpqxx will recognise as binary.
Definition: util.hxx:289
Internal items for libpqxx' own use. Do not use these yourself.
Definition: composite.hxx:80
const zview begin_cmd
The SQL command for starting a given type of transaction.
Definition: connection.hxx:95
Binary data corresponding to PostgreSQL's "BYTEA" binary-string type.
Definition: binarystring.hxx:55
std::basic_string_view< std::byte > bytes_view() const
Read data as a std::basic_string_view<std::byte>.
Definition: binarystring.hxx:174
Connection to a database.
Definition: connection.hxx:181
Build a parameter list for a parameterised or prepared statement.
Definition: params.hxx:214
pqxx::internal::c_params make_c_params() const
For internal use: Generate a params object for use in calls.
Definition: params.cxx:92
Result set containing data returned by a query or command.
Definition: result.hxx:68
result_size_type size_type
Definition: result.hxx:70
Reference to one row in a result.
Definition: row.hxx:43
std::tuple< TYPE... > as() const
Definition: row.hxx:181
reference front() const noexcept
Definition: row.cxx:55
Stream data from the database.
Definition: stream_from.hxx:72
Interface definition (and common code) for "transaction" classes.
Definition: transaction_base.hxx:73
result exec_prepared(zview statement, Args &&...args)
Execute a prepared statement, with optional arguments.
Definition: transaction_base.hxx:473
std::basic_string< std::byte > unesc_bin(zview text)
Unescape binary data, e.g. from a table field or notification payload.
Definition: transaction_base.hxx:154
row exec1(zview query, std::string_view desc=std::string_view{})
Execute command returning a single row of data.
Definition: transaction_base.hxx:288
void process_notice(zview msg) const
Have connection process a warning message.
Definition: transaction_base.hxx:519
std::string unesc_raw(char const *text) const
Unescape binary data, e.g. from a table field or notification payload.
Definition: transaction_base.hxx:164
result exec_prepared_n(result::size_type rows, zview statement, Args &&...args)
Execute a prepared statement, expect a result with given number of rows.
Definition: transaction_base.hxx:503
transaction_base(transaction_base const &)=delete
TYPE query_value(zview query, std::string_view desc=std::string_view{})
Perform query, expecting exactly 1 row with 1 field, and convert it.
Definition: transaction_base.hxx:308
transaction_base(connection &c, std::string_view tname, std::shared_ptr< std::string > rollback_cmd)
Create a transaction (to be called by implementation classes only).
Definition: transaction_base.hxx:552
std::string quote(T const &t) const
Represent object as SQL string, including quoting & escaping.
Definition: transaction_base.hxx:182
row exec_params1(zview query, Args &&...args)
Definition: transaction_base.hxx:414
connection & conn() const
The connection in which this transaction lives.
Definition: transaction_base.hxx:523
transaction_base & operator=(transaction_base const &)=delete
auto esc_raw(ARGS &&...args) const
Escape binary data for use as SQL string literal in this transaction.
Definition: transaction_base.hxx:133
std::string quote(binarystring const &t) const
Definition: transaction_base.hxx:189
transaction_base(transaction_base &&)=delete
result exec_params(zview query, Args &&...args)
Execute an SQL statement with parameters.
Definition: transaction_base.hxx:405
result exec_params0(zview query, Args &&...args)
Definition: transaction_base.hxx:422
std::string unesc_raw(zview text) const
Unescape binary data, e.g. from a table field or notification payload.
Definition: transaction_base.hxx:143
result exec_prepared0(zview statement, Args &&...args)
Execute a prepared statement, and expect a result with zero rows.
Definition: transaction_base.hxx:492
std::string esc_like(std::string_view bin, char escape_char='\\') const
Escape string for literal LIKE match.
Definition: transaction_base.hxx:223
std::basic_string< std::byte > unesc_bin(char const text[])
Unescape binary data, e.g. from a table field or notification payload.
Definition: transaction_base.hxx:175
transaction_base & operator=(transaction_base &&)=delete
result exec0(zview query, std::string_view desc=std::string_view{})
Execute command, which should return zero rows of data.
Definition: transaction_base.hxx:276
result exec(std::stringstream const &query, std::string_view desc=std::string_view{})
Execute a command.
Definition: transaction_base.hxx:264
row exec_prepared1(zview statement, Args &&...args)
Execute a prepared statement, and expect a single-row result.
Definition: transaction_base.hxx:483
std::string quote_name(std::string_view identifier) const
Escape an SQL identifier for use in a query.
Definition: transaction_base.hxx:216
std::string quote_raw(unsigned char const bin[], std::size_t len) const
Binary-escape and quote a binary string for use as an SQL constant.
Definition: transaction_base.hxx:196
std::string_view name() const &noexcept
Transaction name, if you passed one to the constructor; or empty string.
Definition: transaction_base.hxx:545
result exec_params_n(std::size_t rows, zview query, Args &&...args)
Definition: transaction_base.hxx:431
auto stream(std::string_view query) &
Execute a query, and loop over the results row by row.
Definition: transaction_base.hxx:367
void process_notice(char const msg[]) const
Have connection process a warning message.
Definition: transaction_base.hxx:517
Base class for things that monopolise a transaction's attention.
Definition: transaction_focus.hxx:25
Marker-type wrapper: zero-terminated std::string_view.
Definition: zview.hxx:38