/* Definition of the connection class. * * pqxx::connection encapsulates a connection to a database. * * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/connection instead. * * Copyright (c) 2000-2022, Jeroen T. Vermeulen. * * See COPYING for copyright license. If you did not receive a file called * COPYING with this source code, please notify the distributor of this * mistake, or contact the author. */ #ifndef PQXX_H_CONNECTION #define PQXX_H_CONNECTION #if !defined(PQXX_HEADER_PRE) # error "Include libpqxx headers as , not ." #endif #include #include #include #include #include #include #include #include #include #include // Double-check in order to suppress an overzealous Visual C++ warning (#418). #if defined(PQXX_HAVE_CONCEPTS) && __has_include() # include #endif #include "pqxx/errorhandler.hxx" #include "pqxx/except.hxx" #include "pqxx/internal/concat.hxx" #include "pqxx/params.hxx" #include "pqxx/separated_list.hxx" #include "pqxx/strconv.hxx" #include "pqxx/types.hxx" #include "pqxx/util.hxx" #include "pqxx/zview.hxx" /** * @addtogroup connections * * Use of the libpqxx library starts here. * * Everything that can be done with a database through libpqxx must go through * a @ref pqxx::connection object. It connects to a database when you create * it, and it terminates that communication during destruction. * * Many things come together in this class. Handling of error and warning * messages, for example, is defined by @ref pqxx::errorhandler objects in the * context of a connection. Prepared statements are also defined here. * * When you connect to a database, you pass a connection string containing any * parameters and options, such as the server address and the database name. * * These are identical to the ones in libpq, the C language binding upon which * libpqxx itself is built: * * https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING * * There are also environment variables you can set to provide defaults, again * as defined by libpq: * * https://www.postgresql.org/docs/current/libpq-envars.html * * You can also create a database connection _asynchronously_ using an * intermediate @ref pqxx::connecting object. */ namespace pqxx::internal { class sql_cursor; #if defined(PQXX_HAVE_CONCEPTS) /// Concept: T is a range of pairs of zero-terminated strings. template concept ZKey_ZValues = std::ranges::input_range and requires(T t) { {std::cbegin(t)}; { std::get<0>(*std::cbegin(t)) } -> ZString; { std::get<1>(*std::cbegin(t)) } -> ZString; } and std::tuple_size_v::value_type> == 2; #endif // PQXX_HAVE_CONCEPTS } // namespace pqxx::internal namespace pqxx::internal::gate { class connection_dbtransaction; class connection_errorhandler; class connection_largeobject; class connection_notification_receiver; class connection_pipeline; class connection_sql_cursor; class connection_stream_from; class connection_stream_to; class connection_transaction; class const_connection_largeobject; } // namespace pqxx::internal::gate namespace pqxx { /// Representation of a PostgreSQL table path. /** A "table path" consists of a table name, optionally prefixed by a schema * name, which in turn is optionally prefixed by a database name. * * A minimal example of a table path would be `{mytable}`. But a table path * may also take the forms `{myschema,mytable}` or * `{mydb,myschema,mytable}`. */ using table_path = std::initializer_list; /// Encrypt a password. @deprecated Use connection::encrypt_password instead. [[nodiscard, deprecated("Use connection::encrypt_password instead.")]] std::string PQXX_LIBEXPORT encrypt_password(char const user[], char const password[]); /// Encrypt password. @deprecated Use connection::encrypt_password instead. [[nodiscard, deprecated("Use connection::encrypt_password instead.")]] inline std::string encrypt_password(zview user, zview password) { #include "pqxx/internal/ignore-deprecated-pre.hxx" return encrypt_password(user.c_str(), password.c_str()); #include "pqxx/internal/ignore-deprecated-post.hxx" } /// Error verbosity levels. enum class error_verbosity : int { // These values must match those in libpq's PGVerbosity enum. terse = 0, normal = 1, verbose = 2 }; /// Connection to a database. /** This is the first class to look at when you wish to work with a database * through libpqxx. The connection opens during construction, and closes upon * destruction. * * When creating a connection, you can pass a connection URI or a postgres * connection string, to specify the database server's address, a login * username, and so on. If you don't, the connection will try to obtain them * from certain environment variables. If those are not set either, the * default is to try and connect to the local system's port 5432. * * Find more about connection strings here: * * https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING * * The variables are documented here: * * https://www.postgresql.org/docs/current/libpq-envars.html * * To query or manipulate the database once connected, use one of the * transaction classes (see pqxx/transaction_base.hxx) and perhaps also the * transactor framework (see pqxx/transactor.hxx). * * When a connection breaks, you will typically get a @ref broken_connection * exception. This can happen at almost any point. * * @warning On Unix-like systems, including GNU and BSD systems, your program * may receive the SIGPIPE signal when the connection to the backend breaks. By * default this signal will abort your program. Use "signal(SIGPIPE, SIG_IGN)" * if you want your program to continue running after a connection fails. */ class PQXX_LIBEXPORT connection { public: connection() : connection{""} {} /// Connect to a database, using `options` string. explicit connection(char const options[]) { check_version(); init(options); } /// Connect to a database, using `options` string. explicit connection(zview options) : connection{options.c_str()} { // (Delegates to other constructor which calls check_version for us.) } /// Move constructor. /** Moving a connection is not allowed if it has an open transaction, or has * error handlers or notification receivers registered on it. In those * situations, other objects may hold references to the old object which * would become invalid and might produce hard-to-diagnose bugs. */ connection(connection &&rhs); #if defined(PQXX_HAVE_CONCEPTS) /// Connect to a database, passing options as a range of key/value pairs. /** @warning Experimental. Requires C++20 "concepts" support. Define * `PQXX_HAVE_CONCEPTS` to enable it. * * There's no need to escape the parameter values. * * See the PostgreSQL libpq documentation for the full list of possible * options: * * https://postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS * * The options can be anything that can be iterated as a series of pairs of * zero-terminated strings: `std::pair`, or * `std::tuple`, or * `std::map`, and so on. */ template inline connection(MAPPING const ¶ms); #endif // PQXX_HAVE_CONCEPTS ~connection() { try { close(); } catch (std::exception const &) {} } /// Move assignment. /** Neither connection can have an open transaction, registered error * handlers, or registered notification receivers. */ connection &operator=(connection &&rhs); connection(connection const &) = delete; connection &operator=(connection const &) = delete; /// Is this connection open at the moment? /** @warning This function is **not** needed in most code. Resist the * temptation to check it after opening a connection. The `connection` * constructor will throw a @ref broken_connection exception if can't connect * to the database. */ [[nodiscard]] bool PQXX_PURE is_open() const noexcept; /// Invoke notice processor function. The message should end in newline. void process_notice(char const[]) noexcept; /// Invoke notice processor function. Newline at end is recommended. /** The zview variant, with a message ending in newline, is the most * efficient way to call process_notice. */ void process_notice(zview) noexcept; /// Enable tracing to a given output stream, or nullptr to disable. void trace(std::FILE *) noexcept; /** * @name Connection properties * * These are probably not of great interest, since most are derived from * information supplied by the client program itself, but they are included * for completeness. * * The connection needs to be currently active for these to work. */ //@{ /// Name of database we're connected to, if any. [[nodiscard]] char const *dbname() const; /// Database user ID we're connected under, if any. [[nodiscard]] char const *username() const; /// Address of server, or nullptr if none specified (i.e. default or local) [[nodiscard]] char const *hostname() const; /// Server port number we're connected to. [[nodiscard]] char const *port() const; /// Process ID for backend process, or 0 if inactive. [[nodiscard]] int PQXX_PURE backendpid() const &noexcept; /// Socket currently used for connection, or -1 for none. Use with care! /** Query the current socket number. This is intended for event loops based * on functions such as select() or poll(), where you're waiting for any of * multiple file descriptors to become ready for communication. * * Please try to stay away from this function. It is really only meant for * event loops that need to wait on more than one file descriptor. If all * you need is to block until a notification arrives, for instance, use * await_notification(). If you want to issue queries and retrieve results * in nonblocking fashion, check out the pipeline class. */ [[nodiscard]] int PQXX_PURE sock() const &noexcept; /// What version of the PostgreSQL protocol is this connection using? /** The answer can be 0 (when there is no connection); 3 for protocol 3.0; or * possibly higher values as newer protocol versions come into use. */ [[nodiscard]] int PQXX_PURE protocol_version() const noexcept; /// What version of the PostgreSQL server are we connected to? /** The result is a bit complicated: each of the major, medium, and minor * release numbers is written as a two-digit decimal number, and the three * are then concatenated. Thus server version 9.4.2 will be returned as the * decimal number 90402. If there is no connection to the server, this * returns zero. * * @warning When writing version numbers in your code, don't add zero at the * beginning! Numbers beginning with zero are interpreted as octal (base-8) * in C++. Thus, 070402 is not the same as 70402, and 080000 is not a number * at all because there is no digit "8" in octal notation. Use strictly * decimal notation when it comes to these version numbers. */ [[nodiscard]] int PQXX_PURE server_version() const noexcept; //@} /// @name Text encoding /** * Each connection is governed by a "client encoding," which dictates how * strings and other text is represented in bytes. The database server will * send text data to you in this encoding, and you should use it for the * queries and data which you send to the server. * * Search the PostgreSQL documentation for "character set encodings" to find * out more about the available encodings, how to extend them, and how to use * them. Not all server-side encodings are compatible with all client-side * encodings or vice versa. * * Encoding names are case-insensitive, so e.g. "UTF8" is equivalent to * "utf8". * * You can change the client encoding, but this may not work when the * connection is in a special state, such as when streaming a table. It's * not clear what happens if you change the encoding during a transaction, * and then abort the transaction. */ //@{ /// Get client-side character encoding, by name. [[nodiscard]] std::string get_client_encoding() const; /// Set client-side character encoding, by name. /** * @param encoding Name of the character set encoding to use. */ void set_client_encoding(zview encoding) & { set_client_encoding(encoding.c_str()); } /// Set client-side character encoding, by name. /** * @param encoding Name of the character set encoding to use. */ void set_client_encoding(char const encoding[]) &; /// Get the connection's encoding, as a PostgreSQL-defined code. [[nodiscard]] int PQXX_PRIVATE encoding_id() const; //@} /// Set session variable, using SQL's `SET` command. /** @deprecated To set a session variable, use @ref set_session_var. To set * a transaction-local variable, execute an SQL `SET` command. * * @warning When setting a string value, you must escape and quote it first. * Use the @ref quote() function to do that. * * @warning This executes an SQL query, so do not get or set variables while * a table stream or pipeline is active on the same connection. * * @param var Variable to set. * @param value New value for Var. This can be any SQL expression. If it's * a string, be sure that it's properly escaped and quoted. */ [[deprecated("To set session variables, use set_session_var.")]] void set_variable(std::string_view var, std::string_view value) &; /// Set one of the session variables to a new value. /** This executes SQL, so do not do it while a pipeline or stream is active * on the connection. * * The value you set here will last for the rest of the connection's * duration, or until you set a new value. * * If you set the value while in a @ref dbtransaction (i.e. any transaction * that is not a @ref nontransaction), then rolling back the transaction will * undo the change. * * All applies to setting _session_ variables. You can also set the same * variables as _local_ variables, in which case they will always revert to * their previous value when the transaction ends (or when you overwrite them * of course). To set a local variable, simply execute an SQL statement * along the lines of "`SET LOCAL var = 'value'`" inside your transaction. * * @param var The variable to set. * @param value The new value for the variable. * @throw @ref variable_set_to_null if the value is null; this is not * allowed. */ template void set_session_var(std::string_view var, TYPE const &value) & { if constexpr (nullness::has_null) { if (nullness::is_null(value)) throw variable_set_to_null{ internal::concat("Attempted to set variable ", var, " to null.")}; } exec(internal::concat("SET ", quote_name(var), "=", quote(value))); } /// Read session variable, using SQL's `SHOW` command. /** @warning This executes an SQL query, so do not get or set variables while * a table stream or pipeline is active on the same connection. */ [[deprecated("Use get_var instead.")]] std::string get_variable(std::string_view); /// Read currently applicable value of a variable. /** This function executes an SQL statement, so it won't work while a * @ref pipeline or query stream is active on the connection. * * @return a blank `std::optional` if the variable's value is null, or its * string value otherwise. */ std::string get_var(std::string_view var); /// Read currently applicable value of a variable. /** This function executes an SQL statement, so it won't work while a * @ref pipeline or query stream is active on the connection. * * If there is any possibility that the variable is null, ensure that `TYPE` * can represent null values. */ template TYPE get_var_as(std::string_view var) { return from_string(get_var(var)); } /** * @name Notifications and Receivers */ //@{ /// Check for pending notifications and take appropriate action. /** This does not block. To wait for incoming notifications, either call * await_notification() (it calls this function); or wait for incoming data * on the connection's socket (i.e. wait to read), and then call this * function repeatedly until it returns zero. After that, there are no more * pending notifications so you may want to wait again. * * If any notifications are pending when you call this function, it * processes them by finding any receivers that match the notification string * and invoking those. If no receivers match, there is nothing to invoke but * we do consider the notification processed. * * If any of the client-registered receivers throws an exception, the * function will report it using the connection's errorhandlers. It does not * re-throw the exceptions. * * @return Number of notifications processed. */ int get_notifs(); /// Wait for a notification to come in. /** There are other events that will also terminate the wait, such as the * backend failing. It will also wake up periodically. * * If a notification comes in, the call will process it, along with any other * notifications that may have been pending. * * To wait for notifications into your own event loop instead, wait until * there is incoming data on the connection's socket to be read, then call * @ref get_notifs() repeatedly until it returns zero. * * @return Number of notifications processed. */ int await_notification(); /// Wait for a notification to come in, or for given timeout to pass. /** There are other events that will also terminate the wait, such as the * backend failing, or timeout expiring. * * If a notification comes in, the call will process it, along with any other * notifications that may have been pending. * * To wait for notifications into your own event loop instead, wait until * there is incoming data on the connection's socket to be read, then call * @ref get_notifs repeatedly until it returns zero. * * @return Number of notifications processed */ int await_notification(std::time_t seconds, long microseconds); //@} /** * @name Password encryption * * Use this when setting a new password for the user if password encryption * is enabled. Inputs are the SQL name for the user for whom you with to * encrypt a password; the plaintext password; and the hash algorithm. * * The algorithm must be one of "md5", "scram-sha-256" (introduced in * PostgreSQL 10), or `nullptr`. If the pointer is null, this will query * the `password_encryption setting` from the server, and use the default * algorithm as defined there. * * @return encrypted version of the password, suitable for encrypted * PostgreSQL authentication. * * Thus you can change a user's password with: * ```cxx * void setpw(transaction_base &t, string const &user, string const &pw) * { * t.exec0("ALTER USER " + user + " " * "PASSWORD '" + t.conn().encrypt_password(user,pw) + "'"); * } * ``` * * When building this against a libpq older than version 10, this will use * an older function which only supports md5. In that case, requesting a * different algorithm than md5 will result in a @ref feature_not_supported * exception. */ //@{ /// Encrypt a password for a given user. [[nodiscard]] std::string encrypt_password(zview user, zview password, zview algorithm) { return encrypt_password(user.c_str(), password.c_str(), algorithm.c_str()); } /// Encrypt a password for a given user. [[nodiscard]] std::string encrypt_password( char const user[], char const password[], char const *algorithm = nullptr); //@} /** * @name Prepared statements * * PostgreSQL supports prepared SQL statements, i.e. statements that you can * register under a name you choose, optimized once by the backend, and * executed any number of times under the given name. * * Prepared statement definitions are not sensitive to transaction * boundaries. A statement defined inside a transaction will remain defined * outside that transaction, even if the transaction itself is subsequently * aborted. Once a statement has been prepared, it will only go away if you * close the connection or explicitly "unprepare" the statement. * * Use the `pqxx::transaction_base::exec_prepared` functions to execute a * prepared statement. See @ref prepared for a full discussion. * * @warning Using prepared statements can save time, but if your statement * takes parameters, it may also make your application significantly slower! * The reason is that the server works out a plan for executing the query * when you prepare it. At that time, of course it does not know the values * for the parameters that you will pass. If you execute a query without * preparing it, then the server works out the plan on the spot, with full * knowledge of the parameter values. * * A statement's definition can refer to its parameters as `$1`, `$2`, etc. * The first parameter you pass to the call provides a value for `$1`, and * so on. * * Here's an example of how to use prepared statements. * * ```cxx * using namespace pqxx; * void foo(connection &c) * { * c.prepare("findtable", "select * from pg_tables where name=$1"); * work tx{c}; * result r = tx.exec_prepared("findtable", "mytable"); * if (std::empty(r)) throw runtime_error{"mytable not found!"}; * } * ``` */ //@{ /// Define a prepared statement. /** * @param name unique name for the new prepared statement. * @param definition SQL statement to prepare. */ void prepare(zview name, zview definition) & { prepare(name.c_str(), definition.c_str()); } /** * @param name unique name for the new prepared statement. * @param definition SQL statement to prepare. */ void prepare(char const name[], char const definition[]) &; /// Define a nameless prepared statement. /** * This can be useful if you merely want to pass large binary parameters to a * statement without otherwise wishing to prepare it. If you use this * feature, always keep the definition and the use close together to avoid * the nameless statement being redefined unexpectedly by code somewhere * else. */ void prepare(char const definition[]) &; void prepare(zview definition) & { return prepare(definition.c_str()); } /// Drop prepared statement. void unprepare(std::string_view name); //@} // C++20: constexpr. Breaks ABI. /// Suffix unique number to name to make it unique within session context. /** Used internally to generate identifiers for SQL objects (such as cursors * and nested transactions) based on a given human-readable base name. */ [[nodiscard]] std::string adorn_name(std::string_view); /** * @defgroup escaping-functions String-escaping functions */ //@{ /// Escape string for use as SQL string literal on this connection. /** @warning This accepts a length, and it does not require a terminating * zero byte. But if there is a zero byte, escaping stops there even if * it's not at the end of the string! */ [[deprecated("Use std::string_view or pqxx:zview.")]] std::string esc(char const text[], std::size_t maxlen) const { return esc(std::string_view{text, maxlen}); } /// Escape string for use as SQL string literal on this connection. [[nodiscard]] std::string esc(char const text[]) const { return esc(std::string_view{text}); } #if defined(PQXX_HAVE_SPAN) /// Escape string for use as SQL string literal, into `buffer`. /** Use this variant when you want to re-use the same buffer across multiple * calls. If that's not the case, or convenience and simplicity are more * important, use the single-argument variant. * * For every byte in `text`, there must be at least 2 bytes of space in * `buffer`; plus there must be one byte of space for a trailing zero. * Throws @ref range_error if this space is not available. * * Returns a reference to the escaped string, which is actually stored in * `buffer`. */ [[nodiscard]] std::string_view esc(std::string_view text, std::span buffer) { auto const size{std::size(text)}, space{std::size(buffer)}; auto const needed{2 * size + 1}; if (space < needed) throw range_error{internal::concat( "Not enough room to escape string of ", size, " byte(s): need ", needed, " bytes of buffer space, but buffer size is ", space, ".")}; auto const data{buffer.data()}; return {data, esc_to_buf(text, data)}; } #endif /// Escape string for use as SQL string literal on this connection. /** @warning This is meant for text strings only. It cannot contain bytes * whose value is zero ("nul bytes"). */ [[nodiscard]] std::string esc(std::string_view text) const; #if defined(PQXX_HAVE_CONCEPTS) /// Escape binary string for use as SQL string literal on this connection. /** This is identical to `esc_raw(data)`. */ template [[nodiscard]] std::string esc(DATA const &data) const { return esc_raw(data); } #endif #if defined(PQXX_HAVE_CONCEPTS) && defined(PQXX_HAVE_SPAN) /// Escape binary string for use as SQL string literal, into `buffer`. /** Use this variant when you want to re-use the same buffer across multiple * calls. If that's not the case, or convenience and simplicity are more * important, use the single-argument variant. * * For every byte in `data`, there must be at least two bytes of space in * `buffer`; plus there must be two bytes of space for a header and one for * a trailing zero. Throws @ref range_error if this space is not available. * * Returns a reference to the escaped string, which is actually stored in * `buffer`. */ template [[nodiscard]] zview esc(DATA const &data, std::span buffer) const { auto const size{std::size(data)}, space{std::size(buffer)}; auto const needed{internal::size_esc_bin(std::size(data))}; if (space < needed) throw range_error{internal::concat( "Not enough room to escape binary string of ", size, " byte(s): need ", needed, " bytes of buffer space, but buffer size is ", space, ".")}; std::basic_string_view view{std::data(data), std::size(data)}; auto const out{std::data(buffer)}; // Actually, in the modern format, we know beforehand exactly how many // bytes we're going to fill. Just leave out the trailing zero. internal::esc_bin(view, out); return zview{out, needed - 1}; } #endif /// Escape binary string for use as SQL string literal on this connection. [[deprecated("Use std::byte for binary data.")]] std::string esc_raw(unsigned char const bin[], std::size_t len) const; /// Escape binary string for use as SQL string literal on this connection. /** You can also just use @ref esc with a binary string. */ [[nodiscard]] std::string esc_raw(std::basic_string_view) const; #if defined(PQXX_HAVE_SPAN) /// Escape binary string for use as SQL string literal, into `buffer`. /** You can also just use @ref esc with a binary string. */ [[nodiscard]] std::string esc_raw(std::basic_string_view, std::span buffer) const; #endif #if defined(PQXX_HAVE_CONCEPTS) /// Escape binary string for use as SQL string literal on this connection. /** You can also just use @ref esc with a binary string. */ template [[nodiscard]] std::string esc_raw(DATA const &data) const { return esc_raw( std::basic_string_view{std::data(data), std::size(data)}); } #endif #if defined(PQXX_HAVE_CONCEPTS) && defined(PQXX_HAVE_SPAN) /// Escape binary string for use as SQL string literal, into `buffer`. template [[nodiscard]] zview esc_raw(DATA const &data, std::span buffer) const { return this->esc(binary_cast(data), buffer); } #endif /// Unescape binary data, e.g. from a table field or notification payload. /** Takes a binary string as escaped by PostgreSQL, and returns a restored * copy of the original binary data. */ [[nodiscard, deprecated("Use unesc_bin() instead.")]] std::string unesc_raw(zview text) const { #include "pqxx/internal/ignore-deprecated-pre.hxx" return unesc_raw(text.c_str()); #include "pqxx/internal/ignore-deprecated-post.hxx" } /// Unescape binary data, e.g. from a table field or notification payload. /** Takes a binary string as escaped by PostgreSQL, and returns a restored * copy of the original binary data. */ [[nodiscard, deprecated("Use unesc_bin() instead.")]] std::string unesc_raw(char const text[]) const; // TODO: Make "into buffer" variant to eliminate a string allocation. /// Unescape binary data, e.g. from a table field or notification payload. /** Takes a binary string as escaped by PostgreSQL, and returns a restored * copy of the original binary data. * * (The data must be encoded in PostgreSQL's "hex" format. The legacy * "bytea" escape format, used prior to PostgreSQL 9.0, is no longer * supported.) */ [[nodiscard]] std::basic_string unesc_bin(std::string_view text) const { std::basic_string buf; buf.resize(pqxx::internal::size_unesc_bin(std::size(text))); pqxx::internal::unesc_bin(text, buf.data()); return buf; } /// Escape and quote a string of binary data. [[deprecated("Use quote(std::basic_string_view).")]] std::string quote_raw(unsigned char const bin[], std::size_t len) const; /// Escape and quote a string of binary data. std::string quote_raw(std::basic_string_view) const; #if defined(PQXX_HAVE_CONCEPTS) /// Escape and quote a string of binary data. /** You can also just use @ref quote with binary data. */ template [[nodiscard]] std::string quote_raw(DATA const &data) const { return quote_raw( std::basic_string_view{std::data(data), std::size(data)}); } #endif // TODO: Make "into buffer" variant to eliminate a string allocation. /// Escape and quote an SQL identifier for use in a query. [[nodiscard]] std::string quote_name(std::string_view identifier) const; // TODO: Make "into buffer" variant to eliminate a string allocation. /// Escape and quote a table name. /** When passing just a table name, this is just another name for * @ref quote_name. */ [[nodiscard]] std::string quote_table(std::string_view name) const; // TODO: Make "into buffer" variant to eliminate a string allocation. /// Escape and quote a table path. /** A table path consists of a table name, optionally prefixed by a schema * name; and if both are given, they are in turn optionally prefixed by a * database name. * * Each portion of the path (database name, schema name, table name) will be * quoted separately, and they will be joined together by dots. So for * example, `myschema.mytable` will become `"myschema"."mytable"`. */ [[nodiscard]] std::string quote_table(table_path) const; // TODO: Make "into buffer" variant to eliminate a string allocation. /// Quote and comma-separate a series of column names. /** Use this to save a bit of work in cases where you repeatedly need to pass * the same list of column names, e.g. with @ref stream_to and @ref * stream_from. Some functions that need to quote the columns list * internally, will have a "raw" alternative which let you do the quoting * yourself. It's a bit of extra work, but it can in rare cases let you * eliminate some duplicate work in quoting them repeatedly. */ template inline std::string quote_columns(STRINGS const &columns) const; // TODO: Make "into buffer" variant to eliminate a string allocation. /// Represent object as SQL string, including quoting & escaping. /** * Recognises nulls and represents them as SQL nulls. They get no quotes. */ template [[nodiscard]] inline std::string quote(T const &t) const; [[deprecated("Use std::byte for binary data.")]] std::string quote(binarystring const &) const; // TODO: Make "into buffer" variant to eliminate a string allocation. /// Escape and quote binary data for use as a BYTEA value in SQL statement. [[nodiscard]] std::string quote(std::basic_string_view bytes) const; // TODO: Make "into buffer" variant to eliminate a string allocation. /// Escape string for literal LIKE match. /** Use this when part of an SQL "LIKE" pattern should match only as a * literal string, not as a pattern, even if it contains "%" or "_" * characters that would normally act as wildcards. * * The string does not get string-escaped or quoted. You do that later. * * For instance, let's say you have a string `name` entered by the user, * and you're searching a `file` column for items that match `name` * followed by a dot and three letters. Even if `name` contains wildcard * characters "%" or "_", you only want those to match literally, so "_" * only matches "_" and "%" only matches a single "%". * * You do that by "like-escaping" `name`, appending the wildcard pattern * `".___"`, and finally, escaping and quoting the result for inclusion in * your query: * * ```cxx * tx.exec( * "SELECT file FROM item WHERE file LIKE " + * tx.quote(tx.esc_like(name) + ".___")); * ``` * * The SQL "LIKE" operator also lets you choose your own escape character. * This is supported, but must be a single-byte character. */ [[nodiscard]] std::string esc_like(std::string_view text, char escape_char = '\\') const; //@} /// Attempt to cancel the ongoing query, if any. /** You can use this from another thread, and/or while a query is executing * in a pipeline, but it's up to you to ensure that you're not canceling the * wrong query. This may involve locking. */ void cancel_query(); #if defined(_WIN32) || __has_include() /// Set socket to blocking (true) or nonblocking (false). /** @warning Do not use this unless you _really_ know what you're doing. * @warning This function is available on most systems, but not necessarily * all. */ void set_blocking(bool block) &; #endif // defined(_WIN32) || __has_include() /// Set session verbosity. /** Set the verbosity of error messages to "terse", "normal" (the default), * or "verbose." * * If "terse", returned messages include severity, primary text, and * position only; this will normally fit on a single line. "normal" produces * messages that include the above plus any detail, hint, or context fields * (these might span multiple lines). "verbose" includes all available * fields. */ void set_verbosity(error_verbosity verbosity) &noexcept; /// Return pointers to the active errorhandlers. /** The entries are ordered from oldest to newest handler. * * You may use this to find errorhandlers that your application wants to * delete when destroying the connection. Be aware, however, that libpqxx * may also add errorhandlers of its own, and those will be included in the * list. If this is a problem for you, derive your errorhandlers from a * custom base class derived from pqxx::errorhandler. Then use dynamic_cast * to find which of the error handlers are yours. * * The pointers point to the real errorhandlers. The container it returns * however is a copy of the one internal to the connection, not a reference. */ [[nodiscard]] std::vector get_errorhandlers() const; /// Return a connection string encapsulating this connection's options. /** The connection must be currently open for this to work. * * Returns a reconstruction of this connection's connection string. It may * not exactly match the connection string you passed in when creating this * connection. */ [[nodiscard]] std::string connection_string() const; /// Explicitly close the connection. /** The destructor will do this for you automatically. Still, there is a * reason to `close()` objects explicitly where possible: if an error should * occur while closing, `close()` can throw an exception. A destructor * cannot. * * Closing a connection is idempotent. Closing a connection that's already * closed does nothing. */ void close(); /// Seize control of a raw libpq connection. /** @warning Do not do this. Please. It's for very rare, very specific * use-cases. The mechanism may change (or break) in unexpected ways in * future versions. * * @param raw_conn a raw libpq `PQconn` pointer. */ static connection seize_raw_connection(internal::pq::PGconn *raw_conn) { return connection{raw_conn}; } /// Release the raw connection without closing it. /** @warning Do not do this. It's for very rare, very specific use-cases. * The mechanism may change (or break) in unexpected ways in future versions. * * The `connection` object becomes unusable after this. */ internal::pq::PGconn *release_raw_connection() && { return std::exchange(m_conn, nullptr); } private: friend class connecting; enum connect_mode { connect_nonblocking }; connection(connect_mode, zview connection_string); /// For use by @ref seize_raw_connection. explicit connection(internal::pq::PGconn *raw_conn) : m_conn{raw_conn} {} /// Poll for ongoing connection, try to progress towards completion. /** Returns a pair of "now please wait to read data from socket" and "now * please wait to write data to socket." Both will be false when done. * * Throws an exception if polling indicates that the connection has failed. */ std::pair poll_connect(); // Initialise based on connection string. void init(char const options[]); // Initialise based on parameter names and values. void init(char const *params[], char const *values[]); void complete_init(); result make_result( internal::pq::PGresult *pgr, std::shared_ptr const &query, std::string_view desc = ""sv); void PQXX_PRIVATE set_up_state(); int PQXX_PRIVATE PQXX_PURE status() const noexcept; /// Escape a string, into a buffer allocated by the caller. /** The buffer must have room for at least `2*std::size(text) + 1` bytes. * * Returns the number of bytes written, including the trailing zero. */ std::size_t esc_to_buf(std::string_view text, char *buf) const; friend class internal::gate::const_connection_largeobject; char const *PQXX_PURE err_msg() const noexcept; void PQXX_PRIVATE process_notice_raw(char const msg[]) noexcept; result exec_prepared(std::string_view statement, internal::c_params const &); /// Throw @ref usage_error if this connection is not in a movable state. void check_movable() const; /// Throw @ref usage_error if not in a state where it can be move-assigned. void check_overwritable() const; friend class internal::gate::connection_errorhandler; void PQXX_PRIVATE register_errorhandler(errorhandler *); void PQXX_PRIVATE unregister_errorhandler(errorhandler *) noexcept; friend class internal::gate::connection_transaction; result exec(std::string_view, std::string_view = ""sv); result PQXX_PRIVATE exec(std::shared_ptr, std::string_view = ""sv); void PQXX_PRIVATE register_transaction(transaction_base *); void PQXX_PRIVATE unregister_transaction(transaction_base *) noexcept; friend class internal::gate::connection_stream_from; std::pair>, std::size_t> PQXX_PRIVATE read_copy_line(); friend class internal::gate::connection_stream_to; void PQXX_PRIVATE write_copy_line(std::string_view); void PQXX_PRIVATE end_copy_write(); friend class internal::gate::connection_largeobject; internal::pq::PGconn *raw_connection() const { return m_conn; } friend class internal::gate::connection_notification_receiver; void add_receiver(notification_receiver *); void remove_receiver(notification_receiver *) noexcept; friend class internal::gate::connection_pipeline; void PQXX_PRIVATE start_exec(char const query[]); bool PQXX_PRIVATE consume_input() noexcept; bool PQXX_PRIVATE is_busy() const noexcept; internal::pq::PGresult *get_result(); friend class internal::gate::connection_dbtransaction; friend class internal::gate::connection_sql_cursor; result exec_params(std::string_view query, internal::c_params const &args); /// Connection handle. internal::pq::PGconn *m_conn = nullptr; /// Active transaction on connection, if any. /** We don't use this for anything, except to check for open transactions * when we close the connection or start a new transaction. * * We also don't allow move construction or move assignment while there's a * transaction, since moving the connection in that case would leave one or * more pointers back from the transaction to the connection dangling. */ transaction_base const *m_trans = nullptr; std::list m_errorhandlers; using receiver_list = std::multimap; /// Notification receivers. receiver_list m_receivers; /// Unique number to use as suffix for identifiers (see adorn_name()). int m_unique_id = 0; }; /// @deprecated Old base class for connection. They are now the same class. using connection_base = connection; /// An ongoing, non-blocking stepping stone to a connection. /** Use this when you want to create a connection to the database, but without * blocking your whole thread. It is only available on systems that have * the `` header, and Windows. * * Connecting in this way is probably not "faster" (it's more complicated and * has some extra overhead), but in some situations you can use it to make your * application as a whole faster. It all depends on having other useful work * to do in the same thread, and being able to wait on a socket. If you have * other I/O going on at the same time, your event loop can wait for both the * libpqxx socket and your own sockets, and wake up whenever any of them is * ready to do work. * * Connecting in this way is not properly "asynchronous;" it's merely * "nonblocking." This means it's not a super-high-performance mechanism like * you might get with e.g. `io_uring`. In particular, if we need to look up * the database hostname in DNS, that will happen synchronously. * * To use this, create the `connecting` object, passing a connection string. * Then loop: If @ref wait_to_read returns true, wait for the socket to have * incoming data on it. If @ref wait_to_write returns true, wait for the * socket to be ready for writing. Then call @ref process to process any * incoming or outgoing data. Do all of this until @ref done returns true (or * there is an exception). Finally, call @ref produce to get the completed * connection. * * For example: * * ```cxx * pqxx::connecting cg{}; * * // Loop until we're done connecting. * while (!cg.done()) * { * wait_for_fd(cg.sock(), cg.wait_to_read(), cg.wait_to_write()); * cg.process(); * } * * pqxx::connection conn = std::move(cg).produce(); * * // At this point, conn is a working connection. You can no longer use * // cg at all. * ``` */ class PQXX_LIBEXPORT connecting { public: /// Start connecting. connecting(zview connection_string = ""_zv); connecting(connecting const &) = delete; connecting(connecting &&) = default; connecting &operator=(connecting const &) = delete; connecting &operator=(connecting &&) = default; /// Get the socket. The socket may change during the connection process. [[nodiscard]] int sock() const &noexcept { return m_conn.sock(); } /// Should we currently wait to be able to _read_ from the socket? [[nodiscard]] constexpr bool wait_to_read() const &noexcept { return m_reading; } /// Should we currently wait to be able to _write_ to the socket? [[nodiscard]] constexpr bool wait_to_write() const &noexcept { return m_writing; } /// Progress towards completion (but don't block). void process() &; /// Is our connection finished? [[nodiscard]] constexpr bool done() const &noexcept { return not m_reading and not m_writing; } /// Produce the completed connection object. /** Use this only once, after @ref done returned `true`. Once you have * called this, the `connecting` instance has no more use or meaning. You * can't call any of its member functions afterwards. * * This member function is rvalue-qualified, meaning that you can only call * it on an rvalue instance of the class. If what you have is not an rvalue, * turn it into one by wrapping it in `std::move()`. */ [[nodiscard]] connection produce() &&; private: connection m_conn; bool m_reading{false}; bool m_writing{true}; }; template inline std::string connection::quote(T const &t) const { if constexpr (nullness::always_null) { return "NULL"; } else { if (is_null(t)) return "NULL"; auto const text{to_string(t)}; // Okay, there's an easy way to do this and there's a hard way. The easy // way was "quote, esc(to_string(t)), quote". I'm going with the hard way // because it's going to save some string manipulation that will probably // incur some unnecessary memory allocations and deallocations. std::string buf{'\''}; buf.resize(2 + 2 * std::size(text) + 1); auto const content_bytes{esc_to_buf(text, buf.data() + 1)}; auto const closing_quote{1 + content_bytes}; buf[closing_quote] = '\''; auto const end{closing_quote + 1}; buf.resize(end); return buf; } } template inline std::string connection::quote_columns(STRINGS const &columns) const { return separated_list( ","sv, std::cbegin(columns), std::cend(columns), [this](auto col) { return this->quote_name(*col); }); } #if defined(PQXX_HAVE_CONCEPTS) template inline connection::connection(MAPPING const ¶ms) { check_version(); std::vector keys, values; if constexpr (std::ranges::sized_range) { auto const size{std::ranges::size(params) + 1}; keys.reserve(size); values.reserve(size); } for (auto const &[key, value] : params) { keys.push_back(internal::as_c_string(key)); values.push_back(internal::as_c_string(value)); } keys.push_back(nullptr); values.push_back(nullptr); init(std::data(keys), std::data(values)); } #endif // PQXX_HAVE_CONCEPTS } // namespace pqxx #endif