Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-15 08:42:59

0001 //
0002 // Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 
0008 #ifndef BOOST_MYSQL_ANY_CONNECTION_HPP
0009 #define BOOST_MYSQL_ANY_CONNECTION_HPP
0010 
0011 #include <boost/mysql/any_address.hpp>
0012 #include <boost/mysql/character_set.hpp>
0013 #include <boost/mysql/connect_params.hpp>
0014 #include <boost/mysql/defaults.hpp>
0015 #include <boost/mysql/diagnostics.hpp>
0016 #include <boost/mysql/error_code.hpp>
0017 #include <boost/mysql/execution_state.hpp>
0018 #include <boost/mysql/metadata_mode.hpp>
0019 #include <boost/mysql/rows_view.hpp>
0020 #include <boost/mysql/statement.hpp>
0021 #include <boost/mysql/string_view.hpp>
0022 #include <boost/mysql/with_diagnostics.hpp>
0023 
0024 #include <boost/mysql/detail/access.hpp>
0025 #include <boost/mysql/detail/algo_params.hpp>
0026 #include <boost/mysql/detail/config.hpp>
0027 #include <boost/mysql/detail/connect_params_helpers.hpp>
0028 #include <boost/mysql/detail/connection_impl.hpp>
0029 #include <boost/mysql/detail/engine.hpp>
0030 #include <boost/mysql/detail/execution_concepts.hpp>
0031 #include <boost/mysql/detail/ssl_fwd.hpp>
0032 #include <boost/mysql/detail/throw_on_error_loc.hpp>
0033 
0034 #include <boost/asio/any_io_executor.hpp>
0035 #include <boost/asio/deferred.hpp>
0036 #include <boost/assert.hpp>
0037 #include <boost/optional/optional.hpp>
0038 #include <boost/system/result.hpp>
0039 
0040 #include <cstddef>
0041 #include <cstdint>
0042 #include <memory>
0043 #include <type_traits>
0044 #include <utility>
0045 #include <vector>
0046 
0047 namespace boost {
0048 namespace mysql {
0049 
0050 // Forward declarations
0051 template <class... StaticRow>
0052 class static_execution_state;
0053 
0054 class pipeline_request;
0055 class stage_response;
0056 
0057 /**
0058  * \brief Configuration parameters that can be passed to \ref any_connection's constructor.
0059  */
0060 struct any_connection_params
0061 {
0062     /**
0063      * \brief An external SSL context containing options to configure TLS.
0064      * \details
0065      * Relevant only for SSL connections (those that result on \ref
0066      * any_connection::uses_ssl returning `true`).
0067      * \n
0068      * If the connection is configured to use TLS, an internal `asio::ssl::stream`
0069      * object will be created. If this member is set to a non-null value,
0070      * this internal object will be initialized using the passed context.
0071      * This is the only way to configure TLS options in `any_connection`.
0072      * \n
0073      * If the connection is configured to use TLS and this member is `nullptr`,
0074      * an internal `asio::ssl::context` object with suitable default options
0075      * will be created.
0076      *
0077      * \par Object lifetimes
0078      * If set to non-null, the pointee object must be kept alive until
0079      * all \ref any_connection objects constructed from `*this` are destroyed.
0080      */
0081     asio::ssl::context* ssl_context{};
0082 
0083     /**
0084      * \brief The initial size of the connection's buffer, in bytes.
0085      * \details A bigger read buffer can increase the number of rows
0086      * returned by \ref any_connection::read_some_rows.
0087      */
0088     std::size_t initial_buffer_size{default_initial_read_buffer_size};
0089 
0090     /**
0091      * \brief The maximum size of the connection's buffer, in bytes (64MB by default).
0092      * \details
0093      * Attempting to read or write a protocol packet bigger than this size
0094      * will fail with a \ref client_errc::max_buffer_size_exceeded error.
0095      * \n
0096      * This effectively means: \n
0097      *   - Each request sent to the server must be smaller than this value.
0098      *   - Each individual row received from the server must be smaller than this value.
0099      *     Note that when using `execute` or `async_execute`, results objects may
0100      *     allocate memory beyond this limit if the total number of rows is high.
0101      * \n
0102      * If you need to send or receive larger packets, you may need to adjust
0103      * your server's <a
0104      * href="https://dev.mysql.com/doc/refman/8.4/en/server-system-variables.html#sysvar_max_allowed_packet">`max_allowed_packet`</a>
0105      * system variable, too.
0106      */
0107     std::size_t max_buffer_size{0x4000000};
0108 };
0109 
0110 /**
0111  * \brief A connection to a MySQL server.
0112  * \details
0113  * Represents a connection to a MySQL server.
0114  * This is the main I/O object that this library implements. It's logically comprised
0115  * of session state and an internal stream (usually a socket). The stream is not directly
0116  * accessible. It's constructed using the executor passed to the constructor.
0117  *
0118  * This class supports establishing connections
0119  * with servers using TCP, TCP over TLS and UNIX sockets.
0120  *
0121  * The class is named `any_connection` because it's not templated on a `Stream`
0122  * type, as opposed to \ref connection. New code should prefer using `any_connection`
0123  * whenever possible.
0124  *
0125  * Compared to \ref connection, this class:
0126  *
0127  * - Is type-erased. The type of the connection doesn't depend on the transport being used.
0128  * - Is easier to connect, as \ref connect and \ref async_connect handle hostname resolution.
0129  * - Can always be re-connected after being used or encountering an error.
0130  * - Always uses `asio::any_io_executor`.
0131  * - Has the same level of performance.
0132  *
0133  * This is a move-only type.
0134  *
0135  * \par Single outstanding async operation per connection
0136  * At any given point in time, only one async operation can be outstanding
0137  * per connection. If an async operation is initiated while another one is in progress,
0138  * it will fail with \ref client_errc::operation_in_progress.
0139  *
0140  * \par Default completion tokens
0141  * The default completion token for all async operations in this class is
0142  * `with_diagnostics(asio::deferred)`, which allows you to use `co_await`
0143  * and have the expected exceptions thrown on error.
0144  *
0145  * \par Thread safety
0146  * Distinct objects: safe. \n
0147  * Shared objects: unsafe. \n
0148  * This class is <b>not thread-safe</b>: for a single object, if you
0149  * call its member functions concurrently from separate threads, you will get a race condition.
0150  */
0151 class any_connection
0152 {
0153     detail::connection_impl impl_;
0154 
0155 #ifndef BOOST_MYSQL_DOXYGEN
0156     friend struct detail::access;
0157 #endif
0158 
0159     BOOST_MYSQL_DECL
0160     static std::unique_ptr<detail::engine> create_engine(asio::any_io_executor ex, asio::ssl::context* ctx);
0161 
0162     // Used by tests
0163     any_connection(std::unique_ptr<detail::engine> eng, any_connection_params params)
0164         : impl_(params.initial_buffer_size, params.max_buffer_size, std::move(eng))
0165     {
0166     }
0167 
0168 public:
0169     /**
0170      * \brief Constructs a connection object from an executor and an optional set of parameters.
0171      * \details
0172      * The resulting connection has `this->get_executor() == ex`. Any internally required I/O objects
0173      * will be constructed using this executor.
0174      * \n
0175      * You can configure extra parameters, like the SSL context and buffer sizes, by passing
0176      * an \ref any_connection_params object to this constructor.
0177      */
0178     any_connection(boost::asio::any_io_executor ex, any_connection_params params = {})
0179         : any_connection(create_engine(std::move(ex), params.ssl_context), params)
0180     {
0181     }
0182 
0183     /**
0184      * \brief Constructs a connection object from an execution context and an optional set of parameters.
0185      * \details
0186      * The resulting connection has `this->get_executor() == ctx.get_executor()`.
0187      * Any internally required I/O objects will be constructed using this executor.
0188      * \n
0189      * You can configure extra parameters, like the SSL context and buffer sizes, by passing
0190      * an \ref any_connection_params object to this constructor.
0191      * \n
0192      * This function participates in overload resolution only if `ExecutionContext`
0193      * satisfies the `ExecutionContext` requirements imposed by Boost.Asio.
0194      */
0195     template <
0196         class ExecutionContext
0197 #ifndef BOOST_MYSQL_DOXYGEN
0198         ,
0199         class = typename std::enable_if<std::is_convertible<
0200             decltype(std::declval<ExecutionContext&>().get_executor()),
0201             asio::any_io_executor>::value>::type
0202 #endif
0203         >
0204     any_connection(ExecutionContext& ctx, any_connection_params params = {})
0205         : any_connection(ctx.get_executor(), params)
0206     {
0207     }
0208 
0209     /**
0210      * \brief Move constructor.
0211      */
0212     any_connection(any_connection&& other) = default;
0213 
0214     /**
0215      * \brief Move assignment.
0216      */
0217     any_connection& operator=(any_connection&& rhs) = default;
0218 
0219 #ifndef BOOST_MYSQL_DOXYGEN
0220     any_connection(const any_connection&) = delete;
0221     any_connection& operator=(const any_connection&) = delete;
0222 #endif
0223 
0224     /**
0225      * \brief Destructor.
0226      * \details
0227      * Closes the connection at the transport layer (by closing any underlying socket objects).
0228      * If you require a clean close, call \ref close or \ref async_close before the connection
0229      * is destroyed.
0230      */
0231     ~any_connection() = default;
0232 
0233     /// The executor type associated to this object.
0234     using executor_type = asio::any_io_executor;
0235 
0236     /**
0237      * \brief Retrieves the executor associated to this object.
0238      * \par Exception safety
0239      * No-throw guarantee.
0240      */
0241     executor_type get_executor() noexcept { return impl_.get_engine().get_executor(); }
0242 
0243     /**
0244      * \brief Returns whether the connection negotiated the use of SSL or not.
0245      * \details
0246      * This function can be used to determine whether you are using a SSL
0247      * connection or not when using SSL negotiation.
0248      * \n
0249      * This function always returns `false`
0250      * for connections that haven't been established yet. If the connection establishment fails,
0251      * the return value is undefined.
0252      *
0253      * \par Exception safety
0254      * No-throw guarantee.
0255      */
0256     bool uses_ssl() const noexcept { return impl_.ssl_active(); }
0257 
0258     /**
0259      * \brief Returns whether backslashes are being treated as escape sequences.
0260      * \details
0261      * By default, the server treats backslashes in string values as escape characters.
0262      * This behavior can be disabled by activating the <a
0263      *   href="https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html#sqlmode_no_backslash_escapes">`NO_BACKSLASH_ESCAPES`</a>
0264      * SQL mode.
0265      * \n
0266      * Every time an operation involving server communication completes, the server reports whether
0267      * this mode was activated or not as part of the response. Connections store this information
0268      * and make it available through this function.
0269      * \n
0270      * \li If backslash are treated like escape characters, returns `true`.
0271      * \li If `NO_BACKSLASH_ESCAPES` has been activated, returns `false`.
0272      * \li If connection establishment hasn't happened yet, returns `true`.
0273      * \li Calling this function while an async operation that changes backslash behavior
0274      *     is outstanding may return `true` or `false`.
0275      * \n
0276      * This function does not involve server communication.
0277      *
0278      * \par Exception safety
0279      * No-throw guarantee.
0280      */
0281     bool backslash_escapes() const noexcept { return impl_.backslash_escapes(); }
0282 
0283     /**
0284      * \brief Returns the character set used by this connection.
0285      * \details
0286      * Connections attempt to keep track of the current character set.
0287      * Deficiencies in the protocol can cause the character set to be unknown, though.
0288      * When the character set is known, this function returns
0289      * the character set currently in use. Otherwise, returns \ref client_errc::unknown_character_set.
0290      * \n
0291      * The following functions can modify the return value of this function: \n
0292      *   \li Prior to connection, the character set is always unknown.
0293      *   \li \ref connect and \ref async_connect may set the current character set
0294      *       to a known value, depending on the requested collation.
0295      *   \li \ref set_character_set always and \ref async_set_character_set always
0296      *       set the current character set to the passed value.
0297      *   \li \ref reset_connection and \ref async_reset_connection always makes the current character
0298      *       unknown.
0299      *
0300      * \par Avoid changing the character set directly
0301      * If you change the connection's character set directly using SQL statements
0302      * like `"SET NAMES utf8mb4"`, the client has no way to track this change,
0303      * and this function will return incorrect results.
0304      *
0305      * \par Errors
0306      * \li \ref client_errc::unknown_character_set if the current character set is unknown.
0307      *
0308      * \par Exception safety
0309      * No-throw guarantee.
0310      */
0311     system::result<character_set> current_character_set() const noexcept
0312     {
0313         return impl_.current_character_set();
0314     }
0315 
0316     /**
0317      * \brief Returns format options suitable to format SQL according to the current connection configuration.
0318      * \details
0319      * If the current character set is known (as given by \ref current_character_set), returns
0320      * a value suitable to be passed to SQL formatting functions. Otherwise, returns an error.
0321      *
0322      * \par Errors
0323      * \li \ref client_errc::unknown_character_set if the current character set is unknown.
0324      *
0325      * \par Exception safety
0326      * No-throw guarantee.
0327      */
0328     system::result<format_options> format_opts() const noexcept
0329     {
0330         auto res = current_character_set();
0331         if (res.has_error())
0332             return res.error();
0333         return format_options{res.value(), backslash_escapes()};
0334     }
0335 
0336     /**
0337      * \brief Returns the current metadata mode that this connection is using.
0338      * \details
0339      * \par Exception safety
0340      * No-throw guarantee.
0341      *
0342      * \returns The metadata mode that will be used for queries and statement executions.
0343      */
0344     metadata_mode meta_mode() const noexcept { return impl_.meta_mode(); }
0345 
0346     /**
0347      * \brief Sets the metadata mode.
0348      * \details
0349      * Will affect any query and statement executions performed after the call.
0350      *
0351      * \par Exception safety
0352      * No-throw guarantee.
0353      *
0354      * \par Preconditions
0355      * No asynchronous operation should be outstanding when this function is called.
0356      *
0357      * \param v The new metadata mode.
0358      */
0359     void set_meta_mode(metadata_mode v) noexcept { impl_.set_meta_mode(v); }
0360 
0361     /**
0362      * \brief Retrieves the connection id associated to the current session.
0363      * \details
0364      * If a session has been established, returns its associated connection id.
0365      * If no session has been established (i.e. \ref async_connect hasn't been called yet)
0366      * or the session has been terminated (i.e. \ref async_close has been called), an empty
0367      * optional is returned.
0368      *
0369      * The connection id is a 4 byte value that uniquely identifies a client session
0370      * at a given point in time. It can be used with the
0371      * <a href="https://dev.mysql.com/doc/refman/8.4/en/kill.html">`KILL`</a> SQL statement
0372      * to cancel queries and terminate connections.
0373      *
0374      * The server sends the connection id assigned to the current session as part of the
0375      * handshake process. The value is stored and made available through this function.
0376      * The same id can also be obtained by calling the
0377      * <a
0378      * href="https://dev.mysql.com/doc/refman/8.4/en/information-functions.html#function_connection-id">CONNECTION_ID()</a>
0379      * SQL function. However, this function is faster and more reliable, since it does not entail
0380      * communication with the server.
0381      *
0382      * This function is equivalent to the
0383      * <a href="https://dev.mysql.com/doc/c-api/8.0/en/mysql-thread-id.html">`mysql_thread_id`</a> function
0384      * in the C connector. This function works properly in 64-bit systems, as opposed to what
0385      * the official docs suggest (see
0386      * <a href="https://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-5.html">this changelog</a>).
0387      *
0388      * It is safe to call this function while an async operation is outstanding, except for \ref async_connect
0389      * and \ref async_close.
0390      *
0391      * \par Exception safety
0392      * No-throw guarantee.
0393      */
0394     boost::optional<std::uint32_t> connection_id() const noexcept { return impl_.connection_id(); }
0395 
0396     /**
0397      * \brief Establishes a connection to a MySQL server.
0398      * \details
0399      * This function performs the following:
0400      * \n
0401      * \li If a connection has already been established (by a previous call to \ref connect
0402      *     or \ref async_connect), closes it at the transport layer (by closing any underlying socket)
0403      *     and discards any protocol state associated to it. (If you require
0404      *     a clean close, call \ref close or \ref async_close before using this function).
0405      * \li If the connection is configured to use TCP (`params.server_address.type() ==
0406      *     address_type::host_and_port`), resolves the passed hostname to a set of endpoints. An empty
0407      *     hostname is equivalent to `"localhost"`.
0408      * \li Establishes the physical connection (performing the
0409      *     TCP or UNIX socket connect).
0410      * \li Performs the MySQL handshake to establish a session. If the
0411      *     connection is configured to use TLS, the TLS handshake is performed as part of this step.
0412      * \li If any of the above steps fail, the TCP or UNIX socket connection is closed.
0413      * \n
0414      * You can configure some options using the \ref connect_params struct.
0415      * \n
0416      * The decision to use TLS or not is performed using the following:
0417      * \n
0418      * \li If the transport is not TCP (`params.server_address.type() != address_type::host_and_port`),
0419      *     the connection will never use TLS.
0420      * \li If the transport is TCP, and `params.ssl == ssl_mode::disable`, the connection will not use TLS.
0421      * \li If the transport is TCP, and `params.ssl == ssl_mode::enable`, the connection will use TLS
0422      *     only if the server supports it.
0423      * \li If the transport is TCP, and `params.ssl == ssl_mode::require`, the connection will always use TLS.
0424      *     If the server doesn't support it, the operation will fail with \ref
0425      *     client_errc::server_doesnt_support_ssl.
0426      * \n
0427      * If `params.connection_collation` is within a set of well-known collations, this function
0428      * sets the current character set, such that \ref current_character_set returns a non-null value.
0429      * The default collation (`utf8mb4_general_ci`) is the only one guaranteed to be in the set of well-known
0430      * collations.
0431      */
0432     void connect(const connect_params& params, error_code& ec, diagnostics& diag)
0433     {
0434         impl_.connect_v2(params, ec, diag);
0435     }
0436 
0437     /// \copydoc connect
0438     void connect(const connect_params& params)
0439     {
0440         error_code err;
0441         diagnostics diag;
0442         connect(params, err, diag);
0443         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
0444     }
0445 
0446     /**
0447      * \copydoc connect
0448      *
0449      * \par Object lifetimes
0450      * params needs to be kept alive until the operation completes, as no
0451      * copies will be made by the library.
0452      *
0453      * \par Handler signature
0454      * The handler signature for this operation is `void(boost::mysql::error_code)`.
0455      *
0456      * \par Executor
0457      * Intermediate completion handlers, as well as the final handler, are executed using
0458      * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
0459      * executor.
0460      *
0461      * If the final handler has an associated immediate executor, and the operation
0462      * completes immediately, the final handler is dispatched to it.
0463      * Otherwise, the final handler is called as if it was submitted using `asio::post`,
0464      * and is never be called inline from within this function.
0465      */
0466     template <
0467         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code))
0468             CompletionToken = with_diagnostics_t<asio::deferred_t>>
0469     auto async_connect(const connect_params& params, diagnostics& diag, CompletionToken&& token = {})
0470         BOOST_MYSQL_RETURN_TYPE(detail::async_connect_v2_t<CompletionToken&&>)
0471     {
0472         return impl_.async_connect_v2(params, diag, std::forward<CompletionToken>(token));
0473     }
0474 
0475     /// \copydoc async_connect
0476     template <
0477         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code))
0478             CompletionToken = with_diagnostics_t<asio::deferred_t>>
0479     auto async_connect(const connect_params& params, CompletionToken&& token = {})
0480         BOOST_MYSQL_RETURN_TYPE(detail::async_connect_v2_t<CompletionToken&&>)
0481     {
0482         return async_connect(params, impl_.shared_diag(), std::forward<CompletionToken>(token));
0483     }
0484 
0485     /**
0486      * \brief Executes a text query or prepared statement.
0487      * \details
0488      * Sends `req` to the server for execution and reads the response into `result`.
0489      * `result` may be either a \ref results or \ref static_results object.
0490      * `req` should may be either a type convertible to \ref string_view containing valid SQL
0491      * or a bound prepared statement, obtained by calling \ref statement::bind.
0492      * If a string, it must be encoded using the connection's character set.
0493      * Any string parameters provided to \ref statement::bind should also be encoded
0494      * using the connection's character set.
0495      * \n
0496      * After this operation completes successfully, `result.has_value() == true`.
0497      * \n
0498      * Metadata in `result` will be populated according to `this->meta_mode()`.
0499      */
0500     template <BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest, BOOST_MYSQL_RESULTS_TYPE ResultsType>
0501     void execute(ExecutionRequest&& req, ResultsType& result, error_code& err, diagnostics& diag)
0502     {
0503         impl_.execute(std::forward<ExecutionRequest>(req), result, err, diag);
0504     }
0505 
0506     /// \copydoc execute
0507     template <BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest, BOOST_MYSQL_RESULTS_TYPE ResultsType>
0508     void execute(ExecutionRequest&& req, ResultsType& result)
0509     {
0510         error_code err;
0511         diagnostics diag;
0512         execute(std::forward<ExecutionRequest>(req), result, err, diag);
0513         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
0514     }
0515 
0516     /**
0517      * \copydoc execute
0518      * \par Object lifetimes
0519      * If `CompletionToken` is a deferred completion token (e.g. `use_awaitable`), the caller is
0520      * responsible for managing `req`'s validity following these rules:
0521      * \n
0522      * \li If `req` is `string_view`, the string pointed to by `req`
0523      *     must be kept alive by the caller until the operation is initiated.
0524      * \li If `req` is a \ref bound_statement_tuple, and any of the parameters is a reference
0525      *     type (like `string_view`), the caller must keep the values pointed by these references alive
0526      *     until the operation is initiated.
0527      * \li If `req` is a \ref bound_statement_iterator_range, the caller must keep objects in
0528      *     the iterator range passed to \ref statement::bind alive until the  operation is initiated.
0529      *
0530      * \par Handler signature
0531      * The handler signature for this operation is `void(boost::mysql::error_code)`.
0532      *
0533      * \par Executor
0534      * Intermediate completion handlers, as well as the final handler, are executed using
0535      * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
0536      * executor.
0537      *
0538      * If the final handler has an associated immediate executor, and the operation
0539      * completes immediately, the final handler is dispatched to it.
0540      * Otherwise, the final handler is called as if it was submitted using `asio::post`,
0541      * and is never be called inline from within this function.
0542      */
0543     template <
0544         BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,
0545         BOOST_MYSQL_RESULTS_TYPE ResultsType,
0546         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
0547             CompletionToken = with_diagnostics_t<asio::deferred_t>>
0548     auto async_execute(ExecutionRequest&& req, ResultsType& result, CompletionToken&& token = {})
0549         BOOST_MYSQL_RETURN_TYPE(detail::async_execute_t<ExecutionRequest&&, ResultsType, CompletionToken&&>)
0550     {
0551         return async_execute(
0552             std::forward<ExecutionRequest>(req),
0553             result,
0554             impl_.shared_diag(),
0555             std::forward<CompletionToken>(token)
0556         );
0557     }
0558 
0559     /// \copydoc async_execute
0560     template <
0561         BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,
0562         BOOST_MYSQL_RESULTS_TYPE ResultsType,
0563         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
0564             CompletionToken = with_diagnostics_t<asio::deferred_t>>
0565     auto async_execute(
0566         ExecutionRequest&& req,
0567         ResultsType& result,
0568         diagnostics& diag,
0569         CompletionToken&& token = {}
0570     ) BOOST_MYSQL_RETURN_TYPE(detail::async_execute_t<ExecutionRequest&&, ResultsType, CompletionToken&&>)
0571     {
0572         return impl_.async_execute(
0573             std::forward<ExecutionRequest>(req),
0574             result,
0575             diag,
0576             std::forward<CompletionToken>(token)
0577         );
0578     }
0579 
0580     /**
0581      * \brief Starts a SQL execution as a multi-function operation.
0582      * \details
0583      * Writes the execution request and reads the initial server response and the column
0584      * metadata, but not the generated rows or subsequent resultsets, if any.
0585      * `st` may be either an \ref execution_state or \ref static_execution_state object.
0586      * \n
0587      * After this operation completes, `st` will have
0588      * \ref execution_state::meta populated.
0589      * Metadata will be populated according to `this->meta_mode()`.
0590      * \n
0591      * If the operation generated any rows or more than one resultset, these <b>must</b> be read (by using
0592      * \ref read_some_rows and \ref read_resultset_head) before engaging in any further network operation.
0593      * Otherwise, the results are undefined.
0594      * \n
0595      * req may be either a type convertible to \ref string_view containing valid SQL
0596      * or a bound prepared statement, obtained by calling \ref statement::bind.
0597      * If a string, it must be encoded using the connection's character set.
0598      * Any string parameters provided to \ref statement::bind should also be encoded
0599      * using the connection's character set.
0600      * \n
0601      * When using the static interface, this function will detect schema mismatches for the first
0602      * resultset. Further errors may be detected by \ref read_resultset_head and \ref read_some_rows.
0603      * \n
0604      */
0605     template <
0606         BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,
0607         BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType>
0608     void start_execution(ExecutionRequest&& req, ExecutionStateType& st, error_code& err, diagnostics& diag)
0609     {
0610         impl_.start_execution(std::forward<ExecutionRequest>(req), st, err, diag);
0611     }
0612 
0613     /// \copydoc start_execution
0614     template <
0615         BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,
0616         BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType>
0617     void start_execution(ExecutionRequest&& req, ExecutionStateType& st)
0618     {
0619         error_code err;
0620         diagnostics diag;
0621         start_execution(std::forward<ExecutionRequest>(req), st, err, diag);
0622         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
0623     }
0624 
0625     /**
0626      * \copydoc start_execution
0627      * \par Object lifetimes
0628      * If `CompletionToken` is a deferred completion token (e.g. `use_awaitable`), the caller is
0629      * responsible for managing `req`'s validity following these rules:
0630      * \n
0631      * \li If `req` is `string_view`, the string pointed to by `req`
0632      *     must be kept alive by the caller until the operation is initiated.
0633      * \li If `req` is a \ref bound_statement_tuple, and any of the parameters is a reference
0634      *     type (like `string_view`), the caller must keep the values pointed by these references alive
0635      *     until the operation is initiated.
0636      * \li If `req` is a \ref bound_statement_iterator_range, the caller must keep objects in
0637      *     the iterator range passed to \ref statement::bind alive until the  operation is initiated.
0638      *
0639      * \par Handler signature
0640      * The handler signature for this operation is `void(boost::mysql::error_code)`.
0641      *
0642      * \par Executor
0643      * Intermediate completion handlers, as well as the final handler, are executed using
0644      * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
0645      * executor.
0646      *
0647      * If the final handler has an associated immediate executor, and the operation
0648      * completes immediately, the final handler is dispatched to it.
0649      * Otherwise, the final handler is called as if it was submitted using `asio::post`,
0650      * and is never be called inline from within this function.
0651      */
0652     template <
0653         BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,
0654         BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType,
0655         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
0656             CompletionToken = with_diagnostics_t<asio::deferred_t>>
0657     auto async_start_execution(ExecutionRequest&& req, ExecutionStateType& st, CompletionToken&& token = {})
0658         BOOST_MYSQL_RETURN_TYPE(detail::async_start_execution_t<
0659                                 ExecutionRequest&&,
0660                                 ExecutionStateType,
0661                                 CompletionToken&&>)
0662     {
0663         return async_start_execution(
0664             std::forward<ExecutionRequest>(req),
0665             st,
0666             impl_.shared_diag(),
0667             std::forward<CompletionToken>(token)
0668         );
0669     }
0670 
0671     /// \copydoc async_start_execution
0672     template <
0673         BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,
0674         BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType,
0675         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
0676             CompletionToken = with_diagnostics_t<asio::deferred_t>>
0677     auto async_start_execution(
0678         ExecutionRequest&& req,
0679         ExecutionStateType& st,
0680         diagnostics& diag,
0681         CompletionToken&& token = {}
0682     )
0683         BOOST_MYSQL_RETURN_TYPE(detail::async_start_execution_t<
0684                                 ExecutionRequest&&,
0685                                 ExecutionStateType,
0686                                 CompletionToken&&>)
0687     {
0688         return impl_.async_start_execution(
0689             std::forward<ExecutionRequest>(req),
0690             st,
0691             diag,
0692             std::forward<CompletionToken>(token)
0693         );
0694     }
0695 
0696     /**
0697      * \brief Prepares a statement server-side.
0698      * \details
0699      * `stmt` should be encoded using the connection's character set.
0700      * \n
0701      * The returned statement has `valid() == true`.
0702      */
0703     statement prepare_statement(string_view stmt, error_code& err, diagnostics& diag)
0704     {
0705         return impl_.run(detail::prepare_statement_algo_params{stmt}, err, diag);
0706     }
0707 
0708     /// \copydoc prepare_statement
0709     statement prepare_statement(string_view stmt)
0710     {
0711         error_code err;
0712         diagnostics diag;
0713         statement res = prepare_statement(stmt, err, diag);
0714         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
0715         return res;
0716     }
0717 
0718     /**
0719      * \copydoc prepare_statement
0720      * \details
0721      * \par Object lifetimes
0722      * If `CompletionToken` is a deferred completion token (e.g. `use_awaitable`), the string
0723      * pointed to by `stmt` must be kept alive by the caller until the operation is
0724      * initiated.
0725      *
0726      * \par Handler signature
0727      * The handler signature for this operation is `void(boost::mysql::error_code, boost::mysql::statement)`.
0728      *
0729      * \par Executor
0730      * Intermediate completion handlers, as well as the final handler, are executed using
0731      * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
0732      * executor.
0733      *
0734      * If the final handler has an associated immediate executor, and the operation
0735      * completes immediately, the final handler is dispatched to it.
0736      * Otherwise, the final handler is called as if it was submitted using `asio::post`,
0737      * and is never be called inline from within this function.
0738      */
0739     template <
0740         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, ::boost::mysql::statement))
0741             CompletionToken = with_diagnostics_t<asio::deferred_t>>
0742     auto async_prepare_statement(string_view stmt, CompletionToken&& token = {})
0743         BOOST_MYSQL_RETURN_TYPE(detail::async_prepare_statement_t<CompletionToken&&>)
0744     {
0745         return async_prepare_statement(stmt, impl_.shared_diag(), std::forward<CompletionToken>(token));
0746     }
0747 
0748     /// \copydoc async_prepare_statement
0749     template <
0750         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, ::boost::mysql::statement))
0751             CompletionToken = with_diagnostics_t<asio::deferred_t>>
0752     auto async_prepare_statement(string_view stmt, diagnostics& diag, CompletionToken&& token = {})
0753         BOOST_MYSQL_RETURN_TYPE(detail::async_prepare_statement_t<CompletionToken&&>)
0754     {
0755         return impl_.async_run(
0756             detail::prepare_statement_algo_params{stmt},
0757             diag,
0758             std::forward<CompletionToken>(token)
0759         );
0760     }
0761 
0762     /**
0763      * \brief Closes a statement, deallocating it from the server.
0764      * \details
0765      * After this operation succeeds, `stmt` must not be used again for execution.
0766      * \n
0767      * \par Preconditions
0768      *    `stmt.valid() == true`
0769      */
0770     void close_statement(const statement& stmt, error_code& err, diagnostics& diag)
0771     {
0772         impl_.run(impl_.make_params_close_statement(stmt), err, diag);
0773     }
0774 
0775     /// \copydoc close_statement
0776     void close_statement(const statement& stmt)
0777     {
0778         error_code err;
0779         diagnostics diag;
0780         close_statement(stmt, err, diag);
0781         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
0782     }
0783 
0784     /**
0785      * \copydoc close_statement
0786      * \details
0787      * \par Object lifetimes
0788      * It is not required to keep `stmt` alive, as copies are made by the implementation as required.
0789      *
0790      * \par Handler signature
0791      * The handler signature for this operation is `void(boost::mysql::error_code)`.
0792      *
0793      * \par Executor
0794      * Intermediate completion handlers, as well as the final handler, are executed using
0795      * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
0796      * executor.
0797      *
0798      * If the final handler has an associated immediate executor, and the operation
0799      * completes immediately, the final handler is dispatched to it.
0800      * Otherwise, the final handler is called as if it was submitted using `asio::post`,
0801      * and is never be called inline from within this function.
0802      */
0803     template <
0804         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
0805             CompletionToken = with_diagnostics_t<asio::deferred_t>>
0806     auto async_close_statement(const statement& stmt, CompletionToken&& token = {})
0807         BOOST_MYSQL_RETURN_TYPE(detail::async_close_statement_t<CompletionToken&&>)
0808     {
0809         return async_close_statement(stmt, impl_.shared_diag(), std::forward<CompletionToken>(token));
0810     }
0811 
0812     /// \copydoc async_close_statement
0813     template <
0814         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
0815             CompletionToken = with_diagnostics_t<asio::deferred_t>>
0816     auto async_close_statement(const statement& stmt, diagnostics& diag, CompletionToken&& token = {})
0817         BOOST_MYSQL_RETURN_TYPE(detail::async_close_statement_t<CompletionToken&&>)
0818     {
0819         return impl_
0820             .async_run(impl_.make_params_close_statement(stmt), diag, std::forward<CompletionToken>(token));
0821     }
0822 
0823     /**
0824      * \brief Reads a batch of rows.
0825      * \details
0826      * The number of rows that will be read is unspecified. If the operation represented by `st`
0827      * has still rows to read, at least one will be read. If there are no more rows, or
0828      * `st.should_read_rows() == false`, returns an empty `rows_view`.
0829      * \n
0830      * The number of rows that will be read depends on the connection's buffer size. The bigger the buffer,
0831      * the greater the batch size (up to a maximum). You can set the initial buffer size in the
0832      * constructor. The buffer may be
0833      * grown bigger by other read operations, if required.
0834      * \n
0835      * The returned view points into memory owned by `*this`. It will be valid until
0836      * `*this` performs the next network operation or is destroyed.
0837      */
0838     rows_view read_some_rows(execution_state& st, error_code& err, diagnostics& diag)
0839     {
0840         return impl_.run(impl_.make_params_read_some_rows(st), err, diag);
0841     }
0842 
0843     /// \copydoc read_some_rows(execution_state&,error_code&,diagnostics&)
0844     rows_view read_some_rows(execution_state& st)
0845     {
0846         error_code err;
0847         diagnostics diag;
0848         rows_view res = read_some_rows(st, err, diag);
0849         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
0850         return res;
0851     }
0852 
0853     /**
0854      * \copydoc read_some_rows(execution_state&,error_code&,diagnostics&)
0855      * \details
0856      * \par Handler signature
0857      * The handler signature for this operation is
0858      * `void(boost::mysql::error_code, boost::mysql::rows_view)`.
0859      *
0860      * \par Executor
0861      * Intermediate completion handlers, as well as the final handler, are executed using
0862      * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
0863      * executor.
0864      *
0865      * If the final handler has an associated immediate executor, and the operation
0866      * completes immediately, the final handler is dispatched to it.
0867      * Otherwise, the final handler is called as if it was submitted using `asio::post`,
0868      * and is never be called inline from within this function.
0869      */
0870     template <
0871         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, ::boost::mysql::rows_view))
0872             CompletionToken = with_diagnostics_t<asio::deferred_t>>
0873     auto async_read_some_rows(execution_state& st, CompletionToken&& token = {})
0874         BOOST_MYSQL_RETURN_TYPE(detail::async_read_some_rows_dynamic_t<CompletionToken&&>)
0875     {
0876         return async_read_some_rows(st, impl_.shared_diag(), std::forward<CompletionToken>(token));
0877     }
0878 
0879     /// \copydoc async_read_some_rows(execution_state&,CompletionToken&&)
0880     template <
0881         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, ::boost::mysql::rows_view))
0882             CompletionToken = with_diagnostics_t<asio::deferred_t>>
0883     auto async_read_some_rows(execution_state& st, diagnostics& diag, CompletionToken&& token = {})
0884         BOOST_MYSQL_RETURN_TYPE(detail::async_read_some_rows_dynamic_t<CompletionToken&&>)
0885     {
0886         return impl_
0887             .async_run(impl_.make_params_read_some_rows(st), diag, std::forward<CompletionToken>(token));
0888     }
0889 
0890 #ifdef BOOST_MYSQL_CXX14
0891 
0892     /**
0893      * \brief Reads a batch of rows.
0894      * \details
0895      * Reads a batch of rows of unspecified size into the storage given by `output`.
0896      * At most `output.size()` rows will be read. If the operation represented by `st`
0897      * has still rows to read, and `output.size() > 0`, at least one row will be read.
0898      * \n
0899      * Returns the number of read rows.
0900      * \n
0901      * If there are no more rows, or `st.should_read_rows() == false`, this function is a no-op and returns
0902      * zero.
0903      * \n
0904      * The number of rows that will be read depends on the connection's buffer size. The bigger the buffer,
0905      * the greater the batch size (up to a maximum). You can set the initial buffer size in the
0906      * constructor. The buffer may be grown bigger by other read operations, if required.
0907      * \n
0908      * Rows read by this function are owning objects, and don't hold any reference to
0909      * the connection's internal buffers (contrary what happens with the dynamic interface's counterpart).
0910      * \n
0911      * The type `SpanElementType` must be the underlying row type for one of the types in the
0912      * `StaticRow` parameter pack (i.e., one of the types in `underlying_row_t<StaticRow>...`).
0913      * The type must match the resultset that is currently being processed by `st`. For instance,
0914      * given `static_execution_state<T1, T2>`, when reading rows for the second resultset, `SpanElementType`
0915      * must exactly be `underlying_row_t<T2>`. If this is not the case, a runtime error will be issued.
0916      * \n
0917      * This function can report schema mismatches.
0918      */
0919     template <class SpanElementType, class... StaticRow>
0920     std::size_t read_some_rows(
0921         static_execution_state<StaticRow...>& st,
0922         span<SpanElementType> output,
0923         error_code& err,
0924         diagnostics& diag
0925     )
0926     {
0927         return impl_.run(impl_.make_params_read_some_rows_static(st, output), err, diag);
0928     }
0929 
0930     /**
0931      * \brief Reads a batch of rows.
0932      * \details
0933      * Reads a batch of rows of unspecified size into the storage given by `output`.
0934      * At most `output.size()` rows will be read. If the operation represented by `st`
0935      * has still rows to read, and `output.size() > 0`, at least one row will be read.
0936      * \n
0937      * Returns the number of read rows.
0938      * \n
0939      * If there are no more rows, or `st.should_read_rows() == false`, this function is a no-op and returns
0940      * zero.
0941      * \n
0942      * The number of rows that will be read depends on the connection's buffer size. The bigger the buffer,
0943      * the greater the batch size (up to a maximum). You can set the initial buffer size in the
0944      * constructor. The buffer may be grown bigger by other read operations, if required.
0945      * \n
0946      * Rows read by this function are owning objects, and don't hold any reference to
0947      * the connection's internal buffers (contrary what happens with the dynamic interface's counterpart).
0948      * \n
0949      * The type `SpanElementType` must be the underlying row type for one of the types in the
0950      * `StaticRow` parameter pack (i.e., one of the types in `underlying_row_t<StaticRow>...`).
0951      * The type must match the resultset that is currently being processed by `st`. For instance,
0952      * given `static_execution_state<T1, T2>`, when reading rows for the second resultset, `SpanElementType`
0953      * must exactly be `underlying_row_t<T2>`. If this is not the case, a runtime error will be issued.
0954      * \n
0955      * This function can report schema mismatches.
0956      */
0957     template <class SpanElementType, class... StaticRow>
0958     std::size_t read_some_rows(static_execution_state<StaticRow...>& st, span<SpanElementType> output)
0959     {
0960         error_code err;
0961         diagnostics diag;
0962         std::size_t res = read_some_rows(st, output, err, diag);
0963         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
0964         return res;
0965     }
0966 
0967     /**
0968      * \brief Reads a batch of rows.
0969      * \details
0970      * Reads a batch of rows of unspecified size into the storage given by `output`.
0971      * At most `output.size()` rows will be read. If the operation represented by `st`
0972      * has still rows to read, and `output.size() > 0`, at least one row will be read.
0973      * \n
0974      * Returns the number of read rows.
0975      * \n
0976      * If there are no more rows, or `st.should_read_rows() == false`, this function is a no-op and returns
0977      * zero.
0978      * \n
0979      * The number of rows that will be read depends on the connection's buffer size. The bigger the buffer,
0980      * the greater the batch size (up to a maximum). You can set the initial buffer size in the
0981      * constructor. The buffer may be grown bigger by other read operations, if required.
0982      * \n
0983      * Rows read by this function are owning objects, and don't hold any reference to
0984      * the connection's internal buffers (contrary what happens with the dynamic interface's counterpart).
0985      * \n
0986      * The type `SpanElementType` must be the underlying row type for one of the types in the
0987      * `StaticRow` parameter pack (i.e., one of the types in `underlying_row_t<StaticRow>...`).
0988      * The type must match the resultset that is currently being processed by `st`. For instance,
0989      * given `static_execution_state<T1, T2>`, when reading rows for the second resultset, `SpanElementType`
0990      * must exactly be `underlying_row_t<T2>`. If this is not the case, a runtime error will be issued.
0991      * \n
0992      * This function can report schema mismatches.
0993      *
0994      * \par Handler signature
0995      * The handler signature for this operation is
0996      * `void(boost::mysql::error_code, std::size_t)`.
0997      *
0998      * \par Executor
0999      * Intermediate completion handlers, as well as the final handler, are executed using
1000      * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
1001      * executor.
1002      *
1003      * If the final handler has an associated immediate executor, and the operation
1004      * completes immediately, the final handler is dispatched to it.
1005      * Otherwise, the final handler is called as if it was submitted using `asio::post`,
1006      * and is never be called inline from within this function.
1007      *
1008      * \par Object lifetimes
1009      * The storage that `output` references must be kept alive until the operation completes.
1010      */
1011     template <
1012         class SpanElementType,
1013         class... StaticRow,
1014         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, std::size_t))
1015             CompletionToken = with_diagnostics_t<asio::deferred_t>>
1016     auto async_read_some_rows(
1017         static_execution_state<StaticRow...>& st,
1018         span<SpanElementType> output,
1019         CompletionToken&& token = {}
1020     )
1021     {
1022         return async_read_some_rows(st, output, impl_.shared_diag(), std::forward<CompletionToken>(token));
1023     }
1024 
1025     /**
1026      * \brief Reads a batch of rows.
1027      * \details
1028      * Reads a batch of rows of unspecified size into the storage given by `output`.
1029      * At most `output.size()` rows will be read. If the operation represented by `st`
1030      * has still rows to read, and `output.size() > 0`, at least one row will be read.
1031      * \n
1032      * Returns the number of read rows.
1033      * \n
1034      * If there are no more rows, or `st.should_read_rows() == false`, this function is a no-op and returns
1035      * zero.
1036      * \n
1037      * The number of rows that will be read depends on the connection's buffer size. The bigger the buffer,
1038      * the greater the batch size (up to a maximum). You can set the initial buffer size in the
1039      * constructor. The buffer may be grown bigger by other read operations, if required.
1040      * \n
1041      * Rows read by this function are owning objects, and don't hold any reference to
1042      * the connection's internal buffers (contrary what happens with the dynamic interface's counterpart).
1043      * \n
1044      * The type `SpanElementType` must be the underlying row type for one of the types in the
1045      * `StaticRow` parameter pack (i.e., one of the types in `underlying_row_t<StaticRow>...`).
1046      * The type must match the resultset that is currently being processed by `st`. For instance,
1047      * given `static_execution_state<T1, T2>`, when reading rows for the second resultset, `SpanElementType`
1048      * must exactly be `underlying_row_t<T2>`. If this is not the case, a runtime error will be issued.
1049      * \n
1050      * This function can report schema mismatches.
1051      *
1052      * \par Handler signature
1053      * The handler signature for this operation is
1054      * `void(boost::mysql::error_code, std::size_t)`.
1055      *
1056      * \par Executor
1057      * Intermediate completion handlers, as well as the final handler, are executed using
1058      * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
1059      * executor.
1060      *
1061      * If the final handler has an associated immediate executor, and the operation
1062      * completes immediately, the final handler is dispatched to it.
1063      * Otherwise, the final handler is called as if it was submitted using `asio::post`,
1064      * and is never be called inline from within this function.
1065      *
1066      * \par Object lifetimes
1067      * The storage that `output` references must be kept alive until the operation completes.
1068      */
1069     template <
1070         class SpanElementType,
1071         class... StaticRow,
1072         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, std::size_t))
1073             CompletionToken = with_diagnostics_t<asio::deferred_t>>
1074     auto async_read_some_rows(
1075         static_execution_state<StaticRow...>& st,
1076         span<SpanElementType> output,
1077         diagnostics& diag,
1078         CompletionToken&& token = {}
1079     )
1080     {
1081         return impl_.async_run(
1082             impl_.make_params_read_some_rows_static(st, output),
1083             diag,
1084             std::forward<CompletionToken>(token)
1085         );
1086     }
1087 #endif
1088 
1089     /**
1090      * \brief Reads metadata for subsequent resultsets in a multi-resultset operation.
1091      * \details
1092      * If `st.should_read_head() == true`, this function will read the next resultset's
1093      * initial response message and metadata, if any. If the resultset indicates a failure
1094      * (e.g. the query associated to this resultset contained an error), this function will fail
1095      * with that error.
1096      * \n
1097      * If `st.should_read_head() == false`, this function is a no-op.
1098      * \n
1099      * `st` may be either an \ref execution_state or \ref static_execution_state object.
1100      * \n
1101      * This function is only relevant when using multi-function operations with statements
1102      * that return more than one resultset.
1103      * \n
1104      * When using the static interface, this function will detect schema mismatches for the resultset
1105      * currently being read. Further errors may be detected by subsequent invocations of this function
1106      * and by \ref read_some_rows.
1107      * \n
1108      */
1109     template <BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType>
1110     void read_resultset_head(ExecutionStateType& st, error_code& err, diagnostics& diag)
1111     {
1112         return impl_.run(impl_.make_params_read_resultset_head(st), err, diag);
1113     }
1114 
1115     /// \copydoc read_resultset_head
1116     template <BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType>
1117     void read_resultset_head(ExecutionStateType& st)
1118     {
1119         error_code err;
1120         diagnostics diag;
1121         read_resultset_head(st, err, diag);
1122         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
1123     }
1124 
1125     /**
1126      * \copydoc read_resultset_head
1127      * \par Handler signature
1128      * The handler signature for this operation is
1129      * `void(boost::mysql::error_code)`.
1130      *
1131      * \par Executor
1132      * Intermediate completion handlers, as well as the final handler, are executed using
1133      * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
1134      * executor.
1135      *
1136      * If the final handler has an associated immediate executor, and the operation
1137      * completes immediately, the final handler is dispatched to it.
1138      * Otherwise, the final handler is called as if it was submitted using `asio::post`,
1139      * and is never be called inline from within this function.
1140      */
1141     template <
1142         BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType,
1143         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
1144             CompletionToken = with_diagnostics_t<asio::deferred_t>>
1145     auto async_read_resultset_head(ExecutionStateType& st, CompletionToken&& token = {})
1146         BOOST_MYSQL_RETURN_TYPE(detail::async_read_resultset_head_t<CompletionToken&&>)
1147     {
1148         return async_read_resultset_head(st, impl_.shared_diag(), std::forward<CompletionToken>(token));
1149     }
1150 
1151     /// \copydoc async_read_resultset_head
1152     template <
1153         BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType,
1154         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
1155             CompletionToken = with_diagnostics_t<asio::deferred_t>>
1156     auto async_read_resultset_head(ExecutionStateType& st, diagnostics& diag, CompletionToken&& token = {})
1157         BOOST_MYSQL_RETURN_TYPE(detail::async_read_resultset_head_t<CompletionToken&&>)
1158     {
1159         return impl_
1160             .async_run(impl_.make_params_read_resultset_head(st), diag, std::forward<CompletionToken>(token));
1161     }
1162 
1163     /**
1164      * \brief Sets the connection's character set, as per SET NAMES.
1165      * \details
1166      * Sets the connection's character set by running a
1167      * <a href="https://dev.mysql.com/doc/refman/8.0/en/set-names.html">`SET NAMES`</a>
1168      * SQL statement, using the passed \ref character_set::name as the charset name to set.
1169      * \n
1170      * This function will also update the value returned by \ref current_character_set, so
1171      * prefer using this function over raw SQL statements.
1172      * \n
1173      * If the server was unable to set the character set to the requested value (e.g. because
1174      * the server does not support the requested charset), this function will fail,
1175      * as opposed to how \ref connect behaves when an unsupported collation is passed.
1176      * This is a limitation of MySQL servers.
1177      * \n
1178      * You need to perform connection establishment for this function to succeed, since it
1179      * involves communicating with the server.
1180      *
1181      * \par Object lifetimes
1182      * `charset` will be copied as required, and does not need to be kept alive.
1183      */
1184     void set_character_set(const character_set& charset, error_code& err, diagnostics& diag)
1185     {
1186         impl_.run(detail::set_character_set_algo_params{charset}, err, diag);
1187     }
1188 
1189     /// \copydoc set_character_set
1190     void set_character_set(const character_set& charset)
1191     {
1192         error_code err;
1193         diagnostics diag;
1194         set_character_set(charset, err, diag);
1195         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
1196     }
1197 
1198     /**
1199      * \copydoc set_character_set
1200      * \details
1201      * \n
1202      * \par Handler signature
1203      * The handler signature for this operation is `void(boost::mysql::error_code)`.
1204      *
1205      * \par Executor
1206      * Intermediate completion handlers, as well as the final handler, are executed using
1207      * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
1208      * executor.
1209      *
1210      * If the final handler has an associated immediate executor, and the operation
1211      * completes immediately, the final handler is dispatched to it.
1212      * Otherwise, the final handler is called as if it was submitted using `asio::post`,
1213      * and is never be called inline from within this function.
1214      */
1215     template <
1216         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
1217             CompletionToken = with_diagnostics_t<asio::deferred_t>>
1218     auto async_set_character_set(const character_set& charset, CompletionToken&& token = {})
1219         BOOST_MYSQL_RETURN_TYPE(detail::async_set_character_set_t<CompletionToken&&>)
1220     {
1221         return async_set_character_set(charset, impl_.shared_diag(), std::forward<CompletionToken>(token));
1222     }
1223 
1224     /// \copydoc async_set_character_set
1225     template <
1226         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
1227             CompletionToken = with_diagnostics_t<asio::deferred_t>>
1228     auto async_set_character_set(
1229         const character_set& charset,
1230         diagnostics& diag,
1231         CompletionToken&& token = {}
1232     ) BOOST_MYSQL_RETURN_TYPE(detail::async_set_character_set_t<CompletionToken&&>)
1233     {
1234         return impl_.async_run(
1235             detail::set_character_set_algo_params{charset},
1236             diag,
1237             std::forward<CompletionToken>(token)
1238         );
1239     }
1240 
1241     /**
1242      * \brief Checks whether the server is alive.
1243      * \details
1244      * If the server is alive, this function will complete without error.
1245      * If it's not, it will fail with the relevant network or protocol error.
1246      * \n
1247      * Note that ping requests are treated as any other type of request at the protocol
1248      * level, and won't be prioritized anyhow by the server. If the server is stuck
1249      * in a long-running query, the ping request won't be answered until the query is
1250      * finished.
1251      */
1252     void ping(error_code& err, diagnostics& diag) { impl_.run(detail::ping_algo_params{}, err, diag); }
1253 
1254     /// \copydoc ping
1255     void ping()
1256     {
1257         error_code err;
1258         diagnostics diag;
1259         ping(err, diag);
1260         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
1261     }
1262 
1263     /**
1264      * \copydoc ping
1265      * \details
1266      * \n
1267      * \par Handler signature
1268      * The handler signature for this operation is `void(boost::mysql::error_code)`.
1269      *
1270      * \par Executor
1271      * Intermediate completion handlers, as well as the final handler, are executed using
1272      * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
1273      * executor.
1274      *
1275      * If the final handler has an associated immediate executor, and the operation
1276      * completes immediately, the final handler is dispatched to it.
1277      * Otherwise, the final handler is called as if it was submitted using `asio::post`,
1278      * and is never be called inline from within this function.
1279      */
1280     template <
1281         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
1282             CompletionToken = with_diagnostics_t<asio::deferred_t>>
1283     auto async_ping(CompletionToken&& token = {})
1284         BOOST_MYSQL_RETURN_TYPE(detail::async_ping_t<CompletionToken&&>)
1285     {
1286         return async_ping(impl_.shared_diag(), std::forward<CompletionToken>(token));
1287     }
1288 
1289     /// \copydoc async_ping
1290     template <
1291         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
1292             CompletionToken = with_diagnostics_t<asio::deferred_t>>
1293     auto async_ping(diagnostics& diag, CompletionToken&& token = {})
1294         BOOST_MYSQL_RETURN_TYPE(detail::async_ping_t<CompletionToken&&>)
1295     {
1296         return impl_.async_run(detail::ping_algo_params{}, diag, std::forward<CompletionToken>(token));
1297     }
1298 
1299     /**
1300      * \brief Resets server-side session state, like variables and prepared statements.
1301      * \details
1302      * Resets all server-side state for the current session:
1303      * \n
1304      *   \li Rolls back any active transactions and resets autocommit mode.
1305      *   \li Releases all table locks.
1306      *   \li Drops all temporary tables.
1307      *   \li Resets all session system variables to their default values (including the ones set by `SET
1308      *       NAMES`) and clears all user-defined variables.
1309      *   \li Closes all prepared statements.
1310      * \n
1311      * A full reference on the affected session state can be found
1312      * <a href="https://dev.mysql.com/doc/c-api/8.0/en/mysql-reset-connection.html">here</a>.
1313      * \n
1314      * \n
1315      * This function will not reset the current physical connection and won't cause re-authentication.
1316      * It is faster than closing and re-opening a connection.
1317      * \n
1318      * The connection must be connected and authenticated before calling this function.
1319      * This function involves communication with the server, and thus may fail.
1320      *
1321      * \par Warning on character sets
1322      * This function will restore the connection's character set and collation **to the server's default**,
1323      * and not to the one specified during connection establishment. Some servers have `latin1` as their
1324      * default character set, which is not usually what you want. Since there is no way to know this
1325      * character set, \ref current_character_set will return `nullptr` after the operation succeeds.
1326      * We recommend always using \ref set_character_set or \ref async_set_character_set after calling this
1327      * function.
1328      * \n
1329      * You can find the character set that your server will use after the reset by running:
1330      * \code
1331      * "SELECT @@global.character_set_client, @@global.character_set_results;"
1332      * \endcode
1333      */
1334     void reset_connection(error_code& err, diagnostics& diag)
1335     {
1336         impl_.run(detail::reset_connection_algo_params{}, err, diag);
1337     }
1338 
1339     /// \copydoc reset_connection
1340     void reset_connection()
1341     {
1342         error_code err;
1343         diagnostics diag;
1344         reset_connection(err, diag);
1345         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
1346     }
1347 
1348     /**
1349      * \copydoc reset_connection
1350      * \details
1351      * \n
1352      * \par Handler signature
1353      * The handler signature for this operation is `void(boost::mysql::error_code)`.
1354      *
1355      * \par Executor
1356      * Intermediate completion handlers, as well as the final handler, are executed using
1357      * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
1358      * executor.
1359      *
1360      * If the final handler has an associated immediate executor, and the operation
1361      * completes immediately, the final handler is dispatched to it.
1362      * Otherwise, the final handler is called as if it was submitted using `asio::post`,
1363      * and is never be called inline from within this function.
1364      */
1365     template <
1366         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
1367             CompletionToken = with_diagnostics_t<asio::deferred_t>>
1368     auto async_reset_connection(CompletionToken&& token = {})
1369         BOOST_MYSQL_RETURN_TYPE(detail::async_reset_connection_t<CompletionToken&&>)
1370     {
1371         return async_reset_connection(impl_.shared_diag(), std::forward<CompletionToken>(token));
1372     }
1373 
1374     /// \copydoc async_reset_connection
1375     template <
1376         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
1377             CompletionToken = with_diagnostics_t<asio::deferred_t>>
1378     auto async_reset_connection(diagnostics& diag, CompletionToken&& token = {})
1379         BOOST_MYSQL_RETURN_TYPE(detail::async_reset_connection_t<CompletionToken&&>)
1380     {
1381         return impl_
1382             .async_run(detail::reset_connection_algo_params{}, diag, std::forward<CompletionToken>(token));
1383     }
1384 
1385     /**
1386      * \brief Cleanly closes the connection to the server.
1387      * \details
1388      * This function does the following:
1389      * \n
1390      * \li Sends a quit request. This is required by the MySQL protocol, to inform
1391      *     the server that we're closing the connection gracefully.
1392      * \li If the connection is using TLS (`this->uses_ssl() == true`), performs
1393      *     the TLS shutdown.
1394      * \li Closes the transport-level connection (the TCP or UNIX socket).
1395      * \n
1396      * Since this function involves writing a message to the server, it can fail.
1397      * Only use this function if you know that the connection is healthy and you want
1398      * to cleanly close it.
1399      * \n
1400      * If you don't call this function, the destructor or successive connects will
1401      * perform a transport-layer close. This doesn't cause any resource leaks, but may
1402      * cause warnings to be written to the server logs.
1403      */
1404     void close(error_code& err, diagnostics& diag)
1405     {
1406         impl_.run(detail::close_connection_algo_params{}, err, diag);
1407     }
1408 
1409     /// \copydoc close
1410     void close()
1411     {
1412         error_code err;
1413         diagnostics diag;
1414         close(err, diag);
1415         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
1416     }
1417 
1418     /**
1419      * \copydoc close
1420      * \details
1421      * \par Handler signature
1422      * The handler signature for this operation is `void(boost::mysql::error_code)`.
1423      *
1424      * \par Executor
1425      * Intermediate completion handlers, as well as the final handler, are executed using
1426      * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
1427      * executor.
1428      *
1429      * If the final handler has an associated immediate executor, and the operation
1430      * completes immediately, the final handler is dispatched to it.
1431      * Otherwise, the final handler is called as if it was submitted using `asio::post`,
1432      * and is never be called inline from within this function.
1433      */
1434     template <
1435         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code))
1436             CompletionToken = with_diagnostics_t<asio::deferred_t>>
1437     auto async_close(CompletionToken&& token = {})
1438         BOOST_MYSQL_RETURN_TYPE(detail::async_close_connection_t<CompletionToken&&>)
1439     {
1440         return async_close(impl_.shared_diag(), std::forward<CompletionToken>(token));
1441     }
1442 
1443     /// \copydoc async_close
1444     template <
1445         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code))
1446             CompletionToken = with_diagnostics_t<asio::deferred_t>>
1447     auto async_close(diagnostics& diag, CompletionToken&& token = {})
1448         BOOST_MYSQL_RETURN_TYPE(detail::async_close_connection_t<CompletionToken&&>)
1449     {
1450         return this->impl_
1451             .async_run(detail::close_connection_algo_params{}, diag, std::forward<CompletionToken>(token));
1452     }
1453 
1454     /**
1455      * \brief Runs a set of pipelined requests.
1456      * \details
1457      * Runs the pipeline described by `req` and stores its response in `res`.
1458      * After the operation completes, `res` will have as many elements as stages
1459      * were in `req`, even if the operation fails.
1460      * \n
1461      * Request stages are seen by the server as a series of unrelated requests.
1462      * As a consequence, all stages are always run, even if previous stages fail.
1463      * \n
1464      * If all stages succeed, the operation completes successfully. Thus, there is no need to check
1465      * the per-stage error code in `res` if this operation completed successfully.
1466      * \n
1467      * If any stage fails with a non-fatal error (as per \ref is_fatal_error), the result of the operation
1468      * is the first encountered error. You can check which stages succeeded and which ones didn't by
1469      * inspecting each stage in `res`.
1470      * \n
1471      * If any stage fails with a fatal error, the result of the operation is the fatal error.
1472      * Successive stages will be marked as failed with the fatal error. The server may or may
1473      * not have processed such stages.
1474      */
1475     void run_pipeline(
1476         const pipeline_request& req,
1477         std::vector<stage_response>& res,
1478         error_code& err,
1479         diagnostics& diag
1480     )
1481     {
1482         impl_.run(impl_.make_params_pipeline(req, res), err, diag);
1483     }
1484 
1485     /// \copydoc run_pipeline
1486     void run_pipeline(const pipeline_request& req, std::vector<stage_response>& res)
1487     {
1488         error_code err;
1489         diagnostics diag;
1490         run_pipeline(req, res, err, diag);
1491         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
1492     }
1493 
1494     /**
1495      * \copydoc run_pipeline
1496      * \details
1497      * \par Handler signature
1498      * The handler signature for this operation is `void(boost::mysql::error_code)`.
1499      *
1500      * \par Executor
1501      * Intermediate completion handlers, as well as the final handler, are executed using
1502      * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
1503      * executor.
1504      *
1505      * If the final handler has an associated immediate executor, and the operation
1506      * completes immediately, the final handler is dispatched to it.
1507      * Otherwise, the final handler is called as if it was submitted using `asio::post`,
1508      * and is never be called inline from within this function.
1509      *
1510      * \par Object lifetimes
1511      * The request and response objects must be kept alive and should not be modified
1512      * until the operation completes.
1513      */
1514     template <
1515         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code))
1516             CompletionToken = with_diagnostics_t<asio::deferred_t>>
1517     auto async_run_pipeline(
1518         const pipeline_request& req,
1519         std::vector<stage_response>& res,
1520         CompletionToken&& token = {}
1521     ) BOOST_MYSQL_RETURN_TYPE(detail::async_run_pipeline_t<CompletionToken&&>)
1522     {
1523         return async_run_pipeline(req, res, impl_.shared_diag(), std::forward<CompletionToken>(token));
1524     }
1525 
1526     /// \copydoc async_run_pipeline
1527     template <
1528         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code))
1529             CompletionToken = with_diagnostics_t<asio::deferred_t>>
1530     auto async_run_pipeline(
1531         const pipeline_request& req,
1532         std::vector<stage_response>& res,
1533         diagnostics& diag,
1534         CompletionToken&& token = {}
1535     ) BOOST_MYSQL_RETURN_TYPE(detail::async_run_pipeline_t<CompletionToken&&>)
1536     {
1537         return this->impl_
1538             .async_run(impl_.make_params_pipeline(req, res), diag, std::forward<CompletionToken>(token));
1539     }
1540 };
1541 
1542 }  // namespace mysql
1543 }  // namespace boost
1544 
1545 #ifdef BOOST_MYSQL_HEADER_ONLY
1546 #include <boost/mysql/impl/any_connection.ipp>
1547 #endif
1548 
1549 #endif