libpqxx  7.5.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 // 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/prepared_statement.hxx"
37 #include "pqxx/separated_list.hxx"
38 #include "pqxx/strconv.hxx"
39 #include "pqxx/util.hxx"
40 #include "pqxx/zview.hxx"
41 
42 
70 namespace pqxx::internal
71 {
72 class sql_cursor;
73 
74 #if defined(PQXX_HAVE_CONCEPTS)
75 template<typename T>
77 concept ZKey_ZValues = std::ranges::input_range<T> and requires()
78 {
79  {std::tuple_size<typename std::ranges::iterator_t<T>::value_type>::value};
80 }
81 and std::tuple_size_v<typename std::ranges::iterator_t<T>::value_type> == 2 and
82  requires(T t)
83 {
84  {
85  std::get<0>(*std::cbegin(t))
86  }
87  ->ZString;
88  {
89  std::get<1>(*std::cbegin(t))
90  }
91  ->ZString;
92 };
93 #endif // PQXX_HAVE_CONCEPTS
94 } // namespace pqxx::internal
95 
96 
98 {
99 class connection_dbtransaction;
100 class connection_errorhandler;
101 class connection_largeobject;
102 class connection_notification_receiver;
103 class connection_pipeline;
104 class connection_sql_cursor;
105 class connection_stream_from;
106 class connection_stream_to;
107 class connection_transaction;
108 class const_connection_largeobject;
109 } // namespace pqxx::internal::gate
110 
111 
112 namespace pqxx
113 {
115 
122 using table_path = std::initializer_list<std::string_view>;
123 
124 
126 [[nodiscard,
127  deprecated("Use connection::encrypt_password instead.")]] std::string
128  PQXX_LIBEXPORT
129  encrypt_password(char const user[], char const password[]);
130 
132 [[nodiscard,
133  deprecated("Use connection::encrypt_password instead.")]] inline std::string
134 encrypt_password(zview user, zview password)
135 {
136 #include "pqxx/internal/ignore-deprecated-pre.hxx"
137  return encrypt_password(user.c_str(), password.c_str());
138 #include "pqxx/internal/ignore-deprecated-post.hxx"
139 }
140 
141 
143 enum class error_verbosity : int
144 {
145  // These values must match those in libpq's PGVerbosity enum.
146  terse = 0,
147  normal = 1,
148  verbose = 2
149 };
150 
151 
153 
183 class PQXX_LIBEXPORT connection
184 {
185 public:
187 
189  explicit connection(char const options[])
190  {
191  check_version();
192  init(options);
193  }
194 
196  explicit connection(zview options) : connection{options.c_str()}
197  {
198  // (Delegates to other constructor which calls check_version for us.)
199  }
200 
202 
207  connection(connection &&rhs);
208 
209 #if defined(PQXX_HAVE_CONCEPTS)
210 
226  template<internal::ZKey_ZValues MAPPING>
227  inline connection(MAPPING const &params);
228 #endif // PQXX_HAVE_CONCEPTS
229 
231  {
232  try
233  {
234  close();
235  }
236  catch (std::exception const &)
237  {}
238  }
239 
241 
244  connection &operator=(connection &&rhs);
245 
246  connection(connection const &) = delete;
247  connection &operator=(connection const &) = delete;
248 
250 
254  [[nodiscard]] bool PQXX_PURE is_open() const noexcept;
255 
257  void process_notice(char const[]) noexcept;
259 
262  void process_notice(zview) noexcept;
263 
265  void trace(std::FILE *) noexcept;
266 
277  [[nodiscard]] char const *dbname() const;
279 
281  [[nodiscard]] char const *username() const;
282 
284  [[nodiscard]] char const *hostname() const;
285 
287  [[nodiscard]] char const *port() const;
288 
290  [[nodiscard]] int PQXX_PURE backendpid() const noexcept;
291 
293 
308  [[nodiscard]] int PQXX_PURE sock() const noexcept;
309 
311 
314  [[nodiscard]] int PQXX_PURE protocol_version() const noexcept;
315 
317 
329  [[nodiscard]] int PQXX_PURE server_version() const noexcept;
331 
333 
353  [[nodiscard]] std::string get_client_encoding() const;
355 
357 
360  void set_client_encoding(zview encoding)
361  {
362  set_client_encoding(encoding.c_str());
363  }
364 
366 
369  void set_client_encoding(char const encoding[]);
370 
372  [[nodiscard]] int PQXX_PRIVATE encoding_id() const;
373 
375 
377 
392  void set_variable(std::string_view var, std::string_view value);
393 
395 
398  std::string get_variable(std::string_view);
400 
401 
406 
419  int get_notifs();
420 
421 
423 
431  int await_notification();
432 
434 
442  int await_notification(std::time_t seconds, long microseconds);
444 
475  [[nodiscard]] std::string
477  encrypt_password(zview user, zview password, zview algorithm)
478  {
479  return encrypt_password(user.c_str(), password.c_str(), algorithm.c_str());
480  }
482  [[nodiscard]] std::string encrypt_password(
483  char const user[], char const password[], char const *algorithm = nullptr);
485 
528 
530 
534  void prepare(zview name, zview definition)
535  {
536  prepare(name.c_str(), definition.c_str());
537  }
538 
543  void prepare(char const name[], char const definition[]);
544 
546 
553  void prepare(char const definition[]);
554  void prepare(zview definition) { return prepare(definition.c_str()); }
555 
557  void unprepare(std::string_view name);
558 
560 
562 
565  [[nodiscard]] std::string adorn_name(std::string_view);
566 
571 
572  // TODO: Make "into buffer" variant to eliminate a string allocation.
574 
578  [[nodiscard]] std::string esc(char const text[], std::size_t maxlen) const
579  {
580  return esc(std::string_view(text, maxlen));
581  }
582 
583  // TODO: Make "into buffer" variant to eliminate a string allocation.
585  [[nodiscard]] std::string esc(char const text[]) const
586  {
587  return esc(std::string_view(text));
588  }
589 
590  // TODO: Make "into buffer" variant to eliminate a string allocation.
592 
595  [[nodiscard]] std::string esc(std::string_view text) const;
596 
597  // TODO: Also support esc(std::basic_string_view<std::byte>).
599 
601  [[deprecated("Use std::byte for binary data.")]] std::string
602  esc_raw(unsigned char const bin[], std::size_t len) const;
603 
604  // TODO: Make "into buffer" variant to eliminate a string allocation.
606  [[nodiscard]] std::string esc_raw(std::basic_string_view<std::byte>) const;
607 
608  // TODO: Make "into buffer" variant to eliminate a string allocation.
610 
613  [[nodiscard]] std::string unesc_raw(zview text) const
614  {
615  return unesc_raw(text.c_str());
616  }
617 
618  // TODO: Make "into buffer" variant to eliminate a string allocation.
620 
623  [[nodiscard]] std::string unesc_raw(char const text[]) const;
624 
626 
628  [[deprecated("Use quote(std::basic_string_view<std::byte>).")]]
629  std::string
630  quote_raw(unsigned char const bin[], std::size_t len) const;
631 
633  [[deprecated("Use quote(std::basic_string_view<std::byte>).")]]
634  std::string quote_raw(std::basic_string_view<std::byte>) const;
635 
636  // TODO: Make "into buffer" variant to eliminate a string allocation.
638  [[nodiscard]] std::string quote_name(std::string_view identifier) const;
639 
640  // TODO: Make "into buffer" variant to eliminate a string allocation.
642 
645  [[nodiscard]] std::string quote_table(std::string_view name) const;
646 
647  // TODO: Make "into buffer" variant to eliminate a string allocation.
649 
657  [[nodiscard]] std::string quote_table(table_path) const;
658 
659  // TODO: C++20 concept for "range of string_view."
660  // TODO: Make "into buffer" variant to eliminate a string allocation.
662 
669  template<typename CONTAINER>
670  inline std::enable_if_t<
671  std::is_convertible_v<typename CONTAINER::value_type, std::string_view>,
672  std::string>
673  quote_columns(CONTAINER const &columns) const;
674 
675  // TODO: Make "into buffer" variant to eliminate a string allocation.
677 
680  template<typename T>
681  [[nodiscard]] inline std::string quote(T const &t) const;
682 
684  [[nodiscard, deprecated("Use std::byte for binary data.")]] std::string
685  quote(binarystring const &) const;
686 
687  // TODO: Make "into buffer" variant to eliminate a string allocation.
689  [[nodiscard]] std::string
690  quote(std::basic_string_view<std::byte> bytes) const;
691 
692  // TODO: Make "into buffer" variant to eliminate a string allocation.
694 
717  [[nodiscard]] std::string
718  esc_like(std::string_view text, char escape_char = '\\') const;
720 
722 
726  void cancel_query();
727 
729 
738  void set_verbosity(error_verbosity verbosity) noexcept;
739 
741 
753  [[nodiscard]] std::vector<errorhandler *> get_errorhandlers() const;
754 
756 
762  [[nodiscard]] std::string connection_string() const;
763 
765 
768  void close();
769 
770 private:
771  // Initialise based on connection string.
772  void init(char const options[]);
773  // Initialise based on parameter names and values.
774  void init(char const *params[], char const *values[]);
775  void complete_init();
776 
777  void wait_read() const;
778  void wait_read(std::time_t seconds, long microseconds) const;
779 
780  result make_result(
781  internal::pq::PGresult *pgr, std::shared_ptr<std::string> const &query,
782  std::string_view desc = ""sv);
783 
784  void PQXX_PRIVATE set_up_state();
785 
786  int PQXX_PRIVATE PQXX_PURE status() const noexcept;
787 
789 
793  std::size_t esc_to_buf(std::string_view text, char *buf) const;
794 
795  friend class internal::gate::const_connection_largeobject;
796  char const *PQXX_PURE err_msg() const noexcept;
797 
798  void PQXX_PRIVATE process_notice_raw(char const msg[]) noexcept;
799 
800  result exec_prepared(std::string_view statement, internal::c_params const &);
801 
803  void check_movable() const;
805  void check_overwritable() const;
806 
807  friend class internal::gate::connection_errorhandler;
808  void PQXX_PRIVATE register_errorhandler(errorhandler *);
809  void PQXX_PRIVATE unregister_errorhandler(errorhandler *) noexcept;
810 
811  friend class internal::gate::connection_transaction;
812  result PQXX_PRIVATE exec(std::string_view, std::string_view = ""sv);
813  result
814  PQXX_PRIVATE exec(std::shared_ptr<std::string>, std::string_view = ""sv);
815  void PQXX_PRIVATE register_transaction(transaction_base *);
816  void PQXX_PRIVATE unregister_transaction(transaction_base *) noexcept;
817 
818  friend class internal::gate::connection_stream_from;
819  std::pair<std::unique_ptr<char, std::function<void(char *)>>, std::size_t>
820  PQXX_PRIVATE read_copy_line();
821 
822  friend class internal::gate::connection_stream_to;
823  void PQXX_PRIVATE write_copy_line(std::string_view);
824  void PQXX_PRIVATE end_copy_write();
825 
826  friend class internal::gate::connection_largeobject;
827  internal::pq::PGconn *raw_connection() const { return m_conn; }
828 
829  friend class internal::gate::connection_notification_receiver;
830  void add_receiver(notification_receiver *);
831  void remove_receiver(notification_receiver *) noexcept;
832 
833  friend class internal::gate::connection_pipeline;
834  void PQXX_PRIVATE start_exec(char const query[]);
835  bool PQXX_PRIVATE consume_input() noexcept;
836  bool PQXX_PRIVATE is_busy() const noexcept;
837  internal::pq::PGresult *get_result();
838 
839  friend class internal::gate::connection_dbtransaction;
840  friend class internal::gate::connection_sql_cursor;
841 
842  result exec_params(std::string_view query, internal::c_params const &args);
843 
845  internal::pq::PGconn *m_conn = nullptr;
846 
848 
855  transaction_base const *m_trans = nullptr;
856 
857  std::list<errorhandler *> m_errorhandlers;
858 
859  using receiver_list =
860  std::multimap<std::string, pqxx::notification_receiver *>;
862  receiver_list m_receivers;
863 
865  int m_unique_id = 0;
866 };
867 
868 
870 using connection_base = connection;
871 
872 
873 template<typename T> inline std::string connection::quote(T const &t) const
874 {
875  if constexpr (nullness<T>::always_null)
876  {
877  return "NULL";
878  }
879  else
880  {
881  if (is_null(t))
882  return "NULL";
883  auto const text{to_string(t)};
884 
885  // Okay, there's an easy way to do this and there's a hard way. The easy
886  // way was "quote, esc(to_string(t)), quote". I'm going with the hard way
887  // because it's going to save some string manipulation that will probably
888  // incur some unnecessary memory allocations and deallocations.
889  std::string buf{'\''};
890  buf.resize(2 + 2 * std::size(text) + 1);
891  auto const content_bytes{esc_to_buf(text, buf.data() + 1)};
892  auto const closing_quote{1 + content_bytes};
893  buf[closing_quote] = '\'';
894  auto const end{closing_quote + 1};
895  buf.resize(end);
896  return buf;
897  }
898 }
899 
900 
901 template<typename CONTAINER>
902 inline std::enable_if_t<
903  std::is_convertible_v<typename CONTAINER::value_type, std::string_view>,
904  std::string>
905 connection::quote_columns(CONTAINER const &columns) const
906 {
907  return separated_list(
908  ","sv, std::cbegin(columns), std::cend(columns),
909  [this](auto col) { return this->quote_name(*col); });
910 }
911 
912 
913 #if defined(PQXX_HAVE_CONCEPTS)
914 template<internal::ZKey_ZValues MAPPING>
915 inline connection::connection(MAPPING const &params)
916 {
917  check_version();
918 
919  std::vector<char const *> keys, values;
920  if constexpr (std::ranges::sized_range<MAPPING>)
921  {
922  auto const size{std::ranges::size(params) + 1};
923  keys.reserve(size);
924  values.reserve(size);
925  }
926  for (auto const &[key, value] : params)
927  {
928  keys.push_back(internal::as_c_string(key));
929  values.push_back(internal::as_c_string(value));
930  }
931  keys.push_back(nullptr);
932  values.push_back(nullptr);
933  init(keys.data(), values.data());
934 }
935 #endif // PQXX_HAVE_CONCEPTS
936 } // namespace pqxx
937 
938 
939 namespace pqxx::internal
940 {
941 PQXX_LIBEXPORT void wait_read(internal::pq::PGconn const *);
942 PQXX_LIBEXPORT void wait_read(
943  internal::pq::PGconn const *, std::time_t seconds, long microseconds);
944 PQXX_LIBEXPORT void wait_write(internal::pq::PGconn const *);
945 } // namespace pqxx::internal
946 
947 #include "pqxx/internal/compiler-internal-post.hxx"
948 #endif
void check_version()
Definition: util.hxx:171
Internal items for libpqxx&#39; own use. Do not use these yourself.
Definition: composite.hxx:73
error_verbosity
Error verbosity levels.
Definition: connection.hxx:143
void wait_read(internal::pq::PGconn const *)
Definition: connection.cxx:991
std::string to_string(field const &value)
Convert a field to a string.
Definition: result.cxx:503
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:578
connection(zview options)
Connect to a database, using options string.
Definition: connection.hxx:196
Result set containing data returned by a query or command.
Definition: result.hxx:70
Definition: connection.hxx:97
constexpr char const * c_str() const noexcept
Either a null pointer, or a zero-terminated text buffer.
Definition: zview.hxx:85
constexpr char const * as_c_string(char const str[]) noexcept
Get a raw C string pointer.
Definition: zview.hxx:121
The home of all libpqxx classes, functions, templates, etc.
Definition: array.hxx:25
std::string unesc_raw(zview text) const
Unescape binary data, e.g. from a table field or notification payload.
Definition: connection.hxx:613
std::initializer_list< std::string_view > table_path
Representation of a PostgreSQL table path.
Definition: connection.hxx:122
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:905
std::string encrypt_password(zview user, zview password, zview algorithm)
Encrypt a password for a given user.
Definition: connection.hxx:477
std::string encrypt_password(char const user[], char const password[])
Encrypt a password.
Definition: connection.cxx:95
bool is_null(TYPE const &value) noexcept
Is value null?
Definition: strconv.hxx:353
Binary data corresponding to PostgreSQL&#39;s "BYTEA" binary-string type.
Definition: binarystring.hxx:56
connection()
Definition: connection.hxx:186
Traits describing a type&#39;s "null value," if any.
Definition: strconv.hxx:86
void set_client_encoding(zview encoding)
Set client-side character encoding, by name.
Definition: connection.hxx:360
Base class for error-handler callbacks.
Definition: errorhandler.hxx:52
STL namespace.
void wait_write(internal::pq::PGconn const *)
Definition: connection.cxx:1010
~connection()
Definition: connection.hxx:230
Interface definition (and common code) for "transaction" classes.
Definition: transaction_base.hxx:74
void prepare(zview name, zview definition)
Define a prepared statement.
Definition: connection.hxx:534
Connection to a database.
Definition: connection.hxx:183
void prepare(zview definition)
Definition: connection.hxx:554
connection(char const options[])
Connect to a database, using options string.
Definition: connection.hxx:189
Build a parameter list for a parameterised or prepared statement.
Definition: prepared_statement.hxx:121
Marker-type wrapper: zero-terminated std::string_view.
Definition: zview.hxx:37
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
Definition: notification.hxx:55
std::string esc(char const text[]) const
Escape string for use as SQL string literal on this connection.
Definition: connection.hxx:585