libpqxx  7.6.1
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 "pqxx/compiler-public.hxx"
17 #include "pqxx/internal/compiler-internal-pre.hxx"
18 
19 #include <cstddef>
20 #include <ctime>
21 #include <functional>
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 
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 
251  [[nodiscard]] bool PQXX_PURE is_open() const noexcept;
252 
254  void process_notice(char const[]) noexcept;
256 
259  void process_notice(zview) noexcept;
260 
262  void trace(std::FILE *) noexcept;
263 
274  [[nodiscard]] char const *dbname() const;
276 
278  [[nodiscard]] char const *username() const;
279 
281  [[nodiscard]] char const *hostname() const;
282 
284  [[nodiscard]] char const *port() const;
285 
287  [[nodiscard]] int PQXX_PURE backendpid() const noexcept;
288 
290 
305  [[nodiscard]] int PQXX_PURE sock() const noexcept;
306 
308 
311  [[nodiscard]] int PQXX_PURE protocol_version() const noexcept;
312 
314 
326  [[nodiscard]] int PQXX_PURE server_version() const noexcept;
328 
330 
350  [[nodiscard]] std::string get_client_encoding() const;
352 
354 
357  void set_client_encoding(zview encoding)
358  {
359  set_client_encoding(encoding.c_str());
360  }
361 
363 
366  void set_client_encoding(char const encoding[]);
367 
369  [[nodiscard]] int PQXX_PRIVATE encoding_id() const;
370 
372 
374 
389  void set_variable(std::string_view var, std::string_view value);
390 
392 
395  std::string get_variable(std::string_view);
397 
398 
403 
416  int get_notifs();
417 
418 
420 
428  int await_notification();
429 
431 
439  int await_notification(std::time_t seconds, long microseconds);
441 
472  [[nodiscard]] std::string
474  encrypt_password(zview user, zview password, zview algorithm)
475  {
476  return encrypt_password(user.c_str(), password.c_str(), algorithm.c_str());
477  }
479  [[nodiscard]] std::string encrypt_password(
480  char const user[], char const password[], char const *algorithm = nullptr);
482 
525 
527 
531  void prepare(zview name, zview definition)
532  {
533  prepare(name.c_str(), definition.c_str());
534  }
535 
540  void prepare(char const name[], char const definition[]);
541 
543 
550  void prepare(char const definition[]);
551  void prepare(zview definition) { return prepare(definition.c_str()); }
552 
554  void unprepare(std::string_view name);
555 
557 
559 
562  [[nodiscard]] std::string adorn_name(std::string_view);
563 
568 
570 
574  [[deprecated("Use std::string_view or pqxx:zview.")]] std::string
575  esc(char const text[], std::size_t maxlen) const
576  {
577  return esc(std::string_view{text, maxlen});
578  }
579 
581  [[nodiscard]] std::string esc(char const text[]) const
582  {
583  return esc(std::string_view{text});
584  }
585 
586 #if defined(PQXX_HAVE_SPAN)
587 
600  [[nodiscard]] std::string_view
601  esc(std::string_view text, std::span<char> buffer)
602  {
603  auto const size{std::size(text)}, space{std::size(buffer)};
604  auto const needed{2 * size + 1};
605  if (space < needed)
606  throw range_error{internal::concat(
607  "Not enough room to escape string of ", size, " byte(s): need ",
608  needed, " bytes of buffer space, but buffer size is ", space, ".")};
609  auto const data{buffer.data()};
610  return std::string_view{data, esc_to_buf(text, data)};
611  }
612 #endif
613 
615 
618  [[nodiscard]] std::string esc(std::string_view text) const;
619 
620 #if defined(PQXX_HAVE_CONCEPTS)
621 
623  template<binary DATA> [[nodiscard]] std::string esc(DATA const &data) const
624  {
625  return esc_raw(data);
626  }
627 #endif
628 
629 #if defined(PQXX_HAVE_CONCEPTS) && defined(PQXX_HAVE_SPAN)
630 
642  template<binary DATA>
643  [[nodiscard]] zview esc(DATA const &data, std::span<char> buffer) const
644  {
645  auto const size{std::size(data)}, space{std::size(buffer)};
646  auto const needed{internal::size_esc_bin(std::size(data))};
647  if (space < needed)
648  throw range_error{internal::concat(
649  "Not enough room to escape binary string of ", size, " byte(s): need ",
650  needed, " bytes of buffer space, but buffer size is ", space, ".")};
651 
652  std::basic_string_view<std::byte> view{std::data(data), std::size(data)};
653  auto const out{std::data(buffer)};
654  // Actually, in the modern format, we know beforehand exactly how many
655  // bytes we're going to fill. Just leave out the trailing zero.
656  internal::esc_bin(view, out);
657  return zview{out, needed - 1};
658  }
659 #endif
660 
662  [[deprecated("Use std::byte for binary data.")]] std::string
663  esc_raw(unsigned char const bin[], std::size_t len) const;
664 
666 
667  [[nodiscard]] std::string esc_raw(std::basic_string_view<std::byte>) const;
668 
669 #if defined(PQXX_HAVE_SPAN)
670 
672  [[nodiscard]] std::string
673  esc_raw(std::basic_string_view<std::byte>, std::span<char> buffer) const;
674 #endif
675 
676 #if defined(PQXX_HAVE_CONCEPTS)
677 
679  template<binary DATA>
680  [[nodiscard]] std::string esc_raw(DATA const &data) const
681  {
682  return esc_raw(
683  std::basic_string_view<std::byte>{std::data(data), std::size(data)});
684  }
685 #endif
686 
687 #if defined(PQXX_HAVE_CONCEPTS) && defined(PQXX_HAVE_SPAN)
688  template<binary DATA>
690  [[nodiscard]] zview esc_raw(DATA const &data, std::span<char> buffer) const
691  {
692  return this->esc(binary_cast(data), buffer);
693  }
694 #endif
695 
697 
700  [[nodiscard, deprecated("Use unesc_bin() instead.")]] std::string
701  unesc_raw(zview text) const
702  {
703 #include "pqxx/internal/ignore-deprecated-pre.hxx"
704  return unesc_raw(text.c_str());
705 #include "pqxx/internal/ignore-deprecated-post.hxx"
706  }
707 
709 
712  [[nodiscard, deprecated("Use unesc_bin() intead.")]] std::string
713  unesc_raw(char const text[]) const;
714 
715  // TODO: Make "into buffer" variant to eliminate a string allocation.
717 
724  [[nodiscard]] std::basic_string<std::byte>
725  unesc_bin(std::string_view text) const
726  {
727  std::basic_string<std::byte> buf;
728  buf.resize(pqxx::internal::size_unesc_bin(std::size(text)));
729  pqxx::internal::unesc_bin(text, buf.data());
730  return buf;
731  }
732 
734  [[deprecated("Use quote(std::basic_string_view<std::byte>).")]] std::string
735  quote_raw(unsigned char const bin[], std::size_t len) const;
736 
738  std::string quote_raw(std::basic_string_view<std::byte>) const;
739 
740 #if defined(PQXX_HAVE_CONCEPTS)
741 
743  template<binary DATA>
744  [[nodiscard]] std::string quote_raw(DATA const &data) const
745  {
746  return quote_raw(
747  std::basic_string_view<std::byte>{std::data(data), std::size(data)});
748  }
749 #endif
750 
751  // TODO: Make "into buffer" variant to eliminate a string allocation.
753  [[nodiscard]] std::string quote_name(std::string_view identifier) const;
754 
755  // TODO: Make "into buffer" variant to eliminate a string allocation.
757 
760  [[nodiscard]] std::string quote_table(std::string_view name) const;
761 
762  // TODO: Make "into buffer" variant to eliminate a string allocation.
764 
772  [[nodiscard]] std::string quote_table(table_path) const;
773 
774  // TODO: Make "into buffer" variant to eliminate a string allocation.
776 
783  template<PQXX_CHAR_STRINGS_ARG STRINGS>
784  inline std::string quote_columns(STRINGS const &columns) const;
785 
786  // TODO: Make "into buffer" variant to eliminate a string allocation.
788 
791  template<typename T>
792  [[nodiscard]] inline std::string quote(T const &t) const;
793 
794  [[deprecated("Use std::byte for binary data.")]] std::string
795  quote(binarystring const &) const;
796 
797  // TODO: Make "into buffer" variant to eliminate a string allocation.
799  [[nodiscard]] std::string
800  quote(std::basic_string_view<std::byte> bytes) const;
801 
802  // TODO: Make "into buffer" variant to eliminate a string allocation.
804 
827  [[nodiscard]] std::string
828  esc_like(std::string_view text, char escape_char = '\\') const;
830 
832 
836  void cancel_query();
837 
839 
848  void set_verbosity(error_verbosity verbosity) noexcept;
849 
851 
863  [[nodiscard]] std::vector<errorhandler *> get_errorhandlers() const;
864 
866 
872  [[nodiscard]] std::string connection_string() const;
873 
875 
883  void close();
884 
885 private:
886  // Initialise based on connection string.
887  void init(char const options[]);
888  // Initialise based on parameter names and values.
889  void init(char const *params[], char const *values[]);
890  void complete_init();
891 
892  void wait_read() const;
893  void wait_read(std::time_t seconds, long microseconds) const;
894 
895  result make_result(
896  internal::pq::PGresult *pgr, std::shared_ptr<std::string> const &query,
897  std::string_view desc = ""sv);
898 
899  void PQXX_PRIVATE set_up_state();
900 
901  int PQXX_PRIVATE PQXX_PURE status() const noexcept;
902 
904 
908  std::size_t esc_to_buf(std::string_view text, char *buf) const;
909 
910  friend class internal::gate::const_connection_largeobject;
911  char const *PQXX_PURE err_msg() const noexcept;
912 
913  void PQXX_PRIVATE process_notice_raw(char const msg[]) noexcept;
914 
915  result exec_prepared(std::string_view statement, internal::c_params const &);
916 
918  void check_movable() const;
920  void check_overwritable() const;
921 
922  friend class internal::gate::connection_errorhandler;
923  void PQXX_PRIVATE register_errorhandler(errorhandler *);
924  void PQXX_PRIVATE unregister_errorhandler(errorhandler *) noexcept;
925 
926  friend class internal::gate::connection_transaction;
927  result PQXX_PRIVATE exec(std::string_view, std::string_view = ""sv);
928  result
929  PQXX_PRIVATE exec(std::shared_ptr<std::string>, std::string_view = ""sv);
930  void PQXX_PRIVATE register_transaction(transaction_base *);
931  void PQXX_PRIVATE unregister_transaction(transaction_base *) noexcept;
932 
933  friend class internal::gate::connection_stream_from;
934  std::pair<std::unique_ptr<char, std::function<void(char *)>>, std::size_t>
935  PQXX_PRIVATE read_copy_line();
936 
937  friend class internal::gate::connection_stream_to;
938  void PQXX_PRIVATE write_copy_line(std::string_view);
939  void PQXX_PRIVATE end_copy_write();
940 
941  friend class internal::gate::connection_largeobject;
942  internal::pq::PGconn *raw_connection() const { return m_conn; }
943 
944  friend class internal::gate::connection_notification_receiver;
945  void add_receiver(notification_receiver *);
946  void remove_receiver(notification_receiver *) noexcept;
947 
948  friend class internal::gate::connection_pipeline;
949  void PQXX_PRIVATE start_exec(char const query[]);
950  bool PQXX_PRIVATE consume_input() noexcept;
951  bool PQXX_PRIVATE is_busy() const noexcept;
952  internal::pq::PGresult *get_result();
953 
954  friend class internal::gate::connection_dbtransaction;
955  friend class internal::gate::connection_sql_cursor;
956 
957  result exec_params(std::string_view query, internal::c_params const &args);
958 
960  internal::pq::PGconn *m_conn = nullptr;
961 
963 
970  transaction_base const *m_trans = nullptr;
971 
972  std::list<errorhandler *> m_errorhandlers;
973 
974  using receiver_list =
975  std::multimap<std::string, pqxx::notification_receiver *>;
977  receiver_list m_receivers;
978 
980  int m_unique_id = 0;
981 };
982 
983 
985 using connection_base = connection;
986 
987 
988 template<typename T> inline std::string connection::quote(T const &t) const
989 {
990  if constexpr (nullness<T>::always_null)
991  {
992  return "NULL";
993  }
994  else
995  {
996  if (is_null(t))
997  return "NULL";
998  auto const text{to_string(t)};
999 
1000  // Okay, there's an easy way to do this and there's a hard way. The easy
1001  // way was "quote, esc(to_string(t)), quote". I'm going with the hard way
1002  // because it's going to save some string manipulation that will probably
1003  // incur some unnecessary memory allocations and deallocations.
1004  std::string buf{'\''};
1005  buf.resize(2 + 2 * std::size(text) + 1);
1006  auto const content_bytes{esc_to_buf(text, buf.data() + 1)};
1007  auto const closing_quote{1 + content_bytes};
1008  buf[closing_quote] = '\'';
1009  auto const end{closing_quote + 1};
1010  buf.resize(end);
1011  return buf;
1012  }
1013 }
1014 
1015 
1016 template<PQXX_CHAR_STRINGS_ARG STRINGS>
1017 inline std::string connection::quote_columns(STRINGS const &columns) const
1018 {
1019  return separated_list(
1020  ","sv, std::cbegin(columns), std::cend(columns),
1021  [this](auto col) { return this->quote_name(*col); });
1022 }
1023 
1024 
1025 #if defined(PQXX_HAVE_CONCEPTS)
1026 template<internal::ZKey_ZValues MAPPING>
1027 inline connection::connection(MAPPING const &params)
1028 {
1029  check_version();
1030 
1031  std::vector<char const *> keys, values;
1032  if constexpr (std::ranges::sized_range<MAPPING>)
1033  {
1034  auto const size{std::ranges::size(params) + 1};
1035  keys.reserve(size);
1036  values.reserve(size);
1037  }
1038  for (auto const &[key, value] : params)
1039  {
1040  keys.push_back(internal::as_c_string(key));
1041  values.push_back(internal::as_c_string(value));
1042  }
1043  keys.push_back(nullptr);
1044  values.push_back(nullptr);
1045  init(std::data(keys), std::data(values));
1046 }
1047 #endif // PQXX_HAVE_CONCEPTS
1048 } // namespace pqxx
1049 
1050 
1051 namespace pqxx::internal
1052 {
1053 PQXX_LIBEXPORT void wait_read(internal::pq::PGconn const *);
1054 PQXX_LIBEXPORT void wait_read(
1055  internal::pq::PGconn const *, std::time_t seconds, long microseconds);
1056 PQXX_LIBEXPORT void wait_write(internal::pq::PGconn const *);
1057 } // namespace pqxx::internal
1058 
1059 #include "pqxx/internal/compiler-internal-post.hxx"
1060 #endif
std::string encrypt_password(char const user[], char const password[])
Encrypt a password.
Definition: connection.cxx:95
constexpr char const * c_str() const noexcept
Either a null pointer, or a zero-terminated text buffer.
Definition: zview.hxx:87
Marker-type wrapper: zero-terminated std::string_view.
Definition: zview.hxx:39
constexpr char const * as_c_string(char const str[]) noexcept
Get a raw C string pointer.
Definition: zview.hxx:131
void prepare(zview name, zview definition)
Define a prepared statement.
Definition: connection.hxx:531
std::string to_string(field const &value)
Convert a field to a string.
Definition: result.cxx:507
bool is_null(TYPE const &value) noexcept
Is value null?
Definition: strconv.hxx:357
error_verbosity
Error verbosity levels.
Definition: connection.hxx:140
The home of all libpqxx classes, functions, templates, etc.
Definition: array.hxx:25
void esc_bin(std::basic_string_view< std::byte > binary_data, char buffer[]) noexcept
Hex-escape binary data into a buffer.
Definition: util.cxx:145
Binary data corresponding to PostgreSQL&#39;s "BYTEA" binary-string type.
Definition: binarystring.hxx:57
Something is out of range, similar to std::out_of_range.
Definition: except.hxx:192
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:725
void set_client_encoding(zview encoding)
Set client-side character encoding, by name.
Definition: connection.hxx:357
void wait_read(internal::pq::PGconn const *)
Definition: connection.cxx:1011
void check_version()
Definition: util.hxx:162
void unesc_bin(std::string_view escaped_data, std::byte buffer[])
Reconstitute binary data from its escaped version.
Definition: util.cxx:176
std::string unesc_raw(zview text) const
Unescape binary data, e.g. from a table field or notification payload.
Definition: connection.hxx:701
std::string esc(char const text[]) const
Escape string for use as SQL string literal on this connection.
Definition: connection.hxx:581
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:575
std::string quote_columns(STRINGS const &columns) const
Quote and comma-separate a series of column names.
Definition: connection.hxx:1017
void prepare(zview definition)
Definition: connection.hxx:551
connection(zview options)
Connect to a database, using options string.
Definition: connection.hxx:193
Base class for error-handler callbacks.
Definition: errorhandler.hxx:52
std::string encrypt_password(zview user, zview password, zview algorithm)
Encrypt a password for a given user.
Definition: connection.hxx:474
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:230
std::initializer_list< std::string_view > table_path
Representation of a PostgreSQL table path.
Definition: connection.hxx:119
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:326
STL namespace.
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:42
Connection to a database.
Definition: connection.hxx:180
Definition: connection.hxx:94
~connection()
Definition: connection.hxx:227
Traits describing a type&#39;s "null value," if any.
Definition: strconv.hxx:90
Definition: notification.hxx:55
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:335
void wait_write(internal::pq::PGconn const *)
Definition: connection.cxx:1030
Internal items for libpqxx&#39; own use. Do not use these yourself.
Definition: composite.hxx:73
connection()
Definition: connection.hxx:183
Result set containing data returned by a query or command.
Definition: result.hxx:70
Build a parameter list for a parameterised or prepared statement.
Definition: params.hxx:213
connection(char const options[])
Connect to a database, using options string.
Definition: connection.hxx:186
Interface definition (and common code) for "transaction" classes.
Definition: transaction_base.hxx:75