libpqxx  7.4.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-2021, 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 #if __has_include(<ranges>)
30 # include <ranges>
31 #endif
32 
33 #include "pqxx/errorhandler.hxx"
34 #include "pqxx/except.hxx"
35 #include "pqxx/prepared_statement.hxx"
36 #include "pqxx/strconv.hxx"
37 #include "pqxx/util.hxx"
38 #include "pqxx/zview.hxx"
39 
40 
68 namespace pqxx::internal
69 {
70 class sql_cursor;
71 
72 #if defined(PQXX_HAVE_CONCEPTS)
73 template<typename T>
75 concept ZKey_ZValues = std::ranges::input_range<T> and requires()
76 {
77  {std::tuple_size<typename std::ranges::iterator_t<T>::value_type>::value};
78 }
79 and std::tuple_size_v<typename std::ranges::iterator_t<T>::value_type> == 2 and
80  requires(T t)
81 {
82  {
83  std::get<0>(*std::cbegin(t))
84  }
85  ->ZString;
86  {
87  std::get<1>(*std::cbegin(t))
88  }
89  ->ZString;
90 };
91 #endif // PQXX_HAVE_CONCEPTS
92 } // namespace pqxx::internal
93 
94 
96 {
97 class connection_dbtransaction;
98 class connection_errorhandler;
99 class connection_largeobject;
100 class connection_notification_receiver;
101 class connection_pipeline;
102 class connection_sql_cursor;
103 class connection_stream_from;
104 class connection_stream_to;
105 class connection_transaction;
106 class const_connection_largeobject;
107 } // namespace pqxx::internal::gate
108 
109 
110 namespace pqxx
111 {
113 
120 using table_path = std::initializer_list<std::string_view>;
121 
122 
124 [[nodiscard,
125  deprecated("Use connection::encrypt_password instead.")]] std::string
126  PQXX_LIBEXPORT
127  encrypt_password(char const user[], char const password[]);
128 
130 [[nodiscard,
131  deprecated("Use connection::encrypt_password instead.")]] inline std::string
132 encrypt_password(zview user, zview password)
133 {
134 #include "pqxx/internal/ignore-deprecated-pre.hxx"
135  return encrypt_password(user.c_str(), password.c_str());
136 #include "pqxx/internal/ignore-deprecated-post.hxx"
137 }
138 
139 
141 enum class error_verbosity : int
142 {
143  // These values must match those in libpq's PGVerbosity enum.
144  terse = 0,
145  normal = 1,
146  verbose = 2
147 };
148 
149 
151 
181 class PQXX_LIBEXPORT connection
182 {
183 public:
185 
187  explicit connection(char const options[])
188  {
189  check_version();
190  init(options);
191  }
192 
194  explicit connection(zview options) : connection{options.c_str()}
195  {
196  // (Delegates to other constructor which calls check_version for us.)
197  }
198 
200 
205  connection(connection &&rhs);
206 
207 #if defined(PQXX_HAVE_CONCEPTS)
208 
224  template<internal::ZKey_ZValues MAPPING>
225  inline connection(MAPPING const &params);
226 #endif // PQXX_HAVE_CONCEPTS
227 
229  {
230  try
231  {
232  close();
233  }
234  catch (std::exception const &)
235  {}
236  }
237 
239 
242  connection &operator=(connection &&rhs);
243 
244  connection(connection const &) = delete;
245  connection &operator=(connection const &) = delete;
246 
248 
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 
306  [[nodiscard]] int PQXX_PURE sock() const noexcept;
307 
309 
312  [[nodiscard]] int PQXX_PURE protocol_version() const noexcept;
313 
315 
327  [[nodiscard]] int PQXX_PURE server_version() const noexcept;
329 
331 
351  [[nodiscard]] std::string get_client_encoding() const;
353 
355 
358  void set_client_encoding(zview encoding)
359  {
360  set_client_encoding(encoding.c_str());
361  }
362 
364 
367  void set_client_encoding(char const encoding[]);
368 
370  [[nodiscard]] int PQXX_PRIVATE encoding_id() const;
371 
373 
375 
390  void set_variable(std::string_view var, std::string_view value);
391 
393 
396  std::string get_variable(std::string_view);
398 
399 
404 
417  int get_notifs();
418 
419 
421 
429  int await_notification();
430 
432 
440  int await_notification(std::time_t seconds, long microseconds);
442 
473  [[nodiscard]] std::string
475  encrypt_password(zview user, zview password, zview algorithm)
476  {
477  return encrypt_password(user.c_str(), password.c_str(), algorithm.c_str());
478  }
480  [[nodiscard]] std::string encrypt_password(
481  char const user[], char const password[], char const *algorithm = nullptr);
483 
526 
528 
532  void prepare(zview name, zview definition)
533  {
534  prepare(name.c_str(), definition.c_str());
535  }
536 
541  void prepare(char const name[], char const definition[]);
542 
544 
551  void prepare(char const definition[]);
552  void prepare(zview definition) { return prepare(definition.c_str()); }
553 
555  void unprepare(std::string_view name);
556 
558 
560 
563  [[nodiscard]] std::string adorn_name(std::string_view);
564 
569 
570  // TODO: Make "into buffer" variant to eliminate a string allocation.
572 
576  [[nodiscard]] std::string esc(char const text[], std::size_t maxlen) const
577  {
578  return esc(std::string_view(text, maxlen));
579  }
580 
581  // TODO: Make "into buffer" variant to eliminate a string allocation.
583  [[nodiscard]] std::string esc(char const text[]) const
584  {
585  return esc(std::string_view(text));
586  }
587 
588  // TODO: Make "into buffer" variant to eliminate a string allocation.
590 
593  [[nodiscard]] std::string esc(std::string_view text) const;
594 
596 
598  [[nodiscard, deprecated("Use std::byte for binary data.")]] std::string
599  esc_raw(unsigned char const bin[], std::size_t len) const;
600 
601  // TODO: Make "into buffer" variant to eliminate a string allocation.
603  [[nodiscard]] std::string esc_raw(std::basic_string_view<std::byte>) const;
604 
605  // TODO: Make "into buffer" variant to eliminate a string allocation.
607 
610  [[nodiscard]] std::string unesc_raw(zview text) const
611  {
612  return unesc_raw(text.c_str());
613  }
614 
615  // TODO: Make "into buffer" variant to eliminate a string allocation.
617 
620  [[nodiscard]] std::string unesc_raw(char const text[]) const;
621 
623 
625  [[nodiscard, deprecated("Use std::byte for binary data.")]] std::string
626  quote_raw(unsigned char const bin[], std::size_t len) const;
627 
629  [[nodiscard]] std::string quote_raw(std::basic_string_view<std::byte>) const;
630 
631  // TODO: Make "into buffer" variant to eliminate a string allocation.
633  [[nodiscard]] std::string quote_name(std::string_view identifier) const;
634 
635  // TODO: Make "into buffer" variant to eliminate a string allocation.
637 
640  [[nodiscard]] std::string quote_table(std::string_view name) const;
641 
642  // TODO: Make "into buffer" variant to eliminate a string allocation.
644 
652  [[nodiscard]] std::string quote_table(table_path) const;
653 
654  // TODO: C++20 concept for "range of string_view."
655  // TODO: Make "into buffer" variant to eliminate a string allocation.
657 
664  template<typename CONTAINER>
665  inline std::enable_if_t<
666  std::is_convertible_v<typename CONTAINER::value_type, std::string_view>,
667  std::string>
668  quote_columns(CONTAINER const &columns) const;
669 
670  // TODO: Make "into buffer" variant to eliminate a string allocation.
672 
675  template<typename T>
676  [[nodiscard]] inline std::string quote(T const &t) const;
677 
679  [[nodiscard, deprecated("Use std::byte for binary data.")]] std::string
680  quote(binarystring const &) const;
681 
682  // TODO: Make "into buffer" variant to eliminate a string allocation.
684  [[nodiscard]] std::string
685  quote(std::basic_string_view<std::byte> bytes) const;
686 
687  // TODO: Make "into buffer" variant to eliminate a string allocation.
689 
712  [[nodiscard]] std::string
713  esc_like(std::string_view text, char escape_char = '\\') const;
715 
717 
721  void cancel_query();
722 
724 
733  void set_verbosity(error_verbosity verbosity) noexcept;
734 
736 
748  [[nodiscard]] std::vector<errorhandler *> get_errorhandlers() const;
749 
751 
757  [[nodiscard]] std::string connection_string() const;
758 
760 
763  void close();
764 
765 private:
766  // Initialise based on connection string.
767  void init(char const options[]);
768  // Initialise based on parameter names and values.
769  void init(char const *params[], char const *values[]);
770  void complete_init();
771 
772  void wait_read() const;
773  void wait_read(std::time_t seconds, long microseconds) const;
774 
775  result make_result(
776  internal::pq::PGresult *pgr, std::shared_ptr<std::string> const &query,
777  std::string_view desc = ""sv);
778 
779  void PQXX_PRIVATE set_up_state();
780 
781  int PQXX_PRIVATE PQXX_PURE status() const noexcept;
782 
784 
788  std::size_t esc_to_buf(std::string_view text, char *buf) const;
789 
790  friend class internal::gate::const_connection_largeobject;
791  char const *PQXX_PURE err_msg() const noexcept;
792 
793  void PQXX_PRIVATE process_notice_raw(char const msg[]) noexcept;
794 
795  result exec_prepared(std::string_view statement, internal::params const &);
796 
798  void check_movable() const;
800  void check_overwritable() const;
801 
802  friend class internal::gate::connection_errorhandler;
803  void PQXX_PRIVATE register_errorhandler(errorhandler *);
804  void PQXX_PRIVATE unregister_errorhandler(errorhandler *) noexcept;
805 
806  friend class internal::gate::connection_transaction;
807  result PQXX_PRIVATE exec(std::string_view, std::string_view = ""sv);
808  result
809  PQXX_PRIVATE exec(std::shared_ptr<std::string>, std::string_view = ""sv);
810  void PQXX_PRIVATE register_transaction(transaction_base *);
811  void PQXX_PRIVATE unregister_transaction(transaction_base *) noexcept;
812 
813  friend class internal::gate::connection_stream_from;
814  std::pair<std::unique_ptr<char, std::function<void(char *)>>, std::size_t>
815  PQXX_PRIVATE read_copy_line();
816 
817  friend class internal::gate::connection_stream_to;
818  void PQXX_PRIVATE write_copy_line(std::string_view);
819  void PQXX_PRIVATE end_copy_write();
820 
821  friend class internal::gate::connection_largeobject;
822  internal::pq::PGconn *raw_connection() const { return m_conn; }
823 
824  friend class internal::gate::connection_notification_receiver;
825  void add_receiver(notification_receiver *);
826  void remove_receiver(notification_receiver *) noexcept;
827 
828  friend class internal::gate::connection_pipeline;
829  void PQXX_PRIVATE start_exec(char const query[]);
830  bool PQXX_PRIVATE consume_input() noexcept;
831  bool PQXX_PRIVATE is_busy() const noexcept;
832  internal::pq::PGresult *get_result();
833 
834  friend class internal::gate::connection_dbtransaction;
835  friend class internal::gate::connection_sql_cursor;
836 
837  result exec_params(std::string_view query, internal::params const &args);
838 
840  internal::pq::PGconn *m_conn = nullptr;
841 
843 
850  transaction_base const *m_trans = nullptr;
851 
852  std::list<errorhandler *> m_errorhandlers;
853 
854  using receiver_list =
855  std::multimap<std::string, pqxx::notification_receiver *>;
857  receiver_list m_receivers;
858 
860  int m_unique_id = 0;
861 };
862 
863 
865 using connection_base = connection;
866 
867 
868 template<typename T> inline std::string connection::quote(T const &t) const
869 {
870  if constexpr (nullness<T>::always_null)
871  {
872  return "NULL";
873  }
874  else
875  {
876  if (is_null(t))
877  return "NULL";
878  auto const text{to_string(t)};
879 
880  // Okay, there's an easy way to do this and there's a hard way. The easy
881  // way was "quote, esc(to_string(t)), quote". I'm going with the hard way
882  // because it's going to save some string manipulation that will probably
883  // incur some unnecessary memory allocations and deallocations.
884  std::string buf{'\''};
885  buf.resize(2 + 2 * std::size(text) + 1);
886  auto const content_bytes{esc_to_buf(text, buf.data() + 1)};
887  auto const closing_quote{1 + content_bytes};
888  buf[closing_quote] = '\'';
889  auto const end{closing_quote + 1};
890  buf.resize(end);
891  return buf;
892  }
893 }
894 
895 
896 template<typename CONTAINER>
897 inline std::enable_if_t<
898  std::is_convertible_v<typename CONTAINER::value_type, std::string_view>,
899  std::string>
900 connection::quote_columns(CONTAINER const &columns) const
901 {
902  return separated_list(
903  ","sv, std::cbegin(columns), std::cend(columns),
904  [this](auto col) { return this->quote_name(*col); });
905 }
906 
907 
908 #if defined(PQXX_HAVE_CONCEPTS)
909 template<internal::ZKey_ZValues MAPPING>
910 inline connection::connection(MAPPING const &params)
911 {
912  check_version();
913 
914  std::vector<char const *> keys, values;
915  if constexpr (std::ranges::sized_range<MAPPING>)
916  {
917  auto const size{std::ranges::size(params) + 1};
918  keys.reserve(size);
919  values.reserve(size);
920  }
921  for (auto const &[key, value] : params)
922  {
923  keys.push_back(internal::as_c_string(key));
924  values.push_back(internal::as_c_string(value));
925  }
926  keys.push_back(nullptr);
927  values.push_back(nullptr);
928  init(keys.data(), values.data());
929 }
930 #endif // PQXX_HAVE_CONCEPTS
931 } // namespace pqxx
932 
933 
934 namespace pqxx::internal
935 {
936 PQXX_LIBEXPORT void wait_read(internal::pq::PGconn const *);
937 PQXX_LIBEXPORT void wait_read(
938  internal::pq::PGconn const *, std::time_t seconds, long microseconds);
939 PQXX_LIBEXPORT void wait_write(internal::pq::PGconn const *);
940 } // namespace pqxx::internal
941 
942 #include "pqxx/internal/compiler-internal-post.hxx"
943 #endif
void prepare(zview definition)
Definition: connection.hxx:552
constexpr char const * as_c_string(char const str[]) noexcept
Get a raw C string pointer.
Definition: zview.hxx:121
std::enable_if_t< std::is_convertible_v< typename CONTAINER::value_type, std::string_view >, std::string > quote_columns(CONTAINER const &columns) const
Quote and comma-separate a series of column names.
Definition: connection.hxx:900
void set_client_encoding(zview encoding)
Set client-side character encoding, by name.
Definition: connection.hxx:358
The home of all libpqxx classes, functions, templates, etc.
Definition: array.hxx:25
void wait_write(internal::pq::PGconn const *)
Definition: connection.cxx:1010
bool is_null(TYPE const &value) noexcept
Is value null?
Definition: strconv.hxx:353
void check_version()
Definition: util.hxx:171
error_verbosity
Error verbosity levels.
Definition: connection.hxx:141
std::string to_string(field const &value)
Convert a field to a string.
Definition: result.cxx:503
Binary data corresponding to PostgreSQL&#39;s "BYTEA" binary-string type.
Definition: binarystring.hxx:56
std::string encrypt_password(zview user, zview password, zview algorithm)
Encrypt a password for a given user.
Definition: connection.hxx:475
connection()
Definition: connection.hxx:184
void wait_read(internal::pq::PGconn const *)
Definition: connection.cxx:991
Base class for error-handler callbacks.
Definition: errorhandler.hxx:52
~connection()
Definition: connection.hxx:228
STL namespace.
Connection to a database.
Definition: connection.hxx:181
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
Traits describing a type&#39;s "null value," if any.
Definition: strconv.hxx:86
Definition: connection.hxx:95
std::string esc(char const text[]) const
Escape string for use as SQL string literal on this connection.
Definition: connection.hxx:583
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:576
Result set containing data returned by a query or command.
Definition: result.hxx:70
Definition: notification.hxx:55
Interface definition (and common code) for "transaction" classes.
Definition: transaction_base.hxx:74
std::initializer_list< std::string_view > table_path
Representation of a PostgreSQL table path.
Definition: connection.hxx:120
void prepare(zview name, zview definition)
Define a prepared statement.
Definition: connection.hxx:532
std::string unesc_raw(zview text) const
Unescape binary data, e.g. from a table field or notification payload.
Definition: connection.hxx:610
Marker-type wrapper: zero-terminated std::string_view.
Definition: zview.hxx:37
connection(char const options[])
Connect to a database, using options string.
Definition: connection.hxx:187
std::string encrypt_password(char const user[], char const password[])
Encrypt a password.
Definition: connection.cxx:95
connection(zview options)
Connect to a database, using options string.
Definition: connection.hxx:194
Internal items for libpqxx&#39; own use. Do not use these yourself.
Definition: composite.hxx:73
constexpr char const * c_str() const noexcept
Either a null pointer, or a zero-terminated text buffer.
Definition: zview.hxx:85