libpqxx
The C++ client library for PostgreSQL
Loading...
Searching...
No Matches
connection.hxx
1/* Definition of the connection class.
2 *
3 * pqxx::connection encapsulates a connection to a database.
4 *
5 * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/connection instead.
6 *
7 * Copyright (c) 2000-2024, Jeroen T. Vermeulen.
8 *
9 * See COPYING for copyright license. If you did not receive a file called
10 * COPYING with this source code, please notify the distributor of this
11 * mistake, or contact the author.
12 */
13#ifndef PQXX_H_CONNECTION
14#define PQXX_H_CONNECTION
15
16#if !defined(PQXX_HEADER_PRE)
17# error "Include libpqxx headers as <pqxx/header>, not <pqxx/header.hxx>."
18#endif
19
20#include <cstddef>
21#include <ctime>
22#include <initializer_list>
23#include <list>
24#include <map>
25#include <memory>
26#include <string_view>
27#include <tuple>
28
29// Double-check in order to suppress an overzealous Visual C++ warning (#418).
30#if defined(PQXX_HAVE_CONCEPTS) && __has_include(<ranges>)
31# include <ranges>
32#endif
33
34#include "pqxx/errorhandler.hxx"
35#include "pqxx/except.hxx"
36#include "pqxx/internal/concat.hxx"
37#include "pqxx/params.hxx"
38#include "pqxx/separated_list.hxx"
39#include "pqxx/strconv.hxx"
40#include "pqxx/types.hxx"
41#include "pqxx/util.hxx"
42#include "pqxx/zview.hxx"
43
44
78namespace pqxx::internal
79{
80class sql_cursor;
81
82#if defined(PQXX_HAVE_CONCEPTS)
84template<typename T>
85concept ZKey_ZValues = std::ranges::input_range<T> and requires(T t) {
86 { std::cbegin(t) };
87 { std::get<0>(*std::cbegin(t)) } -> ZString;
88 { std::get<1>(*std::cbegin(t)) } -> ZString;
89} and std::tuple_size_v<typename std::ranges::iterator_t<T>::value_type> == 2;
90#endif // PQXX_HAVE_CONCEPTS
91
92
94
101void PQXX_COLD PQXX_LIBEXPORT skip_init_ssl(int skips) noexcept;
102} // namespace pqxx::internal
103
104
105namespace pqxx::internal::gate
106{
107class connection_dbtransaction;
108class connection_errorhandler;
109class connection_largeobject;
110class connection_notification_receiver;
111class connection_pipeline;
112class connection_sql_cursor;
113struct connection_stream_from;
114class connection_stream_to;
115class connection_transaction;
116class const_connection_largeobject;
117} // namespace pqxx::internal::gate
118
119
120namespace pqxx
121{
123
130enum skip_init : int
131{
134
137
140};
141
142
144
167template<skip_init... SKIP> inline void skip_init_ssl() noexcept
168{
169 // (Normalise skip flags to one per.)
170 pqxx::internal::skip_init_ssl(((1 << SKIP) | ...));
171}
172
173
175
182using table_path = std::initializer_list<std::string_view>;
183
184
186enum class error_verbosity : int
187{
188 // These values must match those in libpq's PGVerbosity enum.
189 terse = 0,
190 normal = 1,
191 verbose = 2
192};
193
194
196
229class PQXX_LIBEXPORT connection
230{
231public:
232 connection() : connection{""} {}
233
235 explicit connection(char const options[])
236 {
238 init(options);
239 }
240
242 explicit connection(zview options) : connection{options.c_str()}
243 {
244 // (Delegates to other constructor which calls check_version for us.)
245 }
246
248
253 connection(connection &&rhs);
254
255#if defined(PQXX_HAVE_CONCEPTS)
257
272 template<internal::ZKey_ZValues MAPPING>
273 inline connection(MAPPING const &params);
274#endif // PQXX_HAVE_CONCEPTS
275
276 ~connection()
277 {
278 try
279 {
280 close();
281 }
282 catch (std::exception const &)
283 {}
284 }
285
287
290 connection &operator=(connection &&rhs);
291
292 connection(connection const &) = delete;
293 connection &operator=(connection const &) = delete;
294
296
301 [[nodiscard]] bool PQXX_PURE is_open() const noexcept;
302
304 void process_notice(char const[]) noexcept;
306
309 void process_notice(zview) noexcept;
310
312 void trace(std::FILE *) noexcept;
313
325
326 [[nodiscard]] char const *dbname() const;
327
329
330 [[nodiscard]] char const *username() const;
331
333
336 [[nodiscard]] char const *hostname() const;
337
339 [[nodiscard]] char const *port() const;
340
342 [[nodiscard]] int PQXX_PURE backendpid() const & noexcept;
343
345
355 [[nodiscard]] int PQXX_PURE sock() const & noexcept;
356
358
361 [[nodiscard]] int PQXX_PURE protocol_version() const noexcept;
362
364
376 [[nodiscard]] int PQXX_PURE server_version() const noexcept;
378
380
401 [[nodiscard]] std::string get_client_encoding() const;
402
404
407 void set_client_encoding(zview encoding) &
408 {
409 set_client_encoding(encoding.c_str());
410 }
411
413
416 void set_client_encoding(char const encoding[]) &;
417
419 [[nodiscard]] int encoding_id() const;
420
422
424
445 template<typename TYPE>
446 void set_session_var(std::string_view var, TYPE const &value) &
447 {
448 if constexpr (nullness<TYPE>::has_null)
449 {
450 if (nullness<TYPE>::is_null(value))
451 throw variable_set_to_null{
452 internal::concat("Attempted to set variable ", var, " to null.")};
453 }
454 exec(internal::concat("SET ", quote_name(var), "=", quote(value)));
455 }
456
458
464 std::string get_var(std::string_view var);
465
467
473 template<typename TYPE> TYPE get_var_as(std::string_view var)
474 {
475 return from_string<TYPE>(get_var(var));
476 }
477
483
500 int get_notifs();
501
503
515 int await_notification();
516
518
530 int await_notification(std::time_t seconds, long microseconds);
532
564 [[nodiscard]] std::string
565 encrypt_password(zview user, zview password, zview algorithm)
566 {
567 return encrypt_password(user.c_str(), password.c_str(), algorithm.c_str());
568 }
570 [[nodiscard]] std::string encrypt_password(
571 char const user[], char const password[], char const *algorithm = nullptr);
573
616
618
622 void prepare(zview name, zview definition) &
623 {
624 prepare(name.c_str(), definition.c_str());
625 }
626
631 void prepare(char const name[], char const definition[]) &;
632
634
641 void prepare(char const definition[]) &;
642 void prepare(zview definition) & { return prepare(definition.c_str()); }
643
645 void unprepare(std::string_view name);
646
648
649 // C++20: constexpr. Breaks ABI.
651
654 [[nodiscard]] std::string adorn_name(std::string_view);
655
660
662 [[nodiscard]] std::string esc(char const text[]) const
663 {
664 return esc(std::string_view{text});
665 }
666
667#if defined(PQXX_HAVE_SPAN)
669
680 [[nodiscard]] std::string_view
681 esc(std::string_view text, std::span<char> buffer)
682 {
683 auto const size{std::size(text)}, space{std::size(buffer)};
684 auto const needed{2 * size + 1};
685 if (space < needed)
686 throw range_error{internal::concat(
687 "Not enough room to escape string of ", size, " byte(s): need ",
688 needed, " bytes of buffer space, but buffer size is ", space, ".")};
689 auto const data{buffer.data()};
690 return {data, esc_to_buf(text, data)};
691 }
692#endif
693
695
698 [[nodiscard]] std::string esc(std::string_view text) const;
699
700#if defined(PQXX_HAVE_CONCEPTS)
702
703 template<binary DATA> [[nodiscard]] std::string esc(DATA const &data) const
704 {
705 return esc_raw(data);
706 }
707#endif
708
709#if defined(PQXX_HAVE_CONCEPTS) && defined(PQXX_HAVE_SPAN)
711
722 template<binary DATA>
723 [[nodiscard]] zview esc(DATA const &data, std::span<char> buffer) const
724 {
725 auto const size{std::size(data)}, space{std::size(buffer)};
726 auto const needed{internal::size_esc_bin(std::size(data))};
727 if (space < needed)
728 throw range_error{internal::concat(
729 "Not enough room to escape binary string of ", size, " byte(s): need ",
730 needed, " bytes of buffer space, but buffer size is ", space, ".")};
731
732 bytes_view view{std::data(data), std::size(data)};
733 auto const out{std::data(buffer)};
734 // Actually, in the modern format, we know beforehand exactly how many
735 // bytes we're going to fill. Just leave out the trailing zero.
736 internal::esc_bin(view, out);
737 return zview{out, needed - 1};
738 }
739#endif
740
742 [[deprecated("Use std::byte for binary data.")]] std::string
743 esc_raw(unsigned char const bin[], std::size_t len) const;
744
746
747 [[nodiscard]] std::string esc_raw(bytes_view) const;
748
749#if defined(PQXX_HAVE_SPAN)
751
752 [[nodiscard]] std::string esc_raw(bytes_view, std::span<char> buffer) const;
753#endif
754
755#if defined(PQXX_HAVE_CONCEPTS)
757
758 template<binary DATA>
759 [[nodiscard]] std::string esc_raw(DATA const &data) const
760 {
761 return esc_raw(bytes_view{std::data(data), std::size(data)});
762 }
763#endif
764
765#if defined(PQXX_HAVE_CONCEPTS) && defined(PQXX_HAVE_SPAN)
767 template<binary DATA>
768 [[nodiscard]] zview esc_raw(DATA const &data, std::span<char> buffer) const
769 {
770 return this->esc(binary_cast(data), buffer);
771 }
772#endif
773
774 // TODO: Make "into buffer" variant to eliminate a string allocation.
776
783 [[nodiscard]] bytes unesc_bin(std::string_view text) const
784 {
785 bytes buf;
786 buf.resize(pqxx::internal::size_unesc_bin(std::size(text)));
787 pqxx::internal::unesc_bin(text, buf.data());
788 return buf;
789 }
790
792 std::string quote_raw(bytes_view) const;
793
794#if defined(PQXX_HAVE_CONCEPTS)
796
797 template<binary DATA>
798 [[nodiscard]] std::string quote_raw(DATA const &data) const
799 {
800 return quote_raw(bytes_view{std::data(data), std::size(data)});
801 }
802#endif
803
804 // TODO: Make "into buffer" variant to eliminate a string allocation.
806 [[nodiscard]] std::string quote_name(std::string_view identifier) const;
807
808 // TODO: Make "into buffer" variant to eliminate a string allocation.
810
813 [[nodiscard]] std::string quote_table(std::string_view name) const;
814
815 // TODO: Make "into buffer" variant to eliminate a string allocation.
817
825 [[nodiscard]] std::string quote_table(table_path) const;
826
827 // TODO: Make "into buffer" variant to eliminate a string allocation.
829
836 template<PQXX_CHAR_STRINGS_ARG STRINGS>
837 inline std::string quote_columns(STRINGS const &columns) const;
838
839 // TODO: Make "into buffer" variant to eliminate a string allocation.
841
844 template<typename T>
845 [[nodiscard]] inline std::string quote(T const &t) const;
846
847 [[deprecated("Use std::byte for binary data.")]] std::string
848 quote(binarystring const &) const;
849
850 // TODO: Make "into buffer" variant to eliminate a string allocation.
852 [[nodiscard]] std::string quote(bytes_view bytes) const;
853
854 // TODO: Make "into buffer" variant to eliminate a string allocation.
856
881 [[nodiscard]] std::string
882 esc_like(std::string_view text, char escape_char = '\\') const;
883
885
889 [[deprecated("Use std::string_view or pqxx:zview.")]] std::string
890 esc(char const text[], std::size_t maxlen) const
891 {
892 return esc(std::string_view{text, maxlen});
893 }
894
896
899 [[nodiscard, deprecated("Use unesc_bin() instead.")]] std::string
900 unesc_raw(zview text) const
901 {
902#include "pqxx/internal/ignore-deprecated-pre.hxx"
903 return unesc_raw(text.c_str());
904#include "pqxx/internal/ignore-deprecated-post.hxx"
905 }
906
908
911 [[nodiscard, deprecated("Use unesc_bin() instead.")]] std::string
912 unesc_raw(char const text[]) const;
913
915 [[deprecated("Use quote(bytes_view).")]] std::string
916 quote_raw(unsigned char const bin[], std::size_t len) const;
918
920
924 void cancel_query();
925
926#if defined(_WIN32) || __has_include(<fcntl.h>)
928
932 void set_blocking(bool block) &;
933#endif // defined(_WIN32) || __has_include(<fcntl.h>)
934
936
945 void set_verbosity(error_verbosity verbosity) & noexcept;
946
948
960 [[nodiscard]] std::vector<errorhandler *> get_errorhandlers() const;
961
963
969 [[nodiscard]] std::string connection_string() const;
970
972
980 void close();
981
983
989 static connection seize_raw_connection(internal::pq::PGconn *raw_conn)
990 {
991 return connection{raw_conn};
992 }
993
995
1000 internal::pq::PGconn *release_raw_connection() &&
1001 {
1002 return std::exchange(m_conn, nullptr);
1003 }
1004
1006
1019 [[deprecated("To set session variables, use set_session_var.")]] void
1020 set_variable(std::string_view var, std::string_view value) &;
1021
1023
1026 [[deprecated("Use get_var instead.")]] std::string
1027 get_variable(std::string_view);
1028
1029private:
1030 friend class connecting;
1031 enum connect_mode
1032 {
1033 connect_nonblocking
1034 };
1035 connection(connect_mode, zview connection_string);
1036
1038 explicit connection(internal::pq::PGconn *raw_conn) : m_conn{raw_conn} {}
1039
1041
1046 std::pair<bool, bool> poll_connect();
1047
1048 // Initialise based on connection string.
1049 void init(char const options[]);
1050 // Initialise based on parameter names and values.
1051 void init(char const *params[], char const *values[]);
1052 void complete_init();
1053
1054 result make_result(
1055 internal::pq::PGresult *pgr, std::shared_ptr<std::string> const &query,
1056 std::string_view desc = ""sv);
1057
1058 void PQXX_PRIVATE set_up_state();
1059
1060 int PQXX_PRIVATE PQXX_PURE status() const noexcept;
1061
1063
1067 std::size_t esc_to_buf(std::string_view text, char *buf) const;
1068
1069 friend class internal::gate::const_connection_largeobject;
1070 char const *PQXX_PURE err_msg() const noexcept;
1071
1072 void PQXX_PRIVATE process_notice_raw(char const msg[]) noexcept;
1073
1074 result exec_prepared(std::string_view statement, internal::c_params const &);
1075
1077 void check_movable() const;
1079 void check_overwritable() const;
1080
1081 friend class internal::gate::connection_errorhandler;
1082 void PQXX_PRIVATE register_errorhandler(errorhandler *);
1083 void PQXX_PRIVATE unregister_errorhandler(errorhandler *) noexcept;
1084
1085 friend class internal::gate::connection_transaction;
1086 result exec(std::string_view, std::string_view = ""sv);
1087 result PQXX_PRIVATE
1088 exec(std::shared_ptr<std::string> const &, std::string_view = ""sv);
1089 void PQXX_PRIVATE register_transaction(transaction_base *);
1090 void PQXX_PRIVATE unregister_transaction(transaction_base *) noexcept;
1091
1092 friend struct internal::gate::connection_stream_from;
1094
1099 std::pair<std::unique_ptr<char, void (*)(void const *)>, std::size_t>
1100 read_copy_line();
1101
1102 friend class internal::gate::connection_stream_to;
1103 void PQXX_PRIVATE write_copy_line(std::string_view);
1104 void PQXX_PRIVATE end_copy_write();
1105
1106 friend class internal::gate::connection_largeobject;
1107 internal::pq::PGconn *raw_connection() const { return m_conn; }
1108
1109 friend class internal::gate::connection_notification_receiver;
1110 void add_receiver(notification_receiver *);
1111 void remove_receiver(notification_receiver *) noexcept;
1112
1113 friend class internal::gate::connection_pipeline;
1114 void PQXX_PRIVATE start_exec(char const query[]);
1115 bool PQXX_PRIVATE consume_input() noexcept;
1116 bool PQXX_PRIVATE is_busy() const noexcept;
1117 internal::pq::PGresult *get_result();
1118
1119 friend class internal::gate::connection_dbtransaction;
1120 friend class internal::gate::connection_sql_cursor;
1121
1122 result exec_params(std::string_view query, internal::c_params const &args);
1123
1125 internal::pq::PGconn *m_conn = nullptr;
1126
1128
1135 transaction_base const *m_trans = nullptr;
1136
1137 std::list<errorhandler *> m_errorhandlers;
1138
1139 using receiver_list =
1140 std::multimap<std::string, pqxx::notification_receiver *>;
1142 receiver_list m_receivers;
1143
1145 int m_unique_id = 0;
1146};
1147
1148
1150using connection_base = connection;
1151
1152
1154
1197class PQXX_LIBEXPORT connecting
1198{
1199public:
1201 connecting(zview connection_string = ""_zv);
1202
1203 connecting(connecting const &) = delete;
1204 connecting(connecting &&) = default;
1205 connecting &operator=(connecting const &) = delete;
1206 connecting &operator=(connecting &&) = default;
1207
1209 [[nodiscard]] int sock() const & noexcept { return m_conn.sock(); }
1210
1212 [[nodiscard]] constexpr bool wait_to_read() const & noexcept
1213 {
1214 return m_reading;
1215 }
1216
1218 [[nodiscard]] constexpr bool wait_to_write() const & noexcept
1219 {
1220 return m_writing;
1221 }
1222
1224 void process() &;
1225
1227 [[nodiscard]] constexpr bool done() const & noexcept
1228 {
1229 return not m_reading and not m_writing;
1230 }
1231
1233
1241 [[nodiscard]] connection produce() &&;
1242
1243private:
1244 connection m_conn;
1245 bool m_reading{false};
1246 bool m_writing{true};
1247};
1248
1249
1250template<typename T> inline std::string connection::quote(T const &t) const
1251{
1252 if constexpr (nullness<T>::always_null)
1253 {
1254 return "NULL";
1255 }
1256 else
1257 {
1258 if (is_null(t))
1259 return "NULL";
1260 auto const text{to_string(t)};
1261
1262 // Okay, there's an easy way to do this and there's a hard way. The easy
1263 // way was "quote, esc(to_string(t)), quote". I'm going with the hard way
1264 // because it's going to save some string manipulation that will probably
1265 // incur some unnecessary memory allocations and deallocations.
1266 std::string buf{'\''};
1267 buf.resize(2 + 2 * std::size(text) + 1);
1268 auto const content_bytes{esc_to_buf(text, buf.data() + 1)};
1269 auto const closing_quote{1 + content_bytes};
1270 buf[closing_quote] = '\'';
1271 auto const end{closing_quote + 1};
1272 buf.resize(end);
1273 return buf;
1274 }
1275}
1276
1277
1278template<PQXX_CHAR_STRINGS_ARG STRINGS>
1279inline std::string connection::quote_columns(STRINGS const &columns) const
1280{
1281 return separated_list(
1282 ","sv, std::cbegin(columns), std::cend(columns),
1283 [this](auto col) { return this->quote_name(*col); });
1284}
1285
1286
1287#if defined(PQXX_HAVE_CONCEPTS)
1288template<internal::ZKey_ZValues MAPPING>
1289inline connection::connection(MAPPING const &params)
1290{
1291 check_version();
1292
1293 std::vector<char const *> keys, values;
1294 if constexpr (std::ranges::sized_range<MAPPING>)
1295 {
1296 auto const size{std::ranges::size(params) + 1};
1297 keys.reserve(size);
1298 values.reserve(size);
1299 }
1300 for (auto const &[key, value] : params)
1301 {
1302 keys.push_back(internal::as_c_string(key));
1303 values.push_back(internal::as_c_string(value));
1304 }
1305 keys.push_back(nullptr);
1306 values.push_back(nullptr);
1307 init(std::data(keys), std::data(values));
1308}
1309#endif // PQXX_HAVE_CONCEPTS
1310
1311
1313[[nodiscard,
1314 deprecated("Use connection::encrypt_password instead.")]] std::string
1315 PQXX_LIBEXPORT
1316 encrypt_password(char const user[], char const password[]);
1317
1319[[nodiscard,
1320 deprecated("Use connection::encrypt_password instead.")]] inline std::string
1322{
1323#include "pqxx/internal/ignore-deprecated-pre.hxx"
1324 return encrypt_password(user.c_str(), password.c_str());
1325#include "pqxx/internal/ignore-deprecated-post.hxx"
1326}
1327} // namespace pqxx
1328#endif
Marker-type wrapper: zero-terminated std::string_view.
Definition zview.hxx:38
constexpr char const * c_str() const &noexcept
Either a null pointer, or a zero-terminated text buffer.
Definition zview.hxx:96
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
constexpr std::size_t size_unesc_bin(std::size_t escaped_bytes) noexcept
Compute binary size from the size of its escaped version.
Definition util.hxx:525
The home of all libpqxx classes, functions, templates, etc.
Definition array.cxx:27
std::string encrypt_password(zview user, zview password)
Encrypt password.
Definition connection.hxx:1321
std::string separated_list(std::string_view sep, ITER begin, ITER end, ACCESS access)
Represent sequence of values as a string, joined by a given separator.
Definition separated_list.hxx:46
PQXX_PRIVATE void check_version() noexcept
Definition util.hxx:236
std::conditional< has_generic_bytes_char_traits, std::basic_string_view< std::byte >, std::basic_string_view< std::byte, byte_char_traits > >::type bytes_view
Type alias for a view of bytes.
Definition util.hxx:383
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
void skip_init_ssl() noexcept
Control initialisation of OpenSSL and libcrypto libraries.
Definition connection.hxx:167
bytes_view binary_cast(TYPE const &data)
Cast binary data to a type that libpqxx will recognise as binary.
Definition util.hxx:409
std::initializer_list< std::string_view > table_path
Representation of a PostgreSQL table path.
Definition connection.hxx:182
constexpr bool is_null(TYPE const &value) noexcept
Is value null?
Definition strconv.hxx:514
skip_init
Flags for skipping initialisation of SSL-related libraries.
Definition connection.hxx:131
@ crypto
Skip initialisation of libcrypto.
Definition connection.hxx:139
@ openssl
Skip initialisation of OpenSSL library.
Definition connection.hxx:136
@ nothing
A do-nothing flag that does not affect anything.
Definition connection.hxx:133
connection connection_base
Definition connection.hxx:1150
error_verbosity
Error verbosity levels.
Definition connection.hxx:187