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 <functional>
23#include <initializer_list>
24#include <list>
25#include <map>
26#include <memory>
27#include <string_view>
28#include <tuple>
29#include <utility>
30
31// Double-check in order to suppress an overzealous Visual C++ warning (#418).
32#if defined(PQXX_HAVE_CONCEPTS) && __has_include(<ranges>)
33# include <ranges>
34#endif
35
36#include "pqxx/errorhandler.hxx"
37#include "pqxx/except.hxx"
38#include "pqxx/internal/concat.hxx"
39#include "pqxx/params.hxx"
40#include "pqxx/separated_list.hxx"
41#include "pqxx/strconv.hxx"
42#include "pqxx/types.hxx"
43#include "pqxx/util.hxx"
44#include "pqxx/zview.hxx"
45
46
78
79namespace pqxx::internal
80{
81class sql_cursor;
82
83#if defined(PQXX_HAVE_CONCEPTS)
85template<typename T>
86concept ZKey_ZValues = std::ranges::input_range<T> and requires(T t) {
87 { std::cbegin(t) };
88 { std::get<0>(*std::cbegin(t)) } -> ZString;
89 { std::get<1>(*std::cbegin(t)) } -> ZString;
90} and std::tuple_size_v<typename std::ranges::iterator_t<T>::value_type> == 2;
91#endif // PQXX_HAVE_CONCEPTS
92
93
95
102void PQXX_COLD PQXX_LIBEXPORT skip_init_ssl(int skips) noexcept;
103} // namespace pqxx::internal
104
105
106namespace pqxx::internal::gate
107{
108class connection_dbtransaction;
111class connection_notification_receiver;
112class connection_pipeline;
114struct connection_stream_from;
115class connection_stream_to;
118} // namespace pqxx::internal::gate
119
120
121namespace pqxx
122{
124
136{
138
143 connection &conn;
144
146
150
152
155
157
168};
169
170
172
179enum skip_init : int
180{
183
186
189};
190
191
193
216template<skip_init... SKIP> inline void skip_init_ssl() noexcept
217{
218 // (Normalise skip flags to one per.)
219 pqxx::internal::skip_init_ssl(((1 << SKIP) | ...));
220}
221
222
224
231using table_path = std::initializer_list<std::string_view>;
232
233
235enum class error_verbosity : int
236{
237 // These values must match those in libpq's PGVerbosity enum.
238 terse = 0,
239 normal = 1,
240 verbose = 2
241};
242
243
245
278class PQXX_LIBEXPORT connection
279{
280public:
281 connection() : connection{""} {}
282
284 explicit connection(char const options[])
285 {
287 init(options);
288 }
289
291 explicit connection(zview options) : connection{options.c_str()}
292 {
293 // (Delegates to other constructor which calls check_version for us.)
294 }
295
297
302 connection(connection &&rhs);
303
304#if defined(PQXX_HAVE_CONCEPTS)
306
321 template<internal::ZKey_ZValues MAPPING>
322 inline connection(MAPPING const &params);
323#endif // PQXX_HAVE_CONCEPTS
324
325 ~connection()
326 {
327 try
328 {
329 close();
330 }
331 catch (std::exception const &)
332 {}
333 }
334
335 // TODO: Once we drop notification_receiver/errorhandler, move is easier.
337
340 connection &operator=(connection &&rhs);
341
342 connection(connection const &) = delete;
343 connection &operator=(connection const &) = delete;
344
346
351 [[nodiscard]] bool PQXX_PURE is_open() const noexcept;
352
354 void process_notice(char const[]) noexcept;
356
359 void process_notice(zview) noexcept;
360
362 void trace(std::FILE *) noexcept;
363
374
376 [[nodiscard]] char const *dbname() const;
377
379
380 [[nodiscard]] char const *username() const;
381
383
386 [[nodiscard]] char const *hostname() const;
387
389 [[nodiscard]] char const *port() const;
390
392 [[nodiscard]] int PQXX_PURE backendpid() const & noexcept;
393
395
405 [[nodiscard]] int PQXX_PURE sock() const & noexcept;
406
408
411 [[nodiscard]] int PQXX_PURE protocol_version() const noexcept;
412
414
426 [[nodiscard]] int PQXX_PURE server_version() const noexcept;
428
430
450
451 [[nodiscard]] std::string get_client_encoding() const;
452
454
457 void set_client_encoding(zview encoding) &
458 {
459 set_client_encoding(encoding.c_str());
460 }
461
463
466 void set_client_encoding(char const encoding[]) &;
467
469 [[nodiscard]] int encoding_id() const;
470
472
474
495 template<typename TYPE>
496 void set_session_var(std::string_view var, TYPE const &value) &
497 {
498 if constexpr (nullness<TYPE>::has_null)
499 {
500 if (nullness<TYPE>::is_null(value))
501 throw variable_set_to_null{
502 internal::concat("Attempted to set variable ", var, " to null.")};
503 }
504 exec(internal::concat("SET ", quote_name(var), "=", quote(value)));
505 }
506
508
514 std::string get_var(std::string_view var);
515
517
523 template<typename TYPE> TYPE get_var_as(std::string_view var)
524 {
525 return from_string<TYPE>(get_var(var));
526 }
527
618
636 int get_notifs();
637
639
653 int await_notification();
654
656
672 int await_notification(std::time_t seconds, long microseconds = 0);
673
675
682 using notification_handler = std::function<void(notification)>;
683
685
706 void listen(std::string_view channel, notification_handler handler = {});
707
709
740
741 [[nodiscard]] std::string
742 encrypt_password(zview user, zview password, zview algorithm)
743 {
744 return encrypt_password(user.c_str(), password.c_str(), algorithm.c_str());
745 }
747 [[nodiscard]] std::string encrypt_password(
748 char const user[], char const password[], char const *algorithm = nullptr);
750
793
795
799 void prepare(zview name, zview definition) &
800 {
801 prepare(name.c_str(), definition.c_str());
802 }
803
808 void prepare(char const name[], char const definition[]) &;
809
811
818 void prepare(char const definition[]) &;
819 void prepare(zview definition) & { return prepare(definition.c_str()); }
820
822 void unprepare(std::string_view name);
823
825
826 // C++20: constexpr. Breaks ABI.
828
831 [[nodiscard]] std::string adorn_name(std::string_view);
832
837
839 [[nodiscard]] std::string esc(char const text[]) const
840 {
841 return esc(std::string_view{text});
842 }
843
844#if defined(PQXX_HAVE_SPAN)
846
857 [[nodiscard]] std::string_view
858 esc(std::string_view text, std::span<char> buffer)
859 {
860 auto const size{std::size(text)}, space{std::size(buffer)};
861 auto const needed{2 * size + 1};
862 if (space < needed)
863 throw range_error{internal::concat(
864 "Not enough room to escape string of ", size, " byte(s): need ",
865 needed, " bytes of buffer space, but buffer size is ", space, ".")};
866 auto const data{buffer.data()};
867 return {data, esc_to_buf(text, data)};
868 }
869#endif
870
872
875 [[nodiscard]] std::string esc(std::string_view text) const;
876
877#if defined(PQXX_HAVE_CONCEPTS)
879
880 template<binary DATA> [[nodiscard]] std::string esc(DATA const &data) const
881 {
882 return esc_raw(data);
883 }
884#endif
885
886#if defined(PQXX_HAVE_CONCEPTS) && defined(PQXX_HAVE_SPAN)
888
899 template<binary DATA>
900 [[nodiscard]] zview esc(DATA const &data, std::span<char> buffer) const
901 {
902 auto const size{std::size(data)}, space{std::size(buffer)};
903 auto const needed{internal::size_esc_bin(std::size(data))};
904 if (space < needed)
905 throw range_error{internal::concat(
906 "Not enough room to escape binary string of ", size, " byte(s): need ",
907 needed, " bytes of buffer space, but buffer size is ", space, ".")};
908
909 bytes_view view{std::data(data), std::size(data)};
910 auto const out{std::data(buffer)};
911 // Actually, in the modern format, we know beforehand exactly how many
912 // bytes we're going to fill. Just leave out the trailing zero.
913 internal::esc_bin(view, out);
914 return zview{out, needed - 1};
915 }
916#endif
917
919 [[deprecated("Use std::byte for binary data.")]] std::string
920 esc_raw(unsigned char const bin[], std::size_t len) const;
921
923
924 [[nodiscard]] std::string esc_raw(bytes_view) const;
925
926#if defined(PQXX_HAVE_SPAN)
928
929 [[nodiscard]] std::string esc_raw(bytes_view, std::span<char> buffer) const;
930#endif
931
932#if defined(PQXX_HAVE_CONCEPTS)
934
935 template<binary DATA>
936 [[nodiscard]] std::string esc_raw(DATA const &data) const
937 {
938 return esc_raw(bytes_view{std::data(data), std::size(data)});
939 }
940#endif
941
942#if defined(PQXX_HAVE_CONCEPTS) && defined(PQXX_HAVE_SPAN)
944 template<binary DATA>
945 [[nodiscard]] zview esc_raw(DATA const &data, std::span<char> buffer) const
946 {
947 return this->esc(binary_cast(data), buffer);
948 }
949#endif
950
951 // TODO: Make "into buffer" variant to eliminate a string allocation.
953
960 [[nodiscard]] bytes unesc_bin(std::string_view text) const
961 {
962 bytes buf;
963 buf.resize(pqxx::internal::size_unesc_bin(std::size(text)));
964 pqxx::internal::unesc_bin(text, buf.data());
965 return buf;
966 }
967
969 std::string quote_raw(bytes_view) const;
970
971#if defined(PQXX_HAVE_CONCEPTS)
973
974 template<binary DATA>
975 [[nodiscard]] std::string quote_raw(DATA const &data) const
976 {
977 return quote_raw(bytes_view{std::data(data), std::size(data)});
978 }
979#endif
980
981 // TODO: Make "into buffer" variant to eliminate a string allocation.
983 [[nodiscard]] std::string quote_name(std::string_view identifier) const;
984
985 // TODO: Make "into buffer" variant to eliminate a string allocation.
987
990 [[nodiscard]] std::string quote_table(std::string_view name) const;
991
992 // TODO: Make "into buffer" variant to eliminate a string allocation.
994
1002 [[nodiscard]] std::string quote_table(table_path) const;
1003
1004 // TODO: Make "into buffer" variant to eliminate a string allocation.
1006
1013 template<PQXX_CHAR_STRINGS_ARG STRINGS>
1014 inline std::string quote_columns(STRINGS const &columns) const;
1015
1016 // TODO: Make "into buffer" variant to eliminate a string allocation.
1018
1021 template<typename T>
1022 [[nodiscard]] inline std::string quote(T const &t) const;
1023
1024 [[deprecated("Use std::byte for binary data.")]] std::string
1025 quote(binarystring const &) const;
1026
1027 // TODO: Make "into buffer" variant to eliminate a string allocation.
1029 [[nodiscard]] std::string quote(bytes_view bytes) const;
1030
1031 // TODO: Make "into buffer" variant to eliminate a string allocation.
1033
1058 [[nodiscard]] std::string
1059 esc_like(std::string_view text, char escape_char = '\\') const;
1060
1062
1066 [[deprecated("Use std::string_view or pqxx:zview.")]] std::string
1067 esc(char const text[], std::size_t maxlen) const
1068 {
1069 return esc(std::string_view{text, maxlen});
1070 }
1071
1073
1076 [[nodiscard, deprecated("Use unesc_bin() instead.")]] std::string
1077 unesc_raw(zview text) const
1078 {
1079#include "pqxx/internal/ignore-deprecated-pre.hxx"
1080 return unesc_raw(text.c_str());
1081#include "pqxx/internal/ignore-deprecated-post.hxx"
1082 }
1083
1085
1088 [[nodiscard, deprecated("Use unesc_bin() instead.")]] std::string
1089 unesc_raw(char const text[]) const;
1090
1092 [[deprecated("Use quote(bytes_view).")]] std::string
1093 quote_raw(unsigned char const bin[], std::size_t len) const;
1095
1097
1101 void cancel_query();
1102
1103#if defined(_WIN32) || __has_include(<fcntl.h>)
1105
1109 void set_blocking(bool block) &;
1110#endif // defined(_WIN32) || __has_include(<fcntl.h>)
1111
1113
1125 void set_verbosity(error_verbosity verbosity) & noexcept;
1126
1127 // C++20: Use std::callable.
1128
1130
1142 void set_notice_handler(std::function<void(zview)> handler)
1143 {
1144 m_notice_waiters->notice_handler = std::move(handler);
1145 }
1146
1148
1153 [[nodiscard, deprecated("Use a notice handler instead.")]]
1154 std::vector<errorhandler *> get_errorhandlers() const;
1155
1157
1163 [[nodiscard]] std::string connection_string() const;
1164
1166
1174 void close();
1175
1177
1183 static connection seize_raw_connection(internal::pq::PGconn *raw_conn)
1184 {
1185 return connection{raw_conn};
1186 }
1187
1189
1194 internal::pq::PGconn *release_raw_connection() &&
1195 {
1196 return std::exchange(m_conn, nullptr);
1197 }
1198
1200
1213 [[deprecated("To set session variables, use set_session_var.")]] void
1214 set_variable(std::string_view var, std::string_view value) &;
1215
1217
1220 [[deprecated("Use get_var instead.")]] std::string
1221 get_variable(std::string_view);
1222
1223private:
1224 friend class connecting;
1225 enum connect_mode
1226 {
1227 connect_nonblocking
1228 };
1229 connection(connect_mode, zview connection_string);
1230
1232 explicit connection(internal::pq::PGconn *raw_conn);
1233
1235
1240 std::pair<bool, bool> poll_connect();
1241
1242 // Initialise based on connection string.
1243 void init(char const options[]);
1244 // Initialise based on parameter names and values.
1245 void init(char const *params[], char const *values[]);
1246 void set_up_notice_handlers();
1247 void complete_init();
1248
1249 result make_result(
1250 internal::pq::PGresult *pgr, std::shared_ptr<std::string> const &query,
1251 std::string_view desc = ""sv);
1252
1253 void PQXX_PRIVATE set_up_state();
1254
1255 int PQXX_PRIVATE PQXX_PURE status() const noexcept;
1256
1258
1262 std::size_t esc_to_buf(std::string_view text, char *buf) const;
1263
1264 friend class internal::gate::const_connection_largeobject;
1265 char const *PQXX_PURE err_msg() const noexcept;
1266
1267 result exec_prepared(std::string_view statement, internal::c_params const &);
1268
1270 void check_movable() const;
1272 void check_overwritable() const;
1273
1274 friend class internal::gate::connection_errorhandler;
1275 void PQXX_PRIVATE register_errorhandler(errorhandler *);
1276 void PQXX_PRIVATE unregister_errorhandler(errorhandler *) noexcept;
1277
1278 friend class internal::gate::connection_transaction;
1279 result exec(std::string_view, std::string_view = ""sv);
1280 result PQXX_PRIVATE
1281 exec(std::shared_ptr<std::string> const &, std::string_view = ""sv);
1282 void PQXX_PRIVATE register_transaction(transaction_base *);
1283 void PQXX_PRIVATE unregister_transaction(transaction_base *) noexcept;
1284
1285 friend struct internal::gate::connection_stream_from;
1287
1292 std::pair<std::unique_ptr<char, void (*)(void const *)>, std::size_t>
1293 read_copy_line();
1294
1295 friend class internal::gate::connection_stream_to;
1296 void PQXX_PRIVATE write_copy_line(std::string_view);
1297 void PQXX_PRIVATE end_copy_write();
1298
1299 friend class internal::gate::connection_largeobject;
1300 internal::pq::PGconn *raw_connection() const { return m_conn; }
1301
1302 friend class internal::gate::connection_notification_receiver;
1303 void add_receiver(notification_receiver *);
1304 void remove_receiver(notification_receiver *) noexcept;
1305
1306 friend class internal::gate::connection_pipeline;
1307 void PQXX_PRIVATE start_exec(char const query[]);
1308 bool PQXX_PRIVATE consume_input() noexcept;
1309 bool PQXX_PRIVATE is_busy() const noexcept;
1310 internal::pq::PGresult *get_result();
1311
1312 friend class internal::gate::connection_dbtransaction;
1313 friend class internal::gate::connection_sql_cursor;
1314
1315 result exec_params(std::string_view query, internal::c_params const &args);
1316
1318 internal::pq::PGconn *m_conn = nullptr;
1319
1321
1328 transaction_base const *m_trans = nullptr;
1329
1331 std::shared_ptr<pqxx::internal::notice_waiters> m_notice_waiters;
1332
1333 // TODO: Remove these when we retire notification_receiver.
1334 // TODO: Can we make these movable?
1335 using receiver_list =
1336 std::multimap<std::string, pqxx::notification_receiver *>;
1338 receiver_list m_receivers;
1339
1341
1348 std::map<std::string, notification_handler> m_notification_handlers;
1349
1351 int m_unique_id = 0;
1352};
1353
1354
1356using connection_base = connection;
1357
1358
1360
1403class PQXX_LIBEXPORT connecting
1404{
1405public:
1407 connecting(zview connection_string = ""_zv);
1408
1409 connecting(connecting const &) = delete;
1410 connecting(connecting &&) = default;
1411 connecting &operator=(connecting const &) = delete;
1412 connecting &operator=(connecting &&) = default;
1413
1415 [[nodiscard]] int sock() const & noexcept { return m_conn.sock(); }
1416
1418 [[nodiscard]] constexpr bool wait_to_read() const & noexcept
1419 {
1420 return m_reading;
1421 }
1422
1424 [[nodiscard]] constexpr bool wait_to_write() const & noexcept
1425 {
1426 return m_writing;
1427 }
1428
1430 void process() &;
1431
1433 [[nodiscard]] constexpr bool done() const & noexcept
1434 {
1435 return not m_reading and not m_writing;
1436 }
1437
1439
1447 [[nodiscard]] connection produce() &&;
1448
1449private:
1450 connection m_conn;
1451 bool m_reading{false};
1452 bool m_writing{true};
1453};
1454
1455
1456template<typename T> inline std::string connection::quote(T const &t) const
1457{
1458 if constexpr (nullness<T>::always_null)
1459 {
1460 return "NULL";
1461 }
1462 else
1463 {
1464 if (is_null(t))
1465 return "NULL";
1466 auto const text{to_string(t)};
1467
1468 // Okay, there's an easy way to do this and there's a hard way. The easy
1469 // way was "quote, esc(to_string(t)), quote". I'm going with the hard way
1470 // because it's going to save some string manipulation that will probably
1471 // incur some unnecessary memory allocations and deallocations.
1472 std::string buf{'\''};
1473 buf.resize(2 + 2 * std::size(text) + 1);
1474 auto const content_bytes{esc_to_buf(text, buf.data() + 1)};
1475 auto const closing_quote{1 + content_bytes};
1476 buf[closing_quote] = '\'';
1477 auto const end{closing_quote + 1};
1478 buf.resize(end);
1479 return buf;
1480 }
1481}
1482
1483
1484template<PQXX_CHAR_STRINGS_ARG STRINGS>
1485inline std::string connection::quote_columns(STRINGS const &columns) const
1486{
1487 return separated_list(
1488 ","sv, std::cbegin(columns), std::cend(columns),
1489 [this](auto col) { return this->quote_name(*col); });
1490}
1491
1492
1493#if defined(PQXX_HAVE_CONCEPTS)
1494template<internal::ZKey_ZValues MAPPING>
1495inline connection::connection(MAPPING const &params)
1496{
1497 check_version();
1498
1499 std::vector<char const *> keys, values;
1500 if constexpr (std::ranges::sized_range<MAPPING>)
1501 {
1502 auto const size{std::ranges::size(params) + 1};
1503 keys.reserve(size);
1504 values.reserve(size);
1505 }
1506 for (auto const &[key, value] : params)
1507 {
1508 keys.push_back(internal::as_c_string(key));
1509 values.push_back(internal::as_c_string(value));
1510 }
1511 keys.push_back(nullptr);
1512 values.push_back(nullptr);
1513 init(std::data(keys), std::data(values));
1514}
1515#endif // PQXX_HAVE_CONCEPTS
1516
1517
1519[[nodiscard,
1520 deprecated("Use connection::encrypt_password instead.")]] std::string
1521 PQXX_LIBEXPORT
1522 encrypt_password(char const user[], char const password[]);
1523
1525[[nodiscard,
1526 deprecated("Use connection::encrypt_password instead.")]] inline std::string
1528{
1529#include "pqxx/internal/ignore-deprecated-pre.hxx"
1530 return encrypt_password(user.c_str(), password.c_str());
1531#include "pqxx/internal/ignore-deprecated-post.hxx"
1532}
1533} // namespace pqxx
1534#endif
Definition connection-errorhandler.hxx:12
Definition connection-largeobject.hxx:16
Definition connection-sql_cursor.hxx:12
Definition connection-transaction.hxx:11
Definition connection-largeobject.hxx:27
Cursor with SQL positioning semantics.
Definition sql_cursor.hxx:32
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:166
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:1527
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:216
bytes_view binary_cast(TYPE const &data)
End a code block started by "ignore-deprecated-pre.hxx".
Definition util.hxx:409
std::initializer_list< std::string_view > table_path
Representation of a PostgreSQL table path.
Definition connection.hxx:231
connection & conn
The connection which received the notification.
Definition connection.hxx:143
constexpr bool is_null(TYPE const &value) noexcept
Is value null?
Definition strconv.hxx:515
int backend_pid
Process ID of the backend that sent the notification.
Definition connection.hxx:167
skip_init
Flags for skipping initialisation of SSL-related libraries.
Definition connection.hxx:180
@ crypto
Skip initialisation of libcrypto.
Definition connection.hxx:188
@ openssl
Skip initialisation of OpenSSL library.
Definition connection.hxx:185
@ nothing
A do-nothing flag that does not affect anything.
Definition connection.hxx:182
zview channel
Channel name.
Definition connection.hxx:149
connection connection_base
Definition connection.hxx:1356
zview payload
Optional payload text.
Definition connection.hxx:154
error_verbosity
Error verbosity levels.
Definition connection.hxx:236
An incoming notification.
Definition connection.hxx:136