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 
72 namespace pqxx::internal
73 {
74 class sql_cursor;
75 
76 #if defined(PQXX_HAVE_CONCEPTS)
77 template<typename T>
79 concept 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 {
96 class connection_dbtransaction;
97 class connection_errorhandler;
98 class connection_largeobject;
99 class connection_notification_receiver;
100 class connection_pipeline;
101 class connection_sql_cursor;
102 class connection_stream_from;
103 class connection_stream_to;
104 class connection_transaction;
105 class const_connection_largeobject;
106 } // namespace pqxx::internal::gate
107 
108 
109 namespace pqxx
110 {
112 
119 using 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
131 encrypt_password(zview user, zview password)
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 
140 enum 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 
180 class PQXX_LIBEXPORT connection
181 {
182 public:
184 
186  explicit connection(char const options[])
187  {
188  check_version();
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)
207 
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 
275  [[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 
346  [[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 
399 
417  int get_notifs();
418 
420 
432  int await_notification();
433 
435 
447  int await_notification(std::time_t seconds, long microseconds);
449 
480  [[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)
595 
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)
628 
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)
637 
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)
677 
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)
684 
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)
695  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)
748 
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>)
848  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 
899 private:
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 
1011 using connection_base = connection;
1012 
1013 
1015 
1058 class PQXX_LIBEXPORT connecting
1059 {
1060 public:
1062  connecting(zview connection_string = ""_zv);
1063 
1064  connecting(connecting const &) = delete;
1065  connecting(connecting &&) = default;
1066  connecting &operator=(connecting const &) = delete;
1067  connecting &operator=(connecting &&) = default;
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 
1098 private:
1099  connection m_conn;
1100  bool m_reading{false};
1101  bool m_writing{true};
1102 };
1103 
1104 
1105 template<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 
1133 template<PQXX_CHAR_STRINGS_ARG STRINGS>
1134 inline 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)
1143 template<internal::ZKey_ZValues MAPPING>
1144 inline 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 
1168 namespace pqxx::internal
1169 {
1171 PQXX_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
Interface definition (and common code) for "transaction" classes.
Definition: transaction_base.hxx:72
void esc_bin(std::basic_string_view< std::byte > binary_data, char buffer[]) noexcept
Hex-escape binary data into a buffer.
Definition: util.cxx:148
Binary data corresponding to PostgreSQL&#39;s "BYTEA" binary-string type.
Definition: binarystring.hxx:54
Base class for error-handler callbacks.
Definition: errorhandler.hxx:49
void unesc_bin(std::string_view escaped_data, std::byte buffer[])
Reconstitute binary data from its escaped version.
Definition: util.cxx:179
An ongoing, non-blocking stepping stone to a connection.
Definition: connection.hxx:1058
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
Result set containing data returned by a query or command.
Definition: result.hxx:67
bool is_null(TYPE const &value) noexcept
Is value null?
Definition: strconv.hxx:364
~connection()
Definition: connection.hxx:227
std::string quote(T const &t) const
Represent object as SQL string, including quoting & escaping.
Definition: connection.hxx:1105
connection(char const options[])
Connect to a database, using options string.
Definition: connection.hxx:186
bool wait_to_read() const &noexcept
Should we currently wait to be able to read from the socket?
Definition: connection.hxx:1073
Definition: notification.hxx:52
Definition: connection.hxx:94
std::string unesc_raw(zview text) const
Unescape binary data, e.g. from a table field or notification payload.
Definition: connection.hxx:708
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
Build a parameter list for a parameterised or prepared statement.
Definition: params.hxx:213
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
bool done() const &noexcept
Is our connection finished?
Definition: connection.hxx:1082
constexpr std::size_t size_esc_bin(std::size_t binary_bytes) noexcept
Compute buffer size needed to escape binary data for use as a BYTEA.
Definition: util.hxx:397
void set_client_encoding(zview encoding) &
Set client-side character encoding, by name.
Definition: connection.hxx:353
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
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
std::string encrypt_password(char const user[], char const password[])
Encrypt a password.
Definition: connection.cxx:101
std::string quote_columns(STRINGS const &columns) const
Quote and comma-separate a series of column names.
Definition: connection.hxx:1134
void prepare(zview definition) &
Definition: connection.hxx:559
connection(zview options)
Connect to a database, using options string.
Definition: connection.hxx:193
Marker-type wrapper: zero-terminated std::string_view.
Definition: zview.hxx:37
std::string esc(char const text[]) const
Escape string for use as SQL string literal on this connection.
Definition: connection.hxx:589
Internal items for libpqxx&#39; own use. Do not use these yourself.
Definition: composite.hxx:79
STL namespace.
Connection to a database.
Definition: connection.hxx:180
void prepare(zview name, zview definition) &
Define a prepared statement.
Definition: connection.hxx:539
error_verbosity
Error verbosity levels.
Definition: connection.hxx:140
std::string encrypt_password(zview user, zview password, zview algorithm)
Encrypt a password for a given user.
Definition: connection.hxx:482
connection()
Definition: connection.hxx:183
Traits describing a type&#39;s "null value," if any.
Definition: strconv.hxx:88
void check_version()
Definition: util.hxx:221
constexpr char const * c_str() const &noexcept
Either a null pointer, or a zero-terminated text buffer.
Definition: zview.hxx:85
bool wait_to_write() const &noexcept
Should we currently wait to be able to write to the socket?
Definition: connection.hxx:1076
constexpr char const * as_c_string(char const str[]) noexcept
Get a raw C string pointer.
Definition: zview.hxx:136
The home of all libpqxx classes, functions, templates, etc.
Definition: array.hxx:22
std::string to_string(field const &value)
Convert a field to a string.
Definition: result.cxx:528
int sock() const &noexcept
Get the socket. The socket may change during the connection process.
Definition: connection.hxx:1070
Something is out of range, similar to std::out_of_range.
Definition: except.hxx:189
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