libpqxx
The C++ client library for PostgreSQL
Loading...
Searching...
No Matches
transaction_base.hxx
Go to the documentation of this file.
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-2025, 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#if !defined(PQXX_HEADER_PRE)
18# error "Include libpqxx headers as <pqxx/header>, not <pqxx/header.hxx>."
19#endif
20
21#include <optional>
22#include <string_view>
23
24/* End-user programs need not include this file, unless they define their own
25 * transaction classes. This is not something the typical program should want
26 * to do.
27 *
28 * However, reading this file is worthwhile because it defines the public
29 * interface for the available transaction classes such as transaction and
30 * nontransaction.
31 */
32
33#include "pqxx/connection.hxx"
37#include "pqxx/isolation.hxx"
39#include "pqxx/result.hxx"
40#include "pqxx/row.hxx"
41#include "pqxx/util.hxx"
42
44{
45class transaction_subtransaction;
47class transaction_stream_to;
48class transaction_transaction_focus;
49} // namespace pqxx::internal::gate
50
51
52namespace pqxx
53{
54using namespace std::literals;
55
56
58
59
145
147
152class PQXX_LIBEXPORT PQXX_NOVTABLE transaction_base
153{
154public:
155 transaction_base() = delete;
156 transaction_base(transaction_base const &) = delete;
157 transaction_base(transaction_base &&) = delete;
158 transaction_base &operator=(transaction_base const &) = delete;
159 transaction_base &operator=(transaction_base &&) = delete;
160
161 virtual ~transaction_base() = 0;
162
164
177 void commit();
178
180
183 void abort();
184
195
196 template<typename... ARGS> [[nodiscard]] auto esc(ARGS &&...args) const
197 {
198 return conn().esc(std::forward<ARGS>(args)...);
199 }
200
202
213 template<typename... ARGS> [[nodiscard]] auto esc_raw(ARGS &&...args) const
214 {
215 return conn().esc_raw(std::forward<ARGS>(args)...);
216 }
217
219
222 [[nodiscard, deprecated("Use unesc_bin() instead.")]] std::string
223 unesc_raw(zview text) const
224 {
226 return conn().unesc_raw(text);
228 }
229
231
234 [[nodiscard]] bytes unesc_bin(zview text) { return conn().unesc_bin(text); }
235
237
240 [[nodiscard, deprecated("Use unesc_bin() instead.")]] std::string
241 unesc_raw(char const *text) const
242 {
244 return conn().unesc_raw(text);
246 }
247
249
252 [[nodiscard]] bytes unesc_bin(char const text[])
253 {
254 return conn().unesc_bin(text);
255 }
256
258
259 template<typename T> [[nodiscard]] std::string quote(T const &t) const
260 {
261 return conn().quote(t);
262 }
263
264 [[deprecated("Use bytes instead of binarystring.")]] std::string
265 quote(binarystring const &t) const
266 {
267 return conn().quote(t.bytes_view());
268 }
269
271 [[deprecated("Use quote(pqxx::bytes_view).")]] std::string
272 quote_raw(unsigned char const bin[], std::size_t len) const
273 {
274 return quote(binary_cast(bin, len));
275 }
276
278 [[deprecated("Use quote(pqxx::bytes_view).")]] std::string
279 quote_raw(zview bin) const;
280
281#if defined(PQXX_HAVE_CONCEPTS) && defined(PQXX_HAVE_RANGES)
283
284 template<binary DATA>
285 [[nodiscard]] std::string quote_raw(DATA const &data) const
286 {
287 return conn().quote_raw(data);
288 }
289#endif
290
292 [[nodiscard]] std::string quote_name(std::string_view identifier) const
293 {
294 return conn().quote_name(identifier);
295 }
296
298 [[nodiscard]] std::string
299 esc_like(std::string_view bin, char escape_char = '\\') const
300 {
301 return conn().esc_like(bin, escape_char);
302 }
304
340
342
347 [[deprecated("The desc parameter is going away.")]]
348 result exec(std::string_view query, std::string_view desc);
349
350 // TODO: Wrap PQdescribePrepared().
351
352 result exec(std::string_view query, params parms)
353 {
354 return internal_exec_params(query, parms.make_c_params());
355 }
356
358
362 result exec(std::string_view query)
363 {
365 return exec(query, std::string_view{});
367 }
368
370
375 [[deprecated(
376 "Pass your query as a std::string_view, not stringstream.")]] result
377 exec(std::stringstream const &query, std::string_view desc)
378 {
380 return exec(query.str(), desc);
382 }
383
385
390 [[deprecated("Use exec(string_view) and call no_rows() on the result.")]]
391 result exec0(zview query, std::string_view desc)
392 {
394 return exec(query, desc).no_rows();
396 }
397
399
404 [[deprecated("Use exec() and call no_rows() on the result.")]]
405 result exec0(zview query)
406 {
407 return exec(query).no_rows();
408 }
409
411
417 [[deprecated("Use exec(string_view), and call one_row() on the result.")]]
418 row exec1(zview query, std::string_view desc)
419 {
421 return exec(query, desc).one_row();
423 }
424
426
432 [[deprecated("Use exec() instead, and call one_row() on the result.")]]
433 row exec1(zview query)
434 {
435 return exec(query).one_row();
436 }
437
439
444 [[deprecated("Use exec() instead, and call expect_rows() on the result.")]]
445 result exec_n(result::size_type rows, zview query, std::string_view desc);
446
448
453 [[deprecated("Use exec() instead, and call expect_rows() on the result.")]]
454 result exec_n(result::size_type rows, zview query)
455 {
457 return exec(query, std::string_view{}).expect_rows(rows);
459 }
460
462
465 template<typename TYPE>
466 [[deprecated("The desc parameter is going away.")]]
467 TYPE query_value(zview query, std::string_view desc)
468 {
470 return exec(query, desc).one_field().as<TYPE>();
472 }
473
475
481 template<typename TYPE> TYPE query_value(zview query)
482 {
483 return exec(query).one_field().as<TYPE>();
484 }
485
487
494 template<typename... TYPE>
495 [[nodiscard]] std::tuple<TYPE...> query1(zview query)
496 {
497 return exec(query).expect_columns(sizeof...(TYPE)).one_row().as<TYPE...>();
498 }
499
501
508 template<typename... TYPE>
509 [[nodiscard]] std::optional<std::tuple<TYPE...>> query01(zview query)
510 {
511 std::optional<row> const r{exec(query).opt_row()};
512 if (r)
513 return {r->as<TYPE...>()};
514 else
515 return {};
516 }
517
519
570 template<typename... TYPE>
571 [[nodiscard]] auto stream(std::string_view query) &
572 {
573 return pqxx::internal::stream_query<TYPE...>{*this, query};
574 }
575
576 // C++20: Concept like std::invocable, but without specifying param types.
578
606 template<typename CALLABLE>
607 auto for_stream(std::string_view query, CALLABLE &&func)
608 {
609 using param_types =
611 param_types const *const sample{nullptr};
612 auto data_stream{stream_like(query, sample)};
613 for (auto const &fields : data_stream) std::apply(func, fields);
614 }
615
616 template<typename CALLABLE>
617 [[deprecated(
618 "pqxx::transaction_base::for_each is now called for_stream.")]] auto
619 for_each(std::string_view query, CALLABLE &&func)
620 {
621 return for_stream(query, std::forward<CALLABLE>(func));
622 }
623
625
656 template<typename... TYPE> auto query(zview query)
657 {
658 return exec(query).iter<TYPE...>();
659 }
660
662 template<typename... TYPE>
663 [[deprecated("Use query() instead, and call expect_rows() on the result.")]]
664 auto query_n(result::size_type rows, zview query)
665 {
666 return exec(query).expect_rows(rows).iter<TYPE...>();
667 }
668
669 // C++20: Concept like std::invocable, but without specifying param types.
671
679 template<typename CALLABLE> void for_query(zview query, CALLABLE &&func)
680 {
681 exec(query).for_each(std::forward<CALLABLE>(func));
682 }
683
713
715
719 template<typename... Args>
720 [[deprecated("Use exec(zview, params) instead.")]]
721 result exec_params(std::string_view query, Args &&...args)
722 {
723 return exec(query, params{args...});
724 }
725
726 // Execute parameterised statement, expect a single-row result.
729 template<typename... Args>
730 [[deprecated("Use exec() instead, and call one_row() on the result.")]]
731 row exec_params1(zview query, Args &&...args)
732 {
733 return exec(query, params{args...}).one_row();
734 }
735
736 // Execute parameterised statement, expect a result with zero rows.
739 template<typename... Args>
740 [[deprecated(
741 "Use exec(string_view, params) and call no_rows() on the result.")]]
742 result exec_params0(zview query, Args &&...args)
743 {
744 return exec(query, params{args...}).no_rows();
745 }
746
747 // Execute parameterised statement, expect exactly a given number of rows.
750 template<typename... Args>
751 [[deprecated("Use exec(), and call expect_rows() on the result.")]]
752 result exec_params_n(std::size_t rows, zview query, Args &&...args)
753 {
754 return exec(query, params{args...})
755 .expect_rows(check_cast<result_size_type>(rows, "number of rows"));
756 }
757
758 // Execute parameterised statement, expect exactly a given number of rows.
761 template<typename... Args>
762 [[deprecated("Use exec(), and call expect_rows() on the result.")]]
763 result exec_params_n(result::size_type rows, zview query, Args &&...args)
764 {
765 return exec(query, params{args...}).expect_rows(rows);
766 }
767
769
802 template<typename... TYPE> auto query(zview query, params const &parms)
803 {
804 return exec(query, parms).iter<TYPE...>();
805 }
806
809
817 template<typename... TYPE>
818 [[deprecated("Use exec(), and call expect_rows() & iter() on the result.")]]
819 auto query_n(result::size_type rows, zview query, params const &parms)
820 {
821 return exec(query, parms).expect_rows(rows).iter<TYPE...>();
822 }
823
825
831 template<typename TYPE> TYPE query_value(zview query, params const &parms)
832 {
833 return exec(query, parms).expect_columns(1).one_field().as<TYPE>();
834 }
835
837
844 template<typename... TYPE>
845 [[nodiscard]]
846 std::tuple<TYPE...> query1(zview query, params const &parms)
847 {
848 return exec(query, parms).one_row().as<TYPE...>();
849 }
850
852
859 template<typename... TYPE>
860 [[nodiscard]] std::optional<std::tuple<TYPE...>>
861 query01(zview query, params const &parms)
862 {
863 std::optional<row> r{exec(query, parms).opt_row()};
864 if (r)
865 return {r->as<TYPE...>()};
866 else
867 return {};
868 }
869
870 // C++20: Concept like std::invocable, but without specifying param types.
872
883 template<typename CALLABLE>
884 void for_query(zview query, CALLABLE &&func, params const &parms)
885 {
886 exec(query, parms).for_each(std::forward<CALLABLE>(func));
887 }
888
890
905 void notify(std::string_view channel, std::string_view payload = {});
907
909 template<typename... Args>
910 [[deprecated("Use exec(prepped, params) instead.")]]
911 result exec_prepared(zview statement, Args &&...args)
912 {
913 return exec(prepped{statement}, params{args...});
914 }
915
917 result exec(prepped statement)
918 {
919 params pp;
920 return internal_exec_prepared(statement, pp.make_c_params());
921 }
922
924
929 template<typename... TYPE>
930 auto query(prepped statement, params const &parms = {})
931 {
932 return exec(statement, parms).iter<TYPE...>();
933 }
934
936
939 template<typename TYPE>
940 TYPE query_value(prepped statement, params const &parms = {})
941 {
942 return exec(statement, parms).expect_columns(1).one_field().as<TYPE>();
943 }
944
945 // C++20: Concept like std::invocable, but without specifying param types.
947
949 template<typename CALLABLE>
950 void for_query(prepped statement, CALLABLE &&func, params const &parms = {})
951 {
952 exec(statement, parms).for_each(std::forward<CALLABLE>(func));
953 }
954
956 result exec(prepped statement, params const &parms)
957 {
958 return internal_exec_prepared(statement, parms.make_c_params());
959 }
960
962
964 template<typename... Args>
965 [[deprecated(
966 "Use exec(string_view, params) and call one_row() on the result.")]]
967 row exec_prepared1(zview statement, Args &&...args)
968 {
969 return exec(prepped{statement}, params{args...}).one_row();
970 }
971
973
975 template<typename... Args>
976 [[deprecated(
977 "Use exec(prepped, params), and call no_rows() on the result.")]]
978 result exec_prepared0(zview statement, Args &&...args)
979 {
980 return exec(prepped{statement}, params{args...}).no_rows();
981 }
982
984
987 template<typename... Args>
988 [[deprecated(
989 "Use exec(prepped, params), and call expect_rows() on the result.")]]
990 result
991 exec_prepared_n(result::size_type rows, zview statement, Args &&...args)
992 {
993 return exec(pqxx::prepped{statement}, params{args...}).expect_rows(rows);
994 }
995
1000
1001 void process_notice(char const msg[]) const { m_conn.process_notice(msg); }
1003 void process_notice(zview msg) const { m_conn.process_notice(msg); }
1005
1007 [[nodiscard]] constexpr connection &conn() const noexcept { return m_conn; }
1008
1010
1025 [[deprecated("Set transaction-local variables using SQL SET statements.")]]
1026 void set_variable(std::string_view var, std::string_view value);
1027
1029
1032 [[deprecated("Read variables using SQL SHOW statements.")]]
1033 std::string get_variable(std::string_view);
1034
1035 // C++20: constexpr.
1037 [[nodiscard]] std::string_view name() const & noexcept { return m_name; }
1038
1039protected:
1041
1044 transaction_base(
1045 connection &cx, std::string_view tname,
1046 std::shared_ptr<std::string> rollback_cmd) :
1047 m_conn{cx}, m_name{tname}, m_rollback_cmd{rollback_cmd}
1048 {}
1049
1051
1056 transaction_base(connection &cx, std::string_view tname);
1057
1059 explicit transaction_base(connection &cx);
1060
1062 void register_transaction();
1063
1065 void close() noexcept;
1066
1068 virtual void do_commit() = 0;
1069
1071
1074 virtual void do_abort();
1075
1077 void set_rollback_cmd(std::shared_ptr<std::string> cmd)
1078 {
1079 m_rollback_cmd = cmd;
1080 }
1081
1083 result direct_exec(std::string_view, std::string_view desc = ""sv);
1084 result
1085 direct_exec(std::shared_ptr<std::string>, std::string_view desc = ""sv);
1086
1087private:
1088 enum class status
1089 {
1090 active,
1091 aborted,
1092 committed,
1093 in_doubt
1094 };
1095
1096 PQXX_PRIVATE void check_pending_error();
1097
1098 result internal_exec_prepared(
1099 std::string_view statement, internal::c_params const &args);
1100
1101 result
1102 internal_exec_params(std::string_view query, internal::c_params const &args);
1103
1105 [[nodiscard]] std::string description() const;
1106
1107 friend class pqxx::internal::gate::transaction_transaction_focus;
1108 PQXX_PRIVATE void register_focus(transaction_focus *);
1109 PQXX_PRIVATE void unregister_focus(transaction_focus *) noexcept;
1110 PQXX_PRIVATE void register_pending_error(zview) noexcept;
1111 PQXX_PRIVATE void register_pending_error(std::string &&) noexcept;
1112
1114 template<typename... ARGS>
1115 auto stream_like(std::string_view query, std::tuple<ARGS...> const *)
1116 {
1117 return stream<ARGS...>(query);
1118 }
1119
1120 connection &m_conn;
1121
1123
1126 transaction_focus const *m_focus = nullptr;
1127
1128 status m_status = status::active;
1129 bool m_registered = false;
1130 std::string m_name;
1131 std::string m_pending_error;
1132
1134 std::shared_ptr<std::string> m_rollback_cmd;
1135
1136 static constexpr std::string_view s_type_name{"transaction"sv};
1137};
1138
1139
1140// C++20: Can borrowed_range help?
1142template<>
1143std::string_view transaction_base::query_value<std::string_view>(
1144 zview query, std::string_view desc) = delete;
1146template<>
1147zview transaction_base::query_value<zview>(
1148 zview query, std::string_view desc) = delete;
1149
1150} // namespace pqxx
1151
1152
1153namespace pqxx::internal
1154{
1156template<pqxx::isolation_level isolation, pqxx::write_policy rw>
1157extern const zview begin_cmd;
1158
1159// These are not static members, so "constexpr" does not imply "inline".
1160template<>
1163template<>
1165 "BEGIN READ ONLY"_zv};
1166template<>
1168 "BEGIN ISOLATION LEVEL REPEATABLE READ"_zv};
1169template<>
1171 "BEGIN ISOLATION LEVEL REPEATABLE READ READ ONLY"_zv};
1172template<>
1174 "BEGIN ISOLATION LEVEL SERIALIZABLE"_zv};
1175template<>
1177 "BEGIN ISOLATION LEVEL SERIALIZABLE READ ONLY"_zv};
1178} // namespace pqxx::internal
1179
1181#endif
Definition transaction-sql_cursor.hxx:6
Base class for things that monopolise a transaction's attention.
Definition transaction_focus.hxx:29
Marker-type wrapper: zero-terminated std::string_view.
Definition zview.hxx:38
#define PQXX_LIBEXPORT
Definition header-pre.hxx:157
#define PQXX_NOVTABLE
Definition header-pre.hxx:172
#define PQXX_PRIVATE
Definition header-pre.hxx:158
Definition connection.hxx:108
Internal items for libpqxx' own use. Do not use these yourself.
Definition encodings.cxx:33
void PQXX_LIBEXPORT unesc_bin(std::string_view escaped_data, std::byte buffer[])
Reconstitute binary data from its escaped version.
Definition util.cxx:165
const zview begin_cmd
The SQL command for starting a given type of transaction.
decltype(strip_types(std::declval< TYPES... >())) strip_types_t
Take a tuple type and apply strip_t to its component types.
Definition util.hxx:629
The home of all libpqxx classes, functions, templates, etc.
Definition array.cxx:27
std::conditional< has_generic_bytes_char_traits, std::basic_string< std::byte >, std::basic_string< std::byte, byte_char_traits > >::type bytes
Type alias for a container containing bytes.
Definition util.hxx:373
bytes_view binary_cast(TYPE const &data)
End a code block started by "ignore-deprecated-pre.hxx".
Definition util.hxx:409