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 <string_view>
22
23/* End-user programs need not include this file, unless they define their own
24 * transaction classes. This is not something the typical program should want
25 * to do.
26 *
27 * However, reading this file is worthwhile because it defines the public
28 * interface for the available transaction classes such as transaction and
29 * nontransaction.
30 */
31
32#include "pqxx/connection.hxx"
36#include "pqxx/isolation.hxx"
38#include "pqxx/result.hxx"
39#include "pqxx/row.hxx"
40#include "pqxx/util.hxx"
41
43{
44class transaction_subtransaction;
46class transaction_stream_to;
47class transaction_transaction_focus;
48} // namespace pqxx::internal::gate
49
50
51namespace pqxx
52{
53using namespace std::literals;
54
55
57
58
144
146
151class PQXX_LIBEXPORT PQXX_NOVTABLE transaction_base
152{
153public:
154 transaction_base() = delete;
155 transaction_base(transaction_base const &) = delete;
156 transaction_base(transaction_base &&) = delete;
157 transaction_base &operator=(transaction_base const &) = delete;
158 transaction_base &operator=(transaction_base &&) = delete;
159
160 virtual ~transaction_base() = 0;
161
163
176 void commit();
177
179
182 void abort();
183
194
195 template<typename... ARGS> [[nodiscard]] auto esc(ARGS &&...args) const
196 {
197 return conn().esc(std::forward<ARGS>(args)...);
198 }
199
201
212 template<typename... ARGS> [[nodiscard]] auto esc_raw(ARGS &&...args) const
213 {
214 return conn().esc_raw(std::forward<ARGS>(args)...);
215 }
216
218
221 [[nodiscard, deprecated("Use unesc_bin() instead.")]] std::string
222 unesc_raw(zview text) const
223 {
225 return conn().unesc_raw(text);
227 }
228
230
233 [[nodiscard]] bytes unesc_bin(zview text) { return conn().unesc_bin(text); }
234
236
239 [[nodiscard, deprecated("Use unesc_bin() instead.")]] std::string
240 unesc_raw(char const *text) const
241 {
243 return conn().unesc_raw(text);
245 }
246
248
251 [[nodiscard]] bytes unesc_bin(char const text[])
252 {
253 return conn().unesc_bin(text);
254 }
255
257
258 template<typename T> [[nodiscard]] std::string quote(T const &t) const
259 {
260 return conn().quote(t);
261 }
262
263 [[deprecated("Use bytes instead of binarystring.")]] std::string
264 quote(binarystring const &t) const
265 {
266 return conn().quote(t.bytes_view());
267 }
268
270 [[deprecated("Use quote(pqxx::bytes_view).")]] std::string
271 quote_raw(unsigned char const bin[], std::size_t len) const
272 {
273 return quote(binary_cast(bin, len));
274 }
275
277 [[deprecated("Use quote(pqxx::bytes_view).")]] std::string
278 quote_raw(zview bin) const;
279
280#if defined(PQXX_HAVE_CONCEPTS) && defined(PQXX_HAVE_RANGES)
282
283 template<binary DATA>
284 [[nodiscard]] std::string quote_raw(DATA const &data) const
285 {
286 return conn().quote_raw(data);
287 }
288#endif
289
291 [[nodiscard]] std::string quote_name(std::string_view identifier) const
292 {
293 return conn().quote_name(identifier);
294 }
295
297 [[nodiscard]] std::string
298 esc_like(std::string_view bin, char escape_char = '\\') const
299 {
300 return conn().esc_like(bin, escape_char);
301 }
303
339
341
346 [[deprecated("The desc parameter is going away.")]]
347 result exec(std::string_view query, std::string_view desc);
348
349 // TODO: Wrap PQdescribePrepared().
350
351 result exec(std::string_view query, params parms)
352 {
353 return internal_exec_params(query, parms.make_c_params());
354 }
355
357
361 result exec(std::string_view query)
362 {
364 return exec(query, std::string_view{});
366 }
367
369
374 [[deprecated(
375 "Pass your query as a std::string_view, not stringstream.")]] result
376 exec(std::stringstream const &query, std::string_view desc)
377 {
379 return exec(query.str(), desc);
381 }
382
384
389 [[deprecated("Use exec(string_view) and call no_rows() on the result.")]]
390 result exec0(zview query, std::string_view desc)
391 {
393 return exec(query, desc).no_rows();
395 }
396
398
403 [[deprecated("Use exec() and call no_rows() on the result.")]]
404 result exec0(zview query)
405 {
406 return exec(query).no_rows();
407 }
408
410
416 [[deprecated("Use exec(string_view), and call one_row() on the result.")]]
417 row exec1(zview query, std::string_view desc)
418 {
420 return exec(query, desc).one_row();
422 }
423
425
431 [[deprecated("Use exec() instead, and call one_row() on the result.")]]
432 row exec1(zview query)
433 {
434 return exec(query).one_row();
435 }
436
438
443 [[deprecated("Use exec() instead, and call expect_rows() on the result.")]]
444 result exec_n(result::size_type rows, zview query, std::string_view desc);
445
447
452 [[deprecated("Use exec() instead, and call expect_rows() on the result.")]]
453 result exec_n(result::size_type rows, zview query)
454 {
456 return exec(query, std::string_view{}).expect_rows(rows);
458 }
459
461
464 template<typename TYPE>
465 [[deprecated("The desc parameter is going away.")]]
466 TYPE query_value(zview query, std::string_view desc)
467 {
469 return exec(query, desc).one_field().as<TYPE>();
471 }
472
474
480 template<typename TYPE> TYPE query_value(zview query)
481 {
482 return exec(query).one_field().as<TYPE>();
483 }
484
486
493 template<typename... TYPE>
494 [[nodiscard]] std::tuple<TYPE...> query1(zview query)
495 {
496 return exec(query).expect_columns(sizeof...(TYPE)).one_row().as<TYPE...>();
497 }
498
500
507 template<typename... TYPE>
508 [[nodiscard]] std::optional<std::tuple<TYPE...>> query01(zview query)
509 {
510 std::optional<row> const r{exec(query).opt_row()};
511 if (r)
512 return {r->as<TYPE...>()};
513 else
514 return {};
515 }
516
518
569 template<typename... TYPE>
570 [[nodiscard]] auto stream(std::string_view query) &
571 {
572 return pqxx::internal::stream_query<TYPE...>{*this, query};
573 }
574
575 // C++20: Concept like std::invocable, but without specifying param types.
577
605 template<typename CALLABLE>
606 auto for_stream(std::string_view query, CALLABLE &&func)
607 {
608 using param_types =
610 param_types const *const sample{nullptr};
611 auto data_stream{stream_like(query, sample)};
612 for (auto const &fields : data_stream) std::apply(func, fields);
613 }
614
615 template<typename CALLABLE>
616 [[deprecated(
617 "pqxx::transaction_base::for_each is now called for_stream.")]] auto
618 for_each(std::string_view query, CALLABLE &&func)
619 {
620 return for_stream(query, std::forward<CALLABLE>(func));
621 }
622
624
655 template<typename... TYPE> auto query(zview query)
656 {
657 return exec(query).iter<TYPE...>();
658 }
659
661 template<typename... TYPE>
662 [[deprecated("Use query() instead, and call expect_rows() on the result.")]]
663 auto query_n(result::size_type rows, zview query)
664 {
665 return exec(query).expect_rows(rows).iter<TYPE...>();
666 }
667
668 // C++20: Concept like std::invocable, but without specifying param types.
670
678 template<typename CALLABLE> void for_query(zview query, CALLABLE &&func)
679 {
680 exec(query).for_each(std::forward<CALLABLE>(func));
681 }
682
712
714
718 template<typename... Args>
719 [[deprecated("Use exec(zview, params) instead.")]]
720 result exec_params(std::string_view query, Args &&...args)
721 {
722 return exec(query, params{args...});
723 }
724
725 // Execute parameterised statement, expect a single-row result.
728 template<typename... Args>
729 [[deprecated("Use exec() instead, and call one_row() on the result.")]]
730 row exec_params1(zview query, Args &&...args)
731 {
732 return exec(query, params{args...}).one_row();
733 }
734
735 // Execute parameterised statement, expect a result with zero rows.
738 template<typename... Args>
739 [[deprecated(
740 "Use exec(string_view, params) and call no_rows() on the result.")]]
741 result exec_params0(zview query, Args &&...args)
742 {
743 return exec(query, params{args...}).no_rows();
744 }
745
746 // Execute parameterised statement, expect exactly a given number of rows.
749 template<typename... Args>
750 [[deprecated("Use exec(), and call expect_rows() on the result.")]]
751 result exec_params_n(std::size_t rows, zview query, Args &&...args)
752 {
753 return exec(query, params{args...})
754 .expect_rows(check_cast<result_size_type>(rows, "number of rows"));
755 }
756
757 // Execute parameterised statement, expect exactly a given number of rows.
760 template<typename... Args>
761 [[deprecated("Use exec(), and call expect_rows() on the result.")]]
762 result exec_params_n(result::size_type rows, zview query, Args &&...args)
763 {
764 return exec(query, params{args...}).expect_rows(rows);
765 }
766
768
801 template<typename... TYPE> auto query(zview query, params const &parms)
802 {
803 return exec(query, parms).iter<TYPE...>();
804 }
805
808
816 template<typename... TYPE>
817 [[deprecated("Use exec(), and call expect_rows() & iter() on the result.")]]
818 auto query_n(result::size_type rows, zview query, params const &parms)
819 {
820 return exec(query, parms).expect_rows(rows).iter<TYPE...>();
821 }
822
824
830 template<typename TYPE> TYPE query_value(zview query, params const &parms)
831 {
832 return exec(query, parms).expect_columns(1).one_field().as<TYPE>();
833 }
834
836
843 template<typename... TYPE>
844 [[nodiscard]]
845 std::tuple<TYPE...> query1(zview query, params const &parms)
846 {
847 return exec(query, parms).one_row().as<TYPE...>();
848 }
849
851
858 template<typename... TYPE>
859 [[nodiscard]] std::optional<std::tuple<TYPE...>>
860 query01(zview query, params const &parms)
861 {
862 std::optional<row> r{exec(query, parms).opt_row()};
863 if (r)
864 return {r->as<TYPE...>()};
865 else
866 return {};
867 }
868
869 // C++20: Concept like std::invocable, but without specifying param types.
871
882 template<typename CALLABLE>
883 void for_query(zview query, CALLABLE &&func, params const &parms)
884 {
885 exec(query, parms).for_each(std::forward<CALLABLE>(func));
886 }
887
889
904 void notify(std::string_view channel, std::string_view payload = {});
906
908 template<typename... Args>
909 [[deprecated("Use exec(prepped, params) instead.")]]
910 result exec_prepared(zview statement, Args &&...args)
911 {
912 return exec(prepped{statement}, params{args...});
913 }
914
916 result exec(prepped statement)
917 {
918 params pp;
919 return internal_exec_prepared(statement, pp.make_c_params());
920 }
921
923
928 template<typename... TYPE>
929 auto query(prepped statement, params const &parms = {})
930 {
931 return exec(statement, parms).iter<TYPE...>();
932 }
933
935
938 template<typename TYPE>
939 TYPE query_value(prepped statement, params const &parms = {})
940 {
941 return exec(statement, parms).expect_columns(1).one_field().as<TYPE>();
942 }
943
944 // C++20: Concept like std::invocable, but without specifying param types.
946
948 template<typename CALLABLE>
949 void for_query(prepped statement, CALLABLE &&func, params const &parms = {})
950 {
951 exec(statement, parms).for_each(std::forward<CALLABLE>(func));
952 }
953
955 result exec(prepped statement, params const &parms)
956 {
957 return internal_exec_prepared(statement, parms.make_c_params());
958 }
959
961
963 template<typename... Args>
964 [[deprecated(
965 "Use exec(string_view, params) and call one_row() on the result.")]]
966 row exec_prepared1(zview statement, Args &&...args)
967 {
968 return exec(prepped{statement}, params{args...}).one_row();
969 }
970
972
974 template<typename... Args>
975 [[deprecated(
976 "Use exec(prepped, params), and call no_rows() on the result.")]]
977 result exec_prepared0(zview statement, Args &&...args)
978 {
979 return exec(prepped{statement}, params{args...}).no_rows();
980 }
981
983
986 template<typename... Args>
987 [[deprecated(
988 "Use exec(prepped, params), and call expect_rows() on the result.")]]
989 result
990 exec_prepared_n(result::size_type rows, zview statement, Args &&...args)
991 {
992 return exec(pqxx::prepped{statement}, params{args...}).expect_rows(rows);
993 }
994
999
1000 void process_notice(char const msg[]) const { m_conn.process_notice(msg); }
1002 void process_notice(zview msg) const { m_conn.process_notice(msg); }
1004
1006 [[nodiscard]] constexpr connection &conn() const noexcept { return m_conn; }
1007
1009
1024 [[deprecated("Set transaction-local variables using SQL SET statements.")]]
1025 void set_variable(std::string_view var, std::string_view value);
1026
1028
1031 [[deprecated("Read variables using SQL SHOW statements.")]]
1032 std::string get_variable(std::string_view);
1033
1034 // C++20: constexpr.
1036 [[nodiscard]] std::string_view name() const & noexcept { return m_name; }
1037
1038protected:
1040
1043 transaction_base(
1044 connection &cx, std::string_view tname,
1045 std::shared_ptr<std::string> rollback_cmd) :
1046 m_conn{cx}, m_name{tname}, m_rollback_cmd{rollback_cmd}
1047 {}
1048
1050
1055 transaction_base(connection &cx, std::string_view tname);
1056
1058 explicit transaction_base(connection &cx);
1059
1061 void register_transaction();
1062
1064 void close() noexcept;
1065
1067 virtual void do_commit() = 0;
1068
1070
1073 virtual void do_abort();
1074
1076 void set_rollback_cmd(std::shared_ptr<std::string> cmd)
1077 {
1078 m_rollback_cmd = cmd;
1079 }
1080
1082 result direct_exec(std::string_view, std::string_view desc = ""sv);
1083 result
1084 direct_exec(std::shared_ptr<std::string>, std::string_view desc = ""sv);
1085
1086private:
1087 enum class status
1088 {
1089 active,
1090 aborted,
1091 committed,
1092 in_doubt
1093 };
1094
1095 PQXX_PRIVATE void check_pending_error();
1096
1097 result internal_exec_prepared(
1098 std::string_view statement, internal::c_params const &args);
1099
1100 result
1101 internal_exec_params(std::string_view query, internal::c_params const &args);
1102
1104 [[nodiscard]] std::string description() const;
1105
1106 friend class pqxx::internal::gate::transaction_transaction_focus;
1107 PQXX_PRIVATE void register_focus(transaction_focus *);
1108 PQXX_PRIVATE void unregister_focus(transaction_focus *) noexcept;
1109 PQXX_PRIVATE void register_pending_error(zview) noexcept;
1110 PQXX_PRIVATE void register_pending_error(std::string &&) noexcept;
1111
1113 template<typename... ARGS>
1114 auto stream_like(std::string_view query, std::tuple<ARGS...> const *)
1115 {
1116 return stream<ARGS...>(query);
1117 }
1118
1119 connection &m_conn;
1120
1122
1125 transaction_focus const *m_focus = nullptr;
1126
1127 status m_status = status::active;
1128 bool m_registered = false;
1129 std::string m_name;
1130 std::string m_pending_error;
1131
1133 std::shared_ptr<std::string> m_rollback_cmd;
1134
1135 static constexpr std::string_view s_type_name{"transaction"sv};
1136};
1137
1138
1139// C++20: Can borrowed_range help?
1141template<>
1142std::string_view transaction_base::query_value<std::string_view>(
1143 zview query, std::string_view desc) = delete;
1145template<>
1146zview transaction_base::query_value<zview>(
1147 zview query, std::string_view desc) = delete;
1148
1149} // namespace pqxx
1150
1151
1152namespace pqxx::internal
1153{
1155template<pqxx::isolation_level isolation, pqxx::write_policy rw>
1156extern const zview begin_cmd;
1157
1158// These are not static members, so "constexpr" does not imply "inline".
1159template<>
1162template<>
1164 "BEGIN READ ONLY"_zv};
1165template<>
1167 "BEGIN ISOLATION LEVEL REPEATABLE READ"_zv};
1168template<>
1170 "BEGIN ISOLATION LEVEL REPEATABLE READ READ ONLY"_zv};
1171template<>
1173 "BEGIN ISOLATION LEVEL SERIALIZABLE"_zv};
1174template<>
1176 "BEGIN ISOLATION LEVEL SERIALIZABLE READ ONLY"_zv};
1177} // namespace pqxx::internal
1178
1180#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:107
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