libpqxx 7.7.0
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-2022, 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#include <cstddef>
17#include <ctime>
18#include <functional>
19#include <initializer_list>
20#include <list>
21#include <map>
22#include <memory>
23#include <string_view>
24#include <tuple>
25
26// Double-check in order to suppress an overzealous Visual C++ warning (#418).
27#if defined(PQXX_HAVE_CONCEPTS) && __has_include(<ranges>)
28# include <ranges>
29#endif
30
31#include "pqxx/errorhandler.hxx"
32#include "pqxx/except.hxx"
33#include "pqxx/internal/concat.hxx"
34#include "pqxx/params.hxx"
35#include "pqxx/separated_list.hxx"
36#include "pqxx/strconv.hxx"
37#include "pqxx/types.hxx"
38#include "pqxx/util.hxx"
39#include "pqxx/zview.hxx"
40
41
72namespace pqxx::internal
73{
74class sql_cursor;
75
76#if defined(PQXX_HAVE_CONCEPTS)
78template<typename T>
79concept ZKey_ZValues = std::ranges::input_range<T> and requires(T t)
80{
81 {std::cbegin(t)};
82 {
83 std::get<0>(*std::cbegin(t))
84 } -> ZString;
85 {
86 std::get<1>(*std::cbegin(t))
87 } -> ZString;
88} and std::tuple_size_v<typename std::ranges::iterator_t<T>::value_type>
89== 2;
90#endif // PQXX_HAVE_CONCEPTS
91} // namespace pqxx::internal
92
93
95{
96class connection_dbtransaction;
97class connection_errorhandler;
98class connection_largeobject;
99class connection_notification_receiver;
100class connection_pipeline;
101class connection_sql_cursor;
102class connection_stream_from;
103class connection_stream_to;
104class connection_transaction;
105class const_connection_largeobject;
106} // namespace pqxx::internal::gate
107
108
109namespace pqxx
110{
112
119using table_path = std::initializer_list<std::string_view>;
120
121
123[[nodiscard,
124 deprecated("Use connection::encrypt_password instead.")]] std::string
125 PQXX_LIBEXPORT
126 encrypt_password(char const user[], char const password[]);
127
129[[nodiscard,
130 deprecated("Use connection::encrypt_password instead.")]] inline std::string
132{
133#include "pqxx/internal/ignore-deprecated-pre.hxx"
134 return encrypt_password(user.c_str(), password.c_str());
135#include "pqxx/internal/ignore-deprecated-post.hxx"
136}
137
138
140enum class error_verbosity : int
141{
142 // These values must match those in libpq's PGVerbosity enum.
143 terse = 0,
144 normal = 1,
145 verbose = 2
146};
147
148
150
180class PQXX_LIBEXPORT connection
181{
182public:
184
186 explicit connection(char const options[])
187 {
189 init(options);
190 }
191
193 explicit connection(zview options) : connection{options.c_str()}
194 {
195 // (Delegates to other constructor which calls check_version for us.)
196 }
197
199
204 connection(connection &&rhs);
205
206#if defined(PQXX_HAVE_CONCEPTS)
208
223 template<internal::ZKey_ZValues MAPPING>
224 inline connection(MAPPING const &params);
225#endif // PQXX_HAVE_CONCEPTS
226
228 {
229 try
230 {
231 close();
232 }
233 catch (std::exception const &)
234 {}
235 }
236
238
241 connection &operator=(connection &&rhs);
242
243 connection(connection const &) = delete;
244 connection &operator=(connection const &) = delete;
245
247
252 [[nodiscard]] bool PQXX_PURE is_open() const noexcept;
253
255 void process_notice(char const[]) noexcept;
257
260 void process_notice(zview) noexcept;
261
263 void trace(std::FILE *) noexcept;
264
276 [[nodiscard]] char const *dbname() const;
277
279 [[nodiscard]] char const *username() const;
280
282 [[nodiscard]] char const *hostname() const;
283
285 [[nodiscard]] char const *port() const;
286
288 [[nodiscard]] int PQXX_PURE backendpid() const &noexcept;
289
291
301 [[nodiscard]] int PQXX_PURE sock() const &noexcept;
302
304
307 [[nodiscard]] int PQXX_PURE protocol_version() const noexcept;
308
310
322 [[nodiscard]] int PQXX_PURE server_version() const noexcept;
324
326
347 [[nodiscard]] std::string get_client_encoding() const;
348
350
353 void set_client_encoding(zview encoding) &
354 {
355 set_client_encoding(encoding.c_str());
356 }
357
359
362 void set_client_encoding(char const encoding[]) &;
363
365 [[nodiscard]] int PQXX_PRIVATE encoding_id() const;
366
368
370
385 void set_variable(std::string_view var, std::string_view value) &;
386
388
391 std::string get_variable(std::string_view);
393
394
400
417 int get_notifs();
418
420
432 int await_notification();
433
435
447 int await_notification(std::time_t seconds, long microseconds);
449
481 [[nodiscard]] std::string
482 encrypt_password(zview user, zview password, zview algorithm)
483 {
484 return encrypt_password(user.c_str(), password.c_str(), algorithm.c_str());
485 }
487 [[nodiscard]] std::string encrypt_password(
488 char const user[], char const password[], char const *algorithm = nullptr);
490
533
535
539 void prepare(zview name, zview definition) &
540 {
541 prepare(name.c_str(), definition.c_str());
542 }
543
548 void prepare(char const name[], char const definition[]) &;
549
551
558 void prepare(char const definition[]) &;
559 void prepare(zview definition) & { return prepare(definition.c_str()); }
560
562 void unprepare(std::string_view name);
563
565
567
570 [[nodiscard]] std::string adorn_name(std::string_view);
571
576
578
582 [[deprecated("Use std::string_view or pqxx:zview.")]] std::string
583 esc(char const text[], std::size_t maxlen) const
584 {
585 return esc(std::string_view{text, maxlen});
586 }
587
589 [[nodiscard]] std::string esc(char const text[]) const
590 {
591 return esc(std::string_view{text});
592 }
593
594#if defined(PQXX_HAVE_SPAN)
596
607 [[nodiscard]] std::string_view
608 esc(std::string_view text, std::span<char> buffer)
609 {
610 auto const size{std::size(text)}, space{std::size(buffer)};
611 auto const needed{2 * size + 1};
612 if (space < needed)
613 throw range_error{internal::concat(
614 "Not enough room to escape string of ", size, " byte(s): need ",
615 needed, " bytes of buffer space, but buffer size is ", space, ".")};
616 auto const data{buffer.data()};
617 return {data, esc_to_buf(text, data)};
618 }
619#endif
620
622
625 [[nodiscard]] std::string esc(std::string_view text) const;
626
627#if defined(PQXX_HAVE_CONCEPTS)
629
630 template<binary DATA> [[nodiscard]] std::string esc(DATA const &data) const
631 {
632 return esc_raw(data);
633 }
634#endif
635
636#if defined(PQXX_HAVE_CONCEPTS) && defined(PQXX_HAVE_SPAN)
638
649 template<binary DATA>
650 [[nodiscard]] zview esc(DATA const &data, std::span<char> buffer) const
651 {
652 auto const size{std::size(data)}, space{std::size(buffer)};
653 auto const needed{internal::size_esc_bin(std::size(data))};
654 if (space < needed)
655 throw range_error{internal::concat(
656 "Not enough room to escape binary string of ", size, " byte(s): need ",
657 needed, " bytes of buffer space, but buffer size is ", space, ".")};
658
659 std::basic_string_view<std::byte> view{std::data(data), std::size(data)};
660 auto const out{std::data(buffer)};
661 // Actually, in the modern format, we know beforehand exactly how many
662 // bytes we're going to fill. Just leave out the trailing zero.
663 internal::esc_bin(view, out);
664 return zview{out, needed - 1};
665 }
666#endif
667
669 [[deprecated("Use std::byte for binary data.")]] std::string
670 esc_raw(unsigned char const bin[], std::size_t len) const;
671
673
674 [[nodiscard]] std::string esc_raw(std::basic_string_view<std::byte>) const;
675
676#if defined(PQXX_HAVE_SPAN)
678
679 [[nodiscard]] std::string
680 esc_raw(std::basic_string_view<std::byte>, std::span<char> buffer) const;
681#endif
682
683#if defined(PQXX_HAVE_CONCEPTS)
685
686 template<binary DATA>
687 [[nodiscard]] std::string esc_raw(DATA const &data) const
688 {
689 return esc_raw(
690 std::basic_string_view<std::byte>{std::data(data), std::size(data)});
691 }
692#endif
693
694#if defined(PQXX_HAVE_CONCEPTS) && defined(PQXX_HAVE_SPAN)
696 template<binary DATA>
697 [[nodiscard]] zview esc_raw(DATA const &data, std::span<char> buffer) const
698 {
699 return this->esc(binary_cast(data), buffer);
700 }
701#endif
702
704
707 [[nodiscard, deprecated("Use unesc_bin() instead.")]] std::string
708 unesc_raw(zview text) const
709 {
710#include "pqxx/internal/ignore-deprecated-pre.hxx"
711 return unesc_raw(text.c_str());
712#include "pqxx/internal/ignore-deprecated-post.hxx"
713 }
714
716
719 [[nodiscard, deprecated("Use unesc_bin() instead.")]] std::string
720 unesc_raw(char const text[]) const;
721
722 // TODO: Make "into buffer" variant to eliminate a string allocation.
724
731 [[nodiscard]] std::basic_string<std::byte>
732 unesc_bin(std::string_view text) const
733 {
734 std::basic_string<std::byte> buf;
735 buf.resize(pqxx::internal::size_unesc_bin(std::size(text)));
736 pqxx::internal::unesc_bin(text, buf.data());
737 return buf;
738 }
739
741 [[deprecated("Use quote(std::basic_string_view<std::byte>).")]] std::string
742 quote_raw(unsigned char const bin[], std::size_t len) const;
743
745 std::string quote_raw(std::basic_string_view<std::byte>) const;
746
747#if defined(PQXX_HAVE_CONCEPTS)
749
750 template<binary DATA>
751 [[nodiscard]] std::string quote_raw(DATA const &data) const
752 {
753 return quote_raw(
754 std::basic_string_view<std::byte>{std::data(data), std::size(data)});
755 }
756#endif
757
758 // TODO: Make "into buffer" variant to eliminate a string allocation.
760 [[nodiscard]] std::string quote_name(std::string_view identifier) const;
761
762 // TODO: Make "into buffer" variant to eliminate a string allocation.
764
767 [[nodiscard]] std::string quote_table(std::string_view name) const;
768
769 // TODO: Make "into buffer" variant to eliminate a string allocation.
771
779 [[nodiscard]] std::string quote_table(table_path) const;
780
781 // TODO: Make "into buffer" variant to eliminate a string allocation.
783
790 template<PQXX_CHAR_STRINGS_ARG STRINGS>
791 inline std::string quote_columns(STRINGS const &columns) const;
792
793 // TODO: Make "into buffer" variant to eliminate a string allocation.
795
798 template<typename T>
799 [[nodiscard]] inline std::string quote(T const &t) const;
800
801 [[deprecated("Use std::byte for binary data.")]] std::string
802 quote(binarystring const &) const;
803
804 // TODO: Make "into buffer" variant to eliminate a string allocation.
806 [[nodiscard]] std::string
807 quote(std::basic_string_view<std::byte> bytes) const;
808
809 // TODO: Make "into buffer" variant to eliminate a string allocation.
811
836 [[nodiscard]] std::string
837 esc_like(std::string_view text, char escape_char = '\\') const;
839
841
845 void cancel_query();
846
847#if defined(_WIN32) || __has_include(<fcntl.h>)
849 void set_blocking(bool block) &;
850#endif // defined(_WIN32) || __has_include(<fcntl.h>)
851
853
862 void set_verbosity(error_verbosity verbosity) &noexcept;
863
865
877 [[nodiscard]] std::vector<errorhandler *> get_errorhandlers() const;
878
880
886 [[nodiscard]] std::string connection_string() const;
887
889
897 void close();
898
899private:
900 friend class connecting;
901 enum connect_mode
902 {
903 connect_nonblocking
904 };
905 connection(connect_mode, zview connection_string);
906
908
913 std::pair<bool, bool> poll_connect();
914
915 // Initialise based on connection string.
916 void init(char const options[]);
917 // Initialise based on parameter names and values.
918 void init(char const *params[], char const *values[]);
919 void complete_init();
920
921 result make_result(
922 internal::pq::PGresult *pgr, std::shared_ptr<std::string> const &query,
923 std::string_view desc = ""sv);
924
925 void PQXX_PRIVATE set_up_state();
926
927 int PQXX_PRIVATE PQXX_PURE status() const noexcept;
928
930
934 std::size_t esc_to_buf(std::string_view text, char *buf) const;
935
936 friend class internal::gate::const_connection_largeobject;
937 char const *PQXX_PURE err_msg() const noexcept;
938
939 void PQXX_PRIVATE process_notice_raw(char const msg[]) noexcept;
940
941 result exec_prepared(std::string_view statement, internal::c_params const &);
942
944 void check_movable() const;
946 void check_overwritable() const;
947
948 friend class internal::gate::connection_errorhandler;
949 void PQXX_PRIVATE register_errorhandler(errorhandler *);
950 void PQXX_PRIVATE unregister_errorhandler(errorhandler *) noexcept;
951
952 friend class internal::gate::connection_transaction;
953 result PQXX_PRIVATE exec(std::string_view, std::string_view = ""sv);
954 result
955 PQXX_PRIVATE exec(std::shared_ptr<std::string>, std::string_view = ""sv);
956 void PQXX_PRIVATE register_transaction(transaction_base *);
957 void PQXX_PRIVATE unregister_transaction(transaction_base *) noexcept;
958
959 friend class internal::gate::connection_stream_from;
960 std::pair<std::unique_ptr<char, std::function<void(char *)>>, std::size_t>
961 PQXX_PRIVATE read_copy_line();
962
963 friend class internal::gate::connection_stream_to;
964 void PQXX_PRIVATE write_copy_line(std::string_view);
965 void PQXX_PRIVATE end_copy_write();
966
967 friend class internal::gate::connection_largeobject;
968 internal::pq::PGconn *raw_connection() const { return m_conn; }
969
970 friend class internal::gate::connection_notification_receiver;
971 void add_receiver(notification_receiver *);
972 void remove_receiver(notification_receiver *) noexcept;
973
974 friend class internal::gate::connection_pipeline;
975 void PQXX_PRIVATE start_exec(char const query[]);
976 bool PQXX_PRIVATE consume_input() noexcept;
977 bool PQXX_PRIVATE is_busy() const noexcept;
978 internal::pq::PGresult *get_result();
979
980 friend class internal::gate::connection_dbtransaction;
981 friend class internal::gate::connection_sql_cursor;
982
983 result exec_params(std::string_view query, internal::c_params const &args);
984
986 internal::pq::PGconn *m_conn = nullptr;
987
989
996 transaction_base const *m_trans = nullptr;
997
998 std::list<errorhandler *> m_errorhandlers;
999
1000 using receiver_list =
1001 std::multimap<std::string, pqxx::notification_receiver *>;
1003 receiver_list m_receivers;
1004
1006 int m_unique_id = 0;
1007};
1008
1009
1012
1013
1015
1058class PQXX_LIBEXPORT connecting
1059{
1060public:
1062 connecting(zview connection_string = ""_zv);
1063
1064 connecting(connecting const &) = delete;
1065 connecting(connecting &&) = default;
1066 connecting &operator=(connecting const &) = delete;
1068
1070 [[nodiscard]] int sock() const &noexcept { return m_conn.sock(); }
1071
1073 [[nodiscard]] bool wait_to_read() const &noexcept { return m_reading; }
1074
1076 [[nodiscard]] bool wait_to_write() const &noexcept { return m_writing; }
1077
1079 void process() &;
1080
1082 [[nodiscard]] bool done() const &noexcept
1083 {
1084 return not m_reading and not m_writing;
1085 }
1086
1088
1096 [[nodiscard]] connection produce() &&;
1097
1098private:
1099 connection m_conn;
1100 bool m_reading{false};
1101 bool m_writing{true};
1102};
1103
1104
1105template<typename T> inline std::string connection::quote(T const &t) const
1106{
1107 if constexpr (nullness<T>::always_null)
1108 {
1109 return "NULL";
1110 }
1111 else
1112 {
1113 if (is_null(t))
1114 return "NULL";
1115 auto const text{to_string(t)};
1116
1117 // Okay, there's an easy way to do this and there's a hard way. The easy
1118 // way was "quote, esc(to_string(t)), quote". I'm going with the hard way
1119 // because it's going to save some string manipulation that will probably
1120 // incur some unnecessary memory allocations and deallocations.
1121 std::string buf{'\''};
1122 buf.resize(2 + 2 * std::size(text) + 1);
1123 auto const content_bytes{esc_to_buf(text, buf.data() + 1)};
1124 auto const closing_quote{1 + content_bytes};
1125 buf[closing_quote] = '\'';
1126 auto const end{closing_quote + 1};
1127 buf.resize(end);
1128 return buf;
1129 }
1130}
1131
1132
1133template<PQXX_CHAR_STRINGS_ARG STRINGS>
1134inline std::string connection::quote_columns(STRINGS const &columns) const
1135{
1136 return separated_list(
1137 ","sv, std::cbegin(columns), std::cend(columns),
1138 [this](auto col) { return this->quote_name(*col); });
1139}
1140
1141
1142#if defined(PQXX_HAVE_CONCEPTS)
1143template<internal::ZKey_ZValues MAPPING>
1144inline connection::connection(MAPPING const &params)
1145{
1146 check_version();
1147
1148 std::vector<char const *> keys, values;
1149 if constexpr (std::ranges::sized_range<MAPPING>)
1150 {
1151 auto const size{std::ranges::size(params) + 1};
1152 keys.reserve(size);
1153 values.reserve(size);
1154 }
1155 for (auto const &[key, value] : params)
1156 {
1157 keys.push_back(internal::as_c_string(key));
1158 values.push_back(internal::as_c_string(value));
1159 }
1160 keys.push_back(nullptr);
1161 values.push_back(nullptr);
1162 init(std::data(keys), std::data(values));
1163}
1164#endif // PQXX_HAVE_CONCEPTS
1165} // namespace pqxx
1166
1167
1168namespace pqxx::internal
1169{
1171PQXX_LIBEXPORT void wait_fd(
1172 int fd, bool for_read, bool for_write, unsigned seconds = 1,
1173 unsigned microseconds = 0);
1174} // namespace pqxx::internal
1175#endif
The home of all libpqxx classes, functions, templates, etc.
Definition: array.hxx:23
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:39
std::string encrypt_password(char const user[], char const password[])
Encrypt a password.
Definition: connection.cxx:101
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
std::initializer_list< std::string_view > table_path
Representation of a PostgreSQL table path.
Definition: connection.hxx:119
void check_version()
Definition: util.hxx:221
std::string to_string(field const &value)
Convert a field to a string.
Definition: result.cxx:528
bool is_null(TYPE const &value) noexcept
Is value null?
Definition: strconv.hxx:364
error_verbosity
Error verbosity levels.
Definition: connection.hxx:141
Internal items for libpqxx' own use. Do not use these yourself.
Definition: composite.hxx:80
void unesc_bin(std::string_view escaped_data, std::byte buffer[])
Reconstitute binary data from its escaped version.
Definition: util.cxx:179
void wait_fd(int fd, bool for_read, bool for_write, unsigned seconds=1, unsigned microseconds=0)
Wait for a socket to be ready for reading/writing, or timeout.
Definition: connection.cxx:1095
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:406
Definition: connection.hxx:95
Connection to a database.
Definition: connection.hxx:181
std::string encrypt_password(zview user, zview password, zview algorithm)
Encrypt a password for a given user.
Definition: connection.hxx:482
void prepare(zview definition) &
Definition: connection.hxx:559
connection(char const options[])
Connect to a database, using options string.
Definition: connection.hxx:186
connection & operator=(connection const &)=delete
connection()
Definition: connection.hxx:183
~connection()
Definition: connection.hxx:227
connection(zview options)
Connect to a database, using options string.
Definition: connection.hxx:193
std::basic_string< std::byte > unesc_bin(std::string_view text) const
Unescape binary data, e.g. from a table field or notification payload.
Definition: connection.hxx:732
std::string esc(char const text[]) const
Escape string for use as SQL string literal on this connection.
Definition: connection.hxx:589
std::string unesc_raw(zview text) const
Unescape binary data, e.g. from a table field or notification payload.
Definition: connection.hxx:708
std::string esc(char const text[], std::size_t maxlen) const
Escape string for use as SQL string literal on this connection.
Definition: connection.hxx:583
void prepare(zview name, zview definition) &
Define a prepared statement.
Definition: connection.hxx:539
connection(connection const &)=delete
An ongoing, non-blocking stepping stone to a connection.
Definition: connection.hxx:1059
connecting(connecting &&)=default
int sock() const &noexcept
Get the socket. The socket may change during the connection process.
Definition: connection.hxx:1070
connecting & operator=(connecting const &)=delete
bool done() const &noexcept
Is our connection finished?
Definition: connection.hxx:1082
connecting(connecting const &)=delete
void process() &
Progress towards completion (but don't block).
connecting & operator=(connecting &&)=default
bool wait_to_write() const &noexcept
Should we currently wait to be able to write to the socket?
Definition: connection.hxx:1076
connecting(zview connection_string=""_zv)
Start connecting.
bool wait_to_read() const &noexcept
Should we currently wait to be able to read from the socket?
Definition: connection.hxx:1073
connection produce() &&
Produce the completed connection object.
Base class for error-handler callbacks.
Definition: errorhandler.hxx:50
Definition: notification.hxx:53
Build a parameter list for a parameterised or prepared statement.
Definition: params.hxx:214
Result set containing data returned by a query or command.
Definition: result.hxx:68
Traits describing a type's "null value," if any.
Definition: strconv.hxx:89
Interface definition (and common code) for "transaction" classes.
Definition: transaction_base.hxx:73
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:85