libpqxx  7.4.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-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/separated_list.hxx"
37 #include "pqxx/strconv.hxx"
38 #include "pqxx/util.hxx"
39 #include "pqxx/zview.hxx"
40 
41 
69 namespace pqxx::internal
70 {
71 class sql_cursor;
72 
73 #if defined(PQXX_HAVE_CONCEPTS)
74 template<typename T>
76 concept ZKey_ZValues = std::ranges::input_range<T> and requires()
77 {
78  {std::tuple_size<typename std::ranges::iterator_t<T>::value_type>::value};
79 }
80 and std::tuple_size_v<typename std::ranges::iterator_t<T>::value_type> == 2 and
81  requires(T t)
82 {
83  {
84  std::get<0>(*std::cbegin(t))
85  }
86  ->ZString;
87  {
88  std::get<1>(*std::cbegin(t))
89  }
90  ->ZString;
91 };
92 #endif // PQXX_HAVE_CONCEPTS
93 } // namespace pqxx::internal
94 
95 
97 {
98 class connection_dbtransaction;
99 class connection_errorhandler;
100 class connection_largeobject;
101 class connection_notification_receiver;
102 class connection_pipeline;
103 class connection_sql_cursor;
104 class connection_stream_from;
105 class connection_stream_to;
106 class connection_transaction;
107 class const_connection_largeobject;
108 } // namespace pqxx::internal::gate
109 
110 
111 namespace pqxx
112 {
114 
121 using table_path = std::initializer_list<std::string_view>;
122 
123 
125 [[nodiscard,
126  deprecated("Use connection::encrypt_password instead.")]] std::string
127  PQXX_LIBEXPORT
128  encrypt_password(char const user[], char const password[]);
129 
131 [[nodiscard,
132  deprecated("Use connection::encrypt_password instead.")]] inline std::string
133 encrypt_password(zview user, zview password)
134 {
135 #include "pqxx/internal/ignore-deprecated-pre.hxx"
136  return encrypt_password(user.c_str(), password.c_str());
137 #include "pqxx/internal/ignore-deprecated-post.hxx"
138 }
139 
140 
142 enum class error_verbosity : int
143 {
144  // These values must match those in libpq's PGVerbosity enum.
145  terse = 0,
146  normal = 1,
147  verbose = 2
148 };
149 
150 
152 
182 class PQXX_LIBEXPORT connection
183 {
184 public:
186 
188  explicit connection(char const options[])
189  {
190  check_version();
191  init(options);
192  }
193 
195  explicit connection(zview options) : connection{options.c_str()}
196  {
197  // (Delegates to other constructor which calls check_version for us.)
198  }
199 
201 
206  connection(connection &&rhs);
207 
208 #if defined(PQXX_HAVE_CONCEPTS)
209 
225  template<internal::ZKey_ZValues MAPPING>
226  inline connection(MAPPING const &params);
227 #endif // PQXX_HAVE_CONCEPTS
228 
230  {
231  try
232  {
233  close();
234  }
235  catch (std::exception const &)
236  {}
237  }
238 
240 
243  connection &operator=(connection &&rhs);
244 
245  connection(connection const &) = delete;
246  connection &operator=(connection const &) = delete;
247 
249 
253  [[nodiscard]] bool PQXX_PURE is_open() const noexcept;
254 
256  void process_notice(char const[]) noexcept;
258 
261  void process_notice(zview) noexcept;
262 
264  void trace(std::FILE *) noexcept;
265 
276  [[nodiscard]] char const *dbname() const;
278 
280  [[nodiscard]] char const *username() const;
281 
283  [[nodiscard]] char const *hostname() const;
284 
286  [[nodiscard]] char const *port() const;
287 
289  [[nodiscard]] int PQXX_PURE backendpid() const noexcept;
290 
292 
307  [[nodiscard]] int PQXX_PURE sock() const noexcept;
308 
310 
313  [[nodiscard]] int PQXX_PURE protocol_version() const noexcept;
314 
316 
328  [[nodiscard]] int PQXX_PURE server_version() const noexcept;
330 
332 
352  [[nodiscard]] std::string get_client_encoding() const;
354 
356 
359  void set_client_encoding(zview encoding)
360  {
361  set_client_encoding(encoding.c_str());
362  }
363 
365 
368  void set_client_encoding(char const encoding[]);
369 
371  [[nodiscard]] int PQXX_PRIVATE encoding_id() const;
372 
374 
376 
391  void set_variable(std::string_view var, std::string_view value);
392 
394 
397  std::string get_variable(std::string_view);
399 
400 
405 
418  int get_notifs();
419 
420 
422 
430  int await_notification();
431 
433 
441  int await_notification(std::time_t seconds, long microseconds);
443 
474  [[nodiscard]] std::string
476  encrypt_password(zview user, zview password, zview algorithm)
477  {
478  return encrypt_password(user.c_str(), password.c_str(), algorithm.c_str());
479  }
481  [[nodiscard]] std::string encrypt_password(
482  char const user[], char const password[], char const *algorithm = nullptr);
484 
527 
529 
533  void prepare(zview name, zview definition)
534  {
535  prepare(name.c_str(), definition.c_str());
536  }
537 
542  void prepare(char const name[], char const definition[]);
543 
545 
552  void prepare(char const definition[]);
553  void prepare(zview definition) { return prepare(definition.c_str()); }
554 
556  void unprepare(std::string_view name);
557 
559 
561 
564  [[nodiscard]] std::string adorn_name(std::string_view);
565 
570 
571  // TODO: Make "into buffer" variant to eliminate a string allocation.
573 
577  [[nodiscard]] std::string esc(char const text[], std::size_t maxlen) const
578  {
579  return esc(std::string_view(text, maxlen));
580  }
581 
582  // TODO: Make "into buffer" variant to eliminate a string allocation.
584  [[nodiscard]] std::string esc(char const text[]) const
585  {
586  return esc(std::string_view(text));
587  }
588 
589  // TODO: Make "into buffer" variant to eliminate a string allocation.
591 
594  [[nodiscard]] std::string esc(std::string_view text) const;
595 
597 
599  [[nodiscard, deprecated("Use std::byte for binary data.")]] std::string
600  esc_raw(unsigned char const bin[], std::size_t len) const;
601 
602  // TODO: Make "into buffer" variant to eliminate a string allocation.
604  [[nodiscard]] std::string esc_raw(std::basic_string_view<std::byte>) const;
605 
606  // TODO: Make "into buffer" variant to eliminate a string allocation.
608 
611  [[nodiscard]] std::string unesc_raw(zview text) const
612  {
613  return unesc_raw(text.c_str());
614  }
615 
616  // TODO: Make "into buffer" variant to eliminate a string allocation.
618 
621  [[nodiscard]] std::string unesc_raw(char const text[]) const;
622 
624 
626  [[nodiscard, deprecated("Use std::byte for binary data.")]] std::string
627  quote_raw(unsigned char const bin[], std::size_t len) const;
628 
630  [[nodiscard]] std::string quote_raw(std::basic_string_view<std::byte>) const;
631 
632  // TODO: Make "into buffer" variant to eliminate a string allocation.
634  [[nodiscard]] std::string quote_name(std::string_view identifier) const;
635 
636  // TODO: Make "into buffer" variant to eliminate a string allocation.
638 
641  [[nodiscard]] std::string quote_table(std::string_view name) const;
642 
643  // TODO: Make "into buffer" variant to eliminate a string allocation.
645 
653  [[nodiscard]] std::string quote_table(table_path) const;
654 
655  // TODO: C++20 concept for "range of string_view."
656  // TODO: Make "into buffer" variant to eliminate a string allocation.
658 
665  template<typename CONTAINER>
666  inline std::enable_if_t<
667  std::is_convertible_v<typename CONTAINER::value_type, std::string_view>,
668  std::string>
669  quote_columns(CONTAINER const &columns) const;
670 
671  // TODO: Make "into buffer" variant to eliminate a string allocation.
673 
676  template<typename T>
677  [[nodiscard]] inline std::string quote(T const &t) const;
678 
680  [[nodiscard, deprecated("Use std::byte for binary data.")]] std::string
681  quote(binarystring const &) const;
682 
683  // TODO: Make "into buffer" variant to eliminate a string allocation.
685  [[nodiscard]] std::string
686  quote(std::basic_string_view<std::byte> bytes) const;
687 
688  // TODO: Make "into buffer" variant to eliminate a string allocation.
690 
713  [[nodiscard]] std::string
714  esc_like(std::string_view text, char escape_char = '\\') const;
716 
718 
722  void cancel_query();
723 
725 
734  void set_verbosity(error_verbosity verbosity) noexcept;
735 
737 
749  [[nodiscard]] std::vector<errorhandler *> get_errorhandlers() const;
750 
752 
758  [[nodiscard]] std::string connection_string() const;
759 
761 
764  void close();
765 
766 private:
767  // Initialise based on connection string.
768  void init(char const options[]);
769  // Initialise based on parameter names and values.
770  void init(char const *params[], char const *values[]);
771  void complete_init();
772 
773  void wait_read() const;
774  void wait_read(std::time_t seconds, long microseconds) const;
775 
776  result make_result(
777  internal::pq::PGresult *pgr, std::shared_ptr<std::string> const &query,
778  std::string_view desc = ""sv);
779 
780  void PQXX_PRIVATE set_up_state();
781 
782  int PQXX_PRIVATE PQXX_PURE status() const noexcept;
783 
785 
789  std::size_t esc_to_buf(std::string_view text, char *buf) const;
790 
791  friend class internal::gate::const_connection_largeobject;
792  char const *PQXX_PURE err_msg() const noexcept;
793 
794  void PQXX_PRIVATE process_notice_raw(char const msg[]) noexcept;
795 
796  result exec_prepared(std::string_view statement, internal::params const &);
797 
799  void check_movable() const;
801  void check_overwritable() const;
802 
803  friend class internal::gate::connection_errorhandler;
804  void PQXX_PRIVATE register_errorhandler(errorhandler *);
805  void PQXX_PRIVATE unregister_errorhandler(errorhandler *) noexcept;
806 
807  friend class internal::gate::connection_transaction;
808  result PQXX_PRIVATE exec(std::string_view, std::string_view = ""sv);
809  result
810  PQXX_PRIVATE exec(std::shared_ptr<std::string>, std::string_view = ""sv);
811  void PQXX_PRIVATE register_transaction(transaction_base *);
812  void PQXX_PRIVATE unregister_transaction(transaction_base *) noexcept;
813 
814  friend class internal::gate::connection_stream_from;
815  std::pair<std::unique_ptr<char, std::function<void(char *)>>, std::size_t>
816  PQXX_PRIVATE read_copy_line();
817 
818  friend class internal::gate::connection_stream_to;
819  void PQXX_PRIVATE write_copy_line(std::string_view);
820  void PQXX_PRIVATE end_copy_write();
821 
822  friend class internal::gate::connection_largeobject;
823  internal::pq::PGconn *raw_connection() const { return m_conn; }
824 
825  friend class internal::gate::connection_notification_receiver;
826  void add_receiver(notification_receiver *);
827  void remove_receiver(notification_receiver *) noexcept;
828 
829  friend class internal::gate::connection_pipeline;
830  void PQXX_PRIVATE start_exec(char const query[]);
831  bool PQXX_PRIVATE consume_input() noexcept;
832  bool PQXX_PRIVATE is_busy() const noexcept;
833  internal::pq::PGresult *get_result();
834 
835  friend class internal::gate::connection_dbtransaction;
836  friend class internal::gate::connection_sql_cursor;
837 
838  result exec_params(std::string_view query, internal::params const &args);
839 
841  internal::pq::PGconn *m_conn = nullptr;
842 
844 
851  transaction_base const *m_trans = nullptr;
852 
853  std::list<errorhandler *> m_errorhandlers;
854 
855  using receiver_list =
856  std::multimap<std::string, pqxx::notification_receiver *>;
858  receiver_list m_receivers;
859 
861  int m_unique_id = 0;
862 };
863 
864 
866 using connection_base = connection;
867 
868 
869 template<typename T> inline std::string connection::quote(T const &t) const
870 {
871  if constexpr (nullness<T>::always_null)
872  {
873  return "NULL";
874  }
875  else
876  {
877  if (is_null(t))
878  return "NULL";
879  auto const text{to_string(t)};
880 
881  // Okay, there's an easy way to do this and there's a hard way. The easy
882  // way was "quote, esc(to_string(t)), quote". I'm going with the hard way
883  // because it's going to save some string manipulation that will probably
884  // incur some unnecessary memory allocations and deallocations.
885  std::string buf{'\''};
886  buf.resize(2 + 2 * std::size(text) + 1);
887  auto const content_bytes{esc_to_buf(text, buf.data() + 1)};
888  auto const closing_quote{1 + content_bytes};
889  buf[closing_quote] = '\'';
890  auto const end{closing_quote + 1};
891  buf.resize(end);
892  return buf;
893  }
894 }
895 
896 
897 template<typename CONTAINER>
898 inline std::enable_if_t<
899  std::is_convertible_v<typename CONTAINER::value_type, std::string_view>,
900  std::string>
901 connection::quote_columns(CONTAINER const &columns) const
902 {
903  return separated_list(
904  ","sv, std::cbegin(columns), std::cend(columns),
905  [this](auto col) { return this->quote_name(*col); });
906 }
907 
908 
909 #if defined(PQXX_HAVE_CONCEPTS)
910 template<internal::ZKey_ZValues MAPPING>
911 inline connection::connection(MAPPING const &params)
912 {
913  check_version();
914 
915  std::vector<char const *> keys, values;
916  if constexpr (std::ranges::sized_range<MAPPING>)
917  {
918  auto const size{std::ranges::size(params) + 1};
919  keys.reserve(size);
920  values.reserve(size);
921  }
922  for (auto const &[key, value] : params)
923  {
924  keys.push_back(internal::as_c_string(key));
925  values.push_back(internal::as_c_string(value));
926  }
927  keys.push_back(nullptr);
928  values.push_back(nullptr);
929  init(keys.data(), values.data());
930 }
931 #endif // PQXX_HAVE_CONCEPTS
932 } // namespace pqxx
933 
934 
935 namespace pqxx::internal
936 {
937 PQXX_LIBEXPORT void wait_read(internal::pq::PGconn const *);
938 PQXX_LIBEXPORT void wait_read(
939  internal::pq::PGconn const *, std::time_t seconds, long microseconds);
940 PQXX_LIBEXPORT void wait_write(internal::pq::PGconn const *);
941 } // namespace pqxx::internal
942 
943 #include "pqxx/internal/compiler-internal-post.hxx"
944 #endif
void prepare(zview definition)
Definition: connection.hxx:553
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:901
void set_client_encoding(zview encoding)
Set client-side character encoding, by name.
Definition: connection.hxx:359
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:142
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:476
connection()
Definition: connection.hxx:185
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:229
STL namespace.
Connection to a database.
Definition: connection.hxx:182
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:96
std::string esc(char const text[]) const
Escape string for use as SQL string literal on this connection.
Definition: connection.hxx:584
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:577
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:121
void prepare(zview name, zview definition)
Define a prepared statement.
Definition: connection.hxx:533
std::string unesc_raw(zview text) const
Unescape binary data, e.g. from a table field or notification payload.
Definition: connection.hxx:611
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:188
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:195
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