Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:58:26

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_CONNECTION_HPP
0009 #define BOOST_MYSQL_CONNECTION_HPP
0010 
0011 #include <boost/mysql/buffer_params.hpp>
0012 #include <boost/mysql/defaults.hpp>
0013 #include <boost/mysql/diagnostics.hpp>
0014 #include <boost/mysql/error_code.hpp>
0015 #include <boost/mysql/execution_state.hpp>
0016 #include <boost/mysql/handshake_params.hpp>
0017 #include <boost/mysql/metadata_mode.hpp>
0018 #include <boost/mysql/results.hpp>
0019 #include <boost/mysql/rows_view.hpp>
0020 #include <boost/mysql/statement.hpp>
0021 #include <boost/mysql/string_view.hpp>
0022 
0023 #include <boost/mysql/detail/access.hpp>
0024 #include <boost/mysql/detail/algo_params.hpp>
0025 #include <boost/mysql/detail/connection_impl.hpp>
0026 #include <boost/mysql/detail/engine_stream_adaptor.hpp>
0027 #include <boost/mysql/detail/execution_concepts.hpp>
0028 #include <boost/mysql/detail/rebind_executor.hpp>
0029 #include <boost/mysql/detail/socket_stream.hpp>
0030 #include <boost/mysql/detail/throw_on_error_loc.hpp>
0031 #include <boost/mysql/detail/writable_field_traits.hpp>
0032 
0033 #include <boost/assert.hpp>
0034 
0035 #include <cstddef>
0036 #include <type_traits>
0037 #include <utility>
0038 
0039 /// The Boost libraries namespace.
0040 namespace boost {
0041 /// Boost.MySQL library namespace.
0042 namespace mysql {
0043 
0044 // Forward declarations
0045 template <class... StaticRow>
0046 class static_execution_state;
0047 
0048 /**
0049  * \brief (Legacy) A connection to a MySQL server.
0050  * \details
0051  * Represents a templated connection to a MySQL server.
0052  *
0053  * `connection` owns a `Stream` object that
0054  * is accessed by functions involving network operations, as well as session state. You can access
0055  * the stream using \ref connection::stream, and its executor via \ref connection::get_executor. The
0056  * executor used by this object is always the same as the underlying stream.
0057  *
0058  * \par Single outstanding async operation per connection
0059  * At any given point in time, only one async operation can be outstanding
0060  * per connection. If an async operation is initiated while another one is in progress,
0061  * it will fail with \ref client_errc::operation_in_progress.
0062  *
0063  * \par Thread safety
0064  * Distinct objects: safe. \n
0065  * Shared objects: unsafe. \n
0066  * This class is <b>not thread-safe</b>: for a single object, if you
0067  * call its member functions concurrently from separate threads, you will get a race condition.
0068  *
0069  * \par Legacy
0070  * New code should use \ref any_connection instead of this class, as it's simpler to use
0071  * and provides the same level of performance.
0072  */
0073 template <class Stream>
0074 class connection
0075 {
0076     detail::connection_impl impl_;
0077 
0078 public:
0079     /**
0080      * \brief Initializing constructor.
0081      * \details
0082      * As part of the initialization, an internal `Stream` object is created.
0083      *
0084      * \par Exception safety
0085      * Basic guarantee. Throws if the `Stream` constructor throws
0086      * or if memory allocation for internal state fails.
0087      *
0088      * \param args Arguments to be forwarded to the `Stream` constructor.
0089      */
0090     template <
0091         class... Args,
0092         class EnableIf = typename std::enable_if<std::is_constructible<Stream, Args...>::value>::type>
0093     connection(Args&&... args) : connection(buffer_params(), std::forward<Args>(args)...)
0094     {
0095     }
0096 
0097     /**
0098      * \brief Initializing constructor with buffer params.
0099      * \details
0100      * As part of the initialization, an internal `Stream` object is created.
0101      *
0102      * \par Exception safety
0103      * Basic guarantee. Throws if the `Stream` constructor throws
0104      * or if memory allocation for internal state fails.
0105      *
0106      * \param buff_params Specifies initial sizes for internal buffers.
0107      * \param args Arguments to be forwarded to the `Stream` constructor.
0108      */
0109     template <
0110         class... Args,
0111         class EnableIf = typename std::enable_if<std::is_constructible<Stream, Args...>::value>::type>
0112     connection(const buffer_params& buff_params, Args&&... args)
0113         : impl_(
0114               buff_params.initial_read_size(),
0115               static_cast<std::size_t>(-1),
0116               detail::make_engine<Stream>(std::forward<Args>(args)...)
0117           )
0118     {
0119     }
0120 
0121     /**
0122      * \brief Move constructor.
0123      */
0124     connection(connection&& other) = default;
0125 
0126     /**
0127      * \brief Move assignment.
0128      */
0129     connection& operator=(connection&& rhs) = default;
0130 
0131 #ifndef BOOST_MYSQL_DOXYGEN
0132     connection(const connection&) = delete;
0133     connection& operator=(const connection&) = delete;
0134 #endif
0135 
0136     /// The executor type associated to this object.
0137     using executor_type = typename Stream::executor_type;
0138 
0139     /// Retrieves the executor associated to this object.
0140     executor_type get_executor() { return stream().get_executor(); }
0141 
0142     /// The `Stream` type this connection is using.
0143     using stream_type = Stream;
0144 
0145     /**
0146      * \brief Retrieves the underlying Stream object.
0147      * \details
0148      *
0149      * \par Exception safety
0150      * No-throw guarantee.
0151      */
0152     Stream& stream() noexcept { return detail::stream_from_engine<Stream>(impl_.get_engine()); }
0153 
0154     /**
0155      * \brief Retrieves the underlying Stream object.
0156      * \details
0157      *
0158      * \par Exception safety
0159      * No-throw guarantee.
0160      */
0161     const Stream& stream() const noexcept { return detail::stream_from_engine<Stream>(impl_.get_engine()); }
0162 
0163     /**
0164      * \brief Returns whether the connection negotiated the use of SSL or not.
0165      * \details
0166      * This function can be used to determine whether you are using a SSL
0167      * connection or not when using SSL negotiation.
0168      * \n
0169      * This function always returns `false` if the underlying
0170      * stream does not support SSL. This function always returns `false`
0171      * for connections that haven't been
0172      * established yet (handshake not run yet). If the handshake fails,
0173      * the return value is undefined.
0174      *
0175      * \par Exception safety
0176      * No-throw guarantee.
0177      *
0178      * \returns Whether the connection is using SSL.
0179      */
0180     bool uses_ssl() const noexcept { return impl_.ssl_active(); }
0181 
0182     /// \copydoc any_connection::meta_mode
0183     metadata_mode meta_mode() const noexcept { return impl_.meta_mode(); }
0184 
0185     /// \copydoc any_connection::set_meta_mode
0186     void set_meta_mode(metadata_mode v) noexcept { impl_.set_meta_mode(v); }
0187 
0188     /**
0189      * \brief Establishes a connection to a MySQL server.
0190      * \details
0191      * This function is only available if `Stream` satisfies the
0192      * `SocketStream` concept.
0193      * \n
0194      * Connects the underlying stream and performs the handshake
0195      * with the server. The underlying stream is closed in case of error. Prefer
0196      * this function to \ref connection::handshake.
0197      * \n
0198      * If using a SSL-capable stream, the SSL handshake will be performed by this function.
0199      * \n
0200      * `endpoint` should be convertible to `Stream::lowest_layer_type::endpoint_type`.
0201      */
0202     template <typename EndpointType>
0203     void connect(
0204         const EndpointType& endpoint,
0205         const handshake_params& params,
0206         error_code& ec,
0207         diagnostics& diag
0208     )
0209     {
0210         static_assert(
0211             detail::is_socket_stream<Stream>::value,
0212             "connect can only be used if Stream satisfies the SocketStream concept"
0213         );
0214         impl_.connect<typename Stream::lowest_layer_type::endpoint_type>(endpoint, params, ec, diag);
0215     }
0216 
0217     /// \copydoc connect
0218     template <typename EndpointType>
0219     void connect(const EndpointType& endpoint, const handshake_params& params)
0220     {
0221         static_assert(
0222             detail::is_socket_stream<Stream>::value,
0223             "connect can only be used if Stream satisfies the SocketStream concept"
0224         );
0225         error_code err;
0226         diagnostics diag;
0227         connect(endpoint, params, err, diag);
0228         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
0229     }
0230 
0231     /**
0232      * \copydoc connect
0233      * \par Object lifetimes
0234      * The strings pointed to by `params` should be kept alive by the caller
0235      * until the operation completes, as no copy is made by the library.
0236      * `endpoint` is copied as required and doesn't need to be kept alive.
0237      *
0238      * \par Handler signature
0239      * The handler signature for this operation is `void(boost::mysql::error_code)`.
0240      *
0241      * \par Executor
0242      * Intermediate completion handlers, as well as the final handler, are executed using
0243      * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
0244      * executor.
0245      *
0246      * If the final handler has an associated immediate executor, and the operation
0247      * completes immediately, the final handler is dispatched to it.
0248      * Otherwise, the final handler is called as if it was submitted using `asio::post`,
0249      * and is never be called inline from within this function.
0250      */
0251     template <
0252         typename EndpointType,
0253         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
0254             CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0255     BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
0256     async_connect(
0257         const EndpointType& endpoint,
0258         const handshake_params& params,
0259         CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
0260     )
0261     {
0262         static_assert(
0263             detail::is_socket_stream<Stream>::value,
0264             "async_connect can only be used if Stream satisfies the SocketStream concept"
0265         );
0266         return async_connect(endpoint, params, impl_.shared_diag(), std::forward<CompletionToken>(token));
0267     }
0268 
0269     /// \copydoc async_connect
0270     template <
0271         typename EndpointType,
0272         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
0273             CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0274     BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
0275     async_connect(
0276         const EndpointType& endpoint,
0277         const handshake_params& params,
0278         diagnostics& diag,
0279         CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
0280     )
0281     {
0282         static_assert(
0283             detail::is_socket_stream<Stream>::value,
0284             "async_connect can only be used if Stream satisfies the SocketStream concept"
0285         );
0286         return impl_.async_connect<typename Stream::lowest_layer_type::endpoint_type>(
0287             endpoint,
0288             params,
0289             diag,
0290             std::forward<CompletionToken>(token)
0291         );
0292     }
0293 
0294     /**
0295      * \brief Performs the MySQL-level handshake.
0296      * \details
0297      * Does not connect the underlying stream.
0298      * If the `Stream` template parameter fulfills the `SocketConnection`
0299      * requirements, use \ref connection::connect instead of this function.
0300      * \n
0301      * If using a SSL-capable stream, the SSL handshake will be performed by this function.
0302      */
0303     void handshake(const handshake_params& params, error_code& ec, diagnostics& diag)
0304     {
0305         impl_.run(impl_.make_params_handshake(params), ec, diag);
0306     }
0307 
0308     /// \copydoc handshake
0309     void handshake(const handshake_params& params)
0310     {
0311         error_code err;
0312         diagnostics diag;
0313         handshake(params, err, diag);
0314         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
0315     }
0316 
0317     /**
0318      * \copydoc handshake
0319      * \par Object lifetimes
0320      * The strings pointed to by `params` should be kept alive by the caller
0321      * until the operation completes, as no copy is made by the library.
0322      *
0323      * \par Handler signature
0324      * The handler signature for this operation is `void(boost::mysql::error_code)`.
0325      *
0326      * \par Executor
0327      * Intermediate completion handlers, as well as the final handler, are executed using
0328      * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
0329      * executor.
0330      *
0331      * If the final handler has an associated immediate executor, and the operation
0332      * completes immediately, the final handler is dispatched to it.
0333      * Otherwise, the final handler is called as if it was submitted using `asio::post`,
0334      * and is never be called inline from within this function.
0335      */
0336     template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
0337                   CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0338     auto async_handshake(
0339         const handshake_params& params,
0340         CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
0341     ) BOOST_MYSQL_RETURN_TYPE(detail::async_handshake_t<CompletionToken&&>)
0342     {
0343         return async_handshake(params, impl_.shared_diag(), std::forward<CompletionToken>(token));
0344     }
0345 
0346     /// \copydoc async_handshake
0347     template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
0348                   CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0349     auto async_handshake(
0350         const handshake_params& params,
0351         diagnostics& diag,
0352         CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
0353     ) BOOST_MYSQL_RETURN_TYPE(detail::async_handshake_t<CompletionToken&&>)
0354     {
0355         return impl_
0356             .async_run(impl_.make_params_handshake(params), diag, std::forward<CompletionToken>(token));
0357     }
0358 
0359     /// \copydoc any_connection::execute
0360     template <BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest, BOOST_MYSQL_RESULTS_TYPE ResultsType>
0361     void execute(ExecutionRequest&& req, ResultsType& result, error_code& err, diagnostics& diag)
0362     {
0363         impl_.execute(std::forward<ExecutionRequest>(req), result, err, diag);
0364     }
0365 
0366     /// \copydoc execute
0367     template <BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest, BOOST_MYSQL_RESULTS_TYPE ResultsType>
0368     void execute(ExecutionRequest&& req, ResultsType& result)
0369     {
0370         error_code err;
0371         diagnostics diag;
0372         execute(std::forward<ExecutionRequest>(req), result, err, diag);
0373         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
0374     }
0375 
0376     /// \copydoc any_connection::async_execute
0377     template <
0378         BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,
0379         BOOST_MYSQL_RESULTS_TYPE ResultsType,
0380         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
0381             CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0382     auto async_execute(
0383         ExecutionRequest&& req,
0384         ResultsType& result,
0385         CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
0386     ) BOOST_MYSQL_RETURN_TYPE(detail::async_execute_t<ExecutionRequest&&, ResultsType, CompletionToken&&>)
0387     {
0388         return async_execute(
0389             std::forward<ExecutionRequest>(req),
0390             result,
0391             impl_.shared_diag(),
0392             std::forward<CompletionToken>(token)
0393         );
0394     }
0395 
0396     /// \copydoc async_execute
0397     template <
0398         BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,
0399         BOOST_MYSQL_RESULTS_TYPE ResultsType,
0400         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
0401             CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0402     auto async_execute(
0403         ExecutionRequest&& req,
0404         ResultsType& result,
0405         diagnostics& diag,
0406         CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
0407     ) BOOST_MYSQL_RETURN_TYPE(detail::async_execute_t<ExecutionRequest&&, ResultsType, CompletionToken&&>)
0408     {
0409         return impl_.async_execute(
0410             std::forward<ExecutionRequest>(req),
0411             result,
0412             diag,
0413             std::forward<CompletionToken>(token)
0414         );
0415     }
0416 
0417     /// \copydoc any_connection::start_execution
0418     template <
0419         BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,
0420         BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType>
0421     void start_execution(ExecutionRequest&& req, ExecutionStateType& st, error_code& err, diagnostics& diag)
0422     {
0423         impl_.start_execution(std::forward<ExecutionRequest>(req), st, err, diag);
0424     }
0425 
0426     /// \copydoc start_execution
0427     template <
0428         BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,
0429         BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType>
0430     void start_execution(ExecutionRequest&& req, ExecutionStateType& st)
0431     {
0432         error_code err;
0433         diagnostics diag;
0434         start_execution(std::forward<ExecutionRequest>(req), st, err, diag);
0435         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
0436     }
0437 
0438     /// \copydoc any_connection::async_start_execution
0439     template <
0440         BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,
0441         BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType,
0442         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
0443             CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0444     auto async_start_execution(
0445         ExecutionRequest&& req,
0446         ExecutionStateType& st,
0447         CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
0448     )
0449         BOOST_MYSQL_RETURN_TYPE(detail::async_start_execution_t<
0450                                 ExecutionRequest&&,
0451                                 ExecutionStateType,
0452                                 CompletionToken&&>)
0453     {
0454         return async_start_execution(
0455             std::forward<ExecutionRequest>(req),
0456             st,
0457             impl_.shared_diag(),
0458             std::forward<CompletionToken>(token)
0459         );
0460     }
0461 
0462     /// \copydoc async_start_execution
0463     template <
0464         BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,
0465         BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType,
0466         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
0467             CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0468     auto async_start_execution(
0469         ExecutionRequest&& req,
0470         ExecutionStateType& st,
0471         diagnostics& diag,
0472         CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
0473     )
0474         BOOST_MYSQL_RETURN_TYPE(detail::async_start_execution_t<
0475                                 ExecutionRequest&&,
0476                                 ExecutionStateType,
0477                                 CompletionToken&&>)
0478     {
0479         return impl_.async_start_execution(
0480             std::forward<ExecutionRequest>(req),
0481             st,
0482             diag,
0483             std::forward<CompletionToken>(token)
0484         );
0485     }
0486 
0487     /// \copydoc any_connection::prepare_statement
0488     statement prepare_statement(string_view stmt, error_code& err, diagnostics& diag)
0489     {
0490         return impl_.run(detail::prepare_statement_algo_params{stmt}, err, diag);
0491     }
0492 
0493     /// \copydoc prepare_statement
0494     statement prepare_statement(string_view stmt)
0495     {
0496         error_code err;
0497         diagnostics diag;
0498         statement res = prepare_statement(stmt, err, diag);
0499         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
0500         return res;
0501     }
0502 
0503     /// \copydoc any_connection::async_prepare_statement
0504     template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, ::boost::mysql::statement))
0505                   CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0506     auto async_prepare_statement(
0507         string_view stmt,
0508         CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
0509     ) BOOST_MYSQL_RETURN_TYPE(detail::async_prepare_statement_t<CompletionToken&&>)
0510     {
0511         return async_prepare_statement(stmt, impl_.shared_diag(), std::forward<CompletionToken>(token));
0512     }
0513 
0514     /// \copydoc async_prepare_statement
0515     template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, ::boost::mysql::statement))
0516                   CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0517     auto async_prepare_statement(
0518         string_view stmt,
0519         diagnostics& diag,
0520         CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
0521     ) BOOST_MYSQL_RETURN_TYPE(detail::async_prepare_statement_t<CompletionToken&&>)
0522     {
0523         return impl_.async_run(
0524             detail::prepare_statement_algo_params{stmt},
0525             diag,
0526             std::forward<CompletionToken>(token)
0527         );
0528     }
0529 
0530     /// \copydoc any_connection::close_statement
0531     void close_statement(const statement& stmt, error_code& err, diagnostics& diag)
0532     {
0533         impl_.run(impl_.make_params_close_statement(stmt), err, diag);
0534     }
0535 
0536     /// \copydoc close_statement
0537     void close_statement(const statement& stmt)
0538     {
0539         error_code err;
0540         diagnostics diag;
0541         close_statement(stmt, err, diag);
0542         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
0543     }
0544 
0545     /// \copydoc any_connection::async_close_statement
0546     template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
0547                   CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0548     auto async_close_statement(
0549         const statement& stmt,
0550         CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
0551     ) BOOST_MYSQL_RETURN_TYPE(detail::async_close_statement_t<CompletionToken&&>)
0552     {
0553         return async_close_statement(stmt, impl_.shared_diag(), std::forward<CompletionToken>(token));
0554     }
0555 
0556     /// \copydoc async_close_statement
0557     template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
0558                   CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0559     auto async_close_statement(
0560         const statement& stmt,
0561         diagnostics& diag,
0562         CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
0563     ) BOOST_MYSQL_RETURN_TYPE(detail::async_close_statement_t<CompletionToken&&>)
0564     {
0565         return impl_
0566             .async_run(impl_.make_params_close_statement(stmt), diag, std::forward<CompletionToken>(token));
0567     }
0568 
0569     /// \copydoc any_connection::read_some_rows
0570     rows_view read_some_rows(execution_state& st, error_code& err, diagnostics& diag)
0571     {
0572         return impl_.run(impl_.make_params_read_some_rows(st), err, diag);
0573     }
0574 
0575     /// \copydoc read_some_rows(execution_state&,error_code&,diagnostics&)
0576     rows_view read_some_rows(execution_state& st)
0577     {
0578         error_code err;
0579         diagnostics diag;
0580         rows_view res = read_some_rows(st, err, diag);
0581         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
0582         return res;
0583     }
0584 
0585     /// \copydoc any_connection::async_read_some_rows(execution_state&,CompletionToken&&)
0586     template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, ::boost::mysql::rows_view))
0587                   CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0588     auto async_read_some_rows(
0589         execution_state& st,
0590         CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
0591     ) BOOST_MYSQL_RETURN_TYPE(detail::async_read_some_rows_dynamic_t<CompletionToken&&>)
0592     {
0593         return async_read_some_rows(st, impl_.shared_diag(), std::forward<CompletionToken>(token));
0594     }
0595 
0596     /// \copydoc async_read_some_rows(execution_state&,CompletionToken&&)
0597     template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, ::boost::mysql::rows_view))
0598                   CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0599     auto async_read_some_rows(
0600         execution_state& st,
0601         diagnostics& diag,
0602         CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
0603     ) BOOST_MYSQL_RETURN_TYPE(detail::async_read_some_rows_dynamic_t<CompletionToken&&>)
0604     {
0605         return impl_
0606             .async_run(impl_.make_params_read_some_rows(st), diag, std::forward<CompletionToken>(token));
0607     }
0608 
0609 #ifdef BOOST_MYSQL_CXX14
0610 
0611     /**
0612      * \brief Reads a batch of rows.
0613      * \details
0614      * Reads a batch of rows of unspecified size into the storage given by `output`.
0615      * At most `output.size()` rows will be read. If the operation represented by `st`
0616      * has still rows to read, and `output.size() > 0`, at least one row will be read.
0617      * \n
0618      * Returns the number of read rows.
0619      * \n
0620      * If there are no more rows, or `st.should_read_rows() == false`, this function is a no-op and returns
0621      * zero.
0622      * \n
0623      * The number of rows that will be read depends on the connection's buffer size. The bigger the buffer,
0624      * the greater the batch size (up to a maximum). You can set the initial buffer size in `connection`'s
0625      * constructor, using \ref buffer_params::initial_read_size. The buffer may be
0626      * grown bigger by other read operations, if required.
0627      * \n
0628      * Rows read by this function are owning objects, and don't hold any reference to
0629      * the connection's internal buffers (contrary what happens with the dynamic interface's counterpart).
0630      * \n
0631      * The type `SpanElementType` must be the underlying row type for one of the types in the
0632      * `StaticRow` parameter pack (i.e., one of the types in `underlying_row_t<StaticRow>...`).
0633      * The type must match the resultset that is currently being processed by `st`. For instance,
0634      * given `static_execution_state<T1, T2>`, when reading rows for the second resultset, `SpanElementType`
0635      * must exactly be `underlying_row_t<T2>`. If this is not the case, a runtime error will be issued.
0636      * \n
0637      * This function can report schema mismatches.
0638      */
0639     template <class SpanElementType, class... StaticRow>
0640     std::size_t read_some_rows(
0641         static_execution_state<StaticRow...>& st,
0642         span<SpanElementType> output,
0643         error_code& err,
0644         diagnostics& diag
0645     )
0646     {
0647         return impl_.run(impl_.make_params_read_some_rows_static(st, output), err, diag);
0648     }
0649 
0650     /**
0651      * \brief Reads a batch of rows.
0652      * \details
0653      * Reads a batch of rows of unspecified size into the storage given by `output`.
0654      * At most `output.size()` rows will be read. If the operation represented by `st`
0655      * has still rows to read, and `output.size() > 0`, at least one row will be read.
0656      * \n
0657      * Returns the number of read rows.
0658      * \n
0659      * If there are no more rows, or `st.should_read_rows() == false`, this function is a no-op and returns
0660      * zero.
0661      * \n
0662      * The number of rows that will be read depends on the connection's buffer size. The bigger the buffer,
0663      * the greater the batch size (up to a maximum). You can set the initial buffer size in `connection`'s
0664      * constructor, using \ref buffer_params::initial_read_size. The buffer may be
0665      * grown bigger by other read operations, if required.
0666      * \n
0667      * Rows read by this function are owning objects, and don't hold any reference to
0668      * the connection's internal buffers (contrary what happens with the dynamic interface's counterpart).
0669      * \n
0670      * The type `SpanElementType` must be the underlying row type for one of the types in the
0671      * `StaticRow` parameter pack (i.e., one of the types in `underlying_row_t<StaticRow>...`).
0672      * The type must match the resultset that is currently being processed by `st`. For instance,
0673      * given `static_execution_state<T1, T2>`, when reading rows for the second resultset, `SpanElementType`
0674      * must exactly be `underlying_row_t<T2>`. If this is not the case, a runtime error will be issued.
0675      * \n
0676      * This function can report schema mismatches.
0677      */
0678     template <class SpanElementType, class... StaticRow>
0679     std::size_t read_some_rows(static_execution_state<StaticRow...>& st, span<SpanElementType> output)
0680     {
0681         error_code err;
0682         diagnostics diag;
0683         std::size_t res = read_some_rows(st, output, err, diag);
0684         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
0685         return res;
0686     }
0687 
0688     /**
0689      * \brief Reads a batch of rows.
0690      * \details
0691      * Reads a batch of rows of unspecified size into the storage given by `output`.
0692      * At most `output.size()` rows will be read. If the operation represented by `st`
0693      * has still rows to read, and `output.size() > 0`, at least one row will be read.
0694      * \n
0695      * Returns the number of read rows.
0696      * \n
0697      * If there are no more rows, or `st.should_read_rows() == false`, this function is a no-op and returns
0698      * zero.
0699      * \n
0700      * The number of rows that will be read depends on the connection's buffer size. The bigger the buffer,
0701      * the greater the batch size (up to a maximum). You can set the initial buffer size in `connection`'s
0702      * constructor, using \ref buffer_params::initial_read_size. The buffer may be
0703      * grown bigger by other read operations, if required.
0704      * \n
0705      * Rows read by this function are owning objects, and don't hold any reference to
0706      * the connection's internal buffers (contrary what happens with the dynamic interface's counterpart).
0707      * \n
0708      * The type `SpanElementType` must be the underlying row type for one of the types in the
0709      * `StaticRow` parameter pack (i.e., one of the types in `underlying_row_t<StaticRow>...`).
0710      * The type must match the resultset that is currently being processed by `st`. For instance,
0711      * given `static_execution_state<T1, T2>`, when reading rows for the second resultset, `SpanElementType`
0712      * must exactly be `underlying_row_t<T2>`. If this is not the case, a runtime error will be issued.
0713      * \n
0714      * This function can report schema mismatches.
0715      *
0716      * \par Handler signature
0717      * The handler signature for this operation is
0718      * `void(boost::mysql::error_code, std::size_t)`.
0719      *
0720      * \par Executor
0721      * Intermediate completion handlers, as well as the final handler, are executed using
0722      * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
0723      * executor.
0724      *
0725      * If the final handler has an associated immediate executor, and the operation
0726      * completes immediately, the final handler is dispatched to it.
0727      * Otherwise, the final handler is called as if it was submitted using `asio::post`,
0728      * and is never be called inline from within this function.
0729      *
0730      * \par Object lifetimes
0731      * The storage that `output` references must be kept alive until the operation completes.
0732      */
0733     template <
0734         class SpanElementType,
0735         class... StaticRow,
0736         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, std::size_t))
0737             CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0738     BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, std::size_t))
0739     async_read_some_rows(
0740         static_execution_state<StaticRow...>& st,
0741         span<SpanElementType> output,
0742         CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
0743     )
0744     {
0745         return async_read_some_rows(st, output, impl_.shared_diag(), std::forward<CompletionToken>(token));
0746     }
0747 
0748     /**
0749      * \brief Reads a batch of rows.
0750      * \details
0751      * Reads a batch of rows of unspecified size into the storage given by `output`.
0752      * At most `output.size()` rows will be read. If the operation represented by `st`
0753      * has still rows to read, and `output.size() > 0`, at least one row will be read.
0754      * \n
0755      * Returns the number of read rows.
0756      * \n
0757      * If there are no more rows, or `st.should_read_rows() == false`, this function is a no-op and returns
0758      * zero.
0759      * \n
0760      * The number of rows that will be read depends on the connection's buffer size. The bigger the buffer,
0761      * the greater the batch size (up to a maximum). You can set the initial buffer size in `connection`'s
0762      * constructor, using \ref buffer_params::initial_read_size. The buffer may be
0763      * grown bigger by other read operations, if required.
0764      * \n
0765      * Rows read by this function are owning objects, and don't hold any reference to
0766      * the connection's internal buffers (contrary what happens with the dynamic interface's counterpart).
0767      * \n
0768      * The type `SpanElementType` must be the underlying row type for one of the types in the
0769      * `StaticRow` parameter pack (i.e., one of the types in `underlying_row_t<StaticRow>...`).
0770      * The type must match the resultset that is currently being processed by `st`. For instance,
0771      * given `static_execution_state<T1, T2>`, when reading rows for the second resultset, `SpanElementType`
0772      * must exactly be `underlying_row_t<T2>`. If this is not the case, a runtime error will be issued.
0773      * \n
0774      * This function can report schema mismatches.
0775      *
0776      * \par Handler signature
0777      * The handler signature for this operation is
0778      * `void(boost::mysql::error_code, std::size_t)`.
0779      *
0780      * \par Executor
0781      * Intermediate completion handlers, as well as the final handler, are executed using
0782      * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
0783      * executor.
0784      *
0785      * If the final handler has an associated immediate executor, and the operation
0786      * completes immediately, the final handler is dispatched to it.
0787      * Otherwise, the final handler is called as if it was submitted using `asio::post`,
0788      * and is never be called inline from within this function.
0789      *
0790      * \par Object lifetimes
0791      * The storage that `output` references must be kept alive until the operation completes.
0792      */
0793     template <
0794         class SpanElementType,
0795         class... StaticRow,
0796         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, std::size_t))
0797             CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0798     BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, std::size_t))
0799     async_read_some_rows(
0800         static_execution_state<StaticRow...>& st,
0801         span<SpanElementType> output,
0802         diagnostics& diag,
0803         CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
0804     )
0805     {
0806         return impl_.async_run(
0807             impl_.make_params_read_some_rows_static(st, output),
0808             diag,
0809             std::forward<CompletionToken>(token)
0810         );
0811     }
0812 #endif
0813 
0814     /// \copydoc any_connection::read_resultset_head
0815     template <BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType>
0816     void read_resultset_head(ExecutionStateType& st, error_code& err, diagnostics& diag)
0817     {
0818         return impl_.run(impl_.make_params_read_resultset_head(st), err, diag);
0819     }
0820 
0821     /// \copydoc read_resultset_head
0822     template <BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType>
0823     void read_resultset_head(ExecutionStateType& st)
0824     {
0825         error_code err;
0826         diagnostics diag;
0827         read_resultset_head(st, err, diag);
0828         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
0829     }
0830 
0831     /// \copydoc any_connection::async_read_resultset_head
0832     template <
0833         BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType,
0834         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
0835             CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0836     auto async_read_resultset_head(
0837         ExecutionStateType& st,
0838         CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
0839     ) BOOST_MYSQL_RETURN_TYPE(detail::async_read_resultset_head_t<CompletionToken&&>)
0840     {
0841         return async_read_resultset_head(st, impl_.shared_diag(), std::forward<CompletionToken>(token));
0842     }
0843 
0844     /// \copydoc async_read_resultset_head
0845     template <
0846         BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType,
0847         BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
0848             CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0849     auto async_read_resultset_head(
0850         ExecutionStateType& st,
0851         diagnostics& diag,
0852         CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
0853     ) BOOST_MYSQL_RETURN_TYPE(detail::async_read_resultset_head_t<CompletionToken&&>)
0854     {
0855         return impl_
0856             .async_run(impl_.make_params_read_resultset_head(st), diag, std::forward<CompletionToken>(token));
0857     }
0858 
0859     /// \copydoc any_connection::ping
0860     void ping(error_code& err, diagnostics& diag) { impl_.run(detail::ping_algo_params{}, err, diag); }
0861 
0862     /// \copydoc ping
0863     void ping()
0864     {
0865         error_code err;
0866         diagnostics diag;
0867         ping(err, diag);
0868         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
0869     }
0870 
0871     /// \copydoc any_connection::async_ping
0872     template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
0873                   CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0874     auto async_ping(CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
0875         BOOST_MYSQL_RETURN_TYPE(detail::async_ping_t<CompletionToken&&>)
0876     {
0877         return async_ping(impl_.shared_diag(), std::forward<CompletionToken>(token));
0878     }
0879 
0880     /// \copydoc async_ping
0881     template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
0882                   CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0883     auto async_ping(
0884         diagnostics& diag,
0885         CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
0886     ) BOOST_MYSQL_RETURN_TYPE(detail::async_ping_t<CompletionToken&&>)
0887     {
0888         return impl_.async_run(detail::ping_algo_params{}, diag, std::forward<CompletionToken>(token));
0889     }
0890 
0891     /**
0892      * \brief Resets server-side session state, like variables and prepared statements.
0893      * \details
0894      * Resets all server-side state for the current session:
0895      * \n
0896      *   \li Rolls back any active transactions and resets autocommit mode.
0897      *   \li Releases all table locks.
0898      *   \li Drops all temporary tables.
0899      *   \li Resets all session system variables to their default values (including the ones set by `SET
0900      *       NAMES`) and clears all user-defined variables.
0901      *   \li Closes all prepared statements.
0902      * \n
0903      * A full reference on the affected session state can be found
0904      * <a href="https://dev.mysql.com/doc/c-api/8.0/en/mysql-reset-connection.html">here</a>.
0905      * \n
0906      * This function will not reset the current physical connection and won't cause re-authentication.
0907      * It is faster than closing and re-opening a connection.
0908      * \n
0909      * The connection must be connected and authenticated before calling this function.
0910      * This function involves communication with the server, and thus may fail.
0911      *
0912      * \par Warning on character sets
0913      * This function will restore the connection's character set and collation **to the server's default**,
0914      * and not to the one specified during connection establishment. Some servers have `latin1` as their
0915      * default character set, which is not usually what you want. Use a `SET NAMES` statement after using
0916      * this function to be sure.
0917      * \n
0918      * You can find the character set that your server will use after reset by running:
0919      * \code
0920      * "SELECT @@global.character_set_client, @@global.character_set_results;"
0921      * \endcode
0922      */
0923     void reset_connection(error_code& err, diagnostics& diag)
0924     {
0925         impl_.run(detail::reset_connection_algo_params{}, err, diag);
0926     }
0927 
0928     /// \copydoc reset_connection
0929     void reset_connection()
0930     {
0931         error_code err;
0932         diagnostics diag;
0933         reset_connection(err, diag);
0934         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
0935     }
0936 
0937     /**
0938      * \copydoc reset_connection
0939      * \details
0940      * \n
0941      * \par Handler signature
0942      * The handler signature for this operation is `void(boost::mysql::error_code)`.
0943      *
0944      * \par Executor
0945      * Intermediate completion handlers, as well as the final handler, are executed using
0946      * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
0947      * executor.
0948      *
0949      * If the final handler has an associated immediate executor, and the operation
0950      * completes immediately, the final handler is dispatched to it.
0951      * Otherwise, the final handler is called as if it was submitted using `asio::post`,
0952      * and is never be called inline from within this function.
0953      */
0954     template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
0955                   CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0956     auto async_reset_connection(CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
0957         BOOST_MYSQL_RETURN_TYPE(detail::async_reset_connection_t<CompletionToken&&>)
0958     {
0959         return async_reset_connection(impl_.shared_diag(), std::forward<CompletionToken>(token));
0960     }
0961 
0962     /// \copydoc async_reset_connection
0963     template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
0964                   CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0965     auto async_reset_connection(
0966         diagnostics& diag,
0967         CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
0968     ) BOOST_MYSQL_RETURN_TYPE(detail::async_reset_connection_t<CompletionToken&&>)
0969     {
0970         return impl_
0971             .async_run(detail::reset_connection_algo_params{}, diag, std::forward<CompletionToken>(token));
0972     }
0973 
0974     /**
0975      * \brief Closes the connection to the server.
0976      * \details
0977      * This function is only available if `Stream` satisfies the `SocketStream` concept.
0978      * \n
0979      * Sends a quit request, performs the TLS shutdown (if required)
0980      * and closes the underlying stream. Prefer this function to \ref connection::quit.
0981      * \n
0982      */
0983     void close(error_code& err, diagnostics& diag)
0984     {
0985         static_assert(
0986             detail::is_socket_stream<Stream>::value,
0987             "close can only be used if Stream satisfies the SocketStream concept"
0988         );
0989         impl_.run(detail::close_connection_algo_params{}, err, diag);
0990     }
0991 
0992     /// \copydoc close
0993     void close()
0994     {
0995         static_assert(
0996             detail::is_socket_stream<Stream>::value,
0997             "close can only be used if Stream satisfies the SocketStream concept"
0998         );
0999         error_code err;
1000         diagnostics diag;
1001         close(err, diag);
1002         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
1003     }
1004 
1005     /**
1006      * \copydoc close
1007      * \details
1008      * \par Handler signature
1009      * The handler signature for this operation is `void(boost::mysql::error_code)`.
1010      *
1011      * \par Executor
1012      * Intermediate completion handlers, as well as the final handler, are executed using
1013      * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
1014      * executor.
1015      *
1016      * If the final handler has an associated immediate executor, and the operation
1017      * completes immediately, the final handler is dispatched to it.
1018      * Otherwise, the final handler is called as if it was submitted using `asio::post`,
1019      * and is never be called inline from within this function.
1020      */
1021     template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
1022                   CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
1023     auto async_close(CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
1024         BOOST_MYSQL_RETURN_TYPE(detail::async_close_connection_t<CompletionToken&&>)
1025     {
1026         static_assert(
1027             detail::is_socket_stream<Stream>::value,
1028             "async_close can only be used if Stream satisfies the SocketStream concept"
1029         );
1030         return async_close(impl_.shared_diag(), std::forward<CompletionToken>(token));
1031     }
1032 
1033     /// \copydoc async_close
1034     template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
1035                   CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
1036     auto async_close(
1037         diagnostics& diag,
1038         CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
1039     ) BOOST_MYSQL_RETURN_TYPE(detail::async_close_connection_t<CompletionToken&&>)
1040     {
1041         static_assert(
1042             detail::is_socket_stream<Stream>::value,
1043             "async_close can only be used if Stream satisfies the SocketStream concept"
1044         );
1045         return impl_
1046             .async_run(detail::close_connection_algo_params{}, diag, std::forward<CompletionToken>(token));
1047     }
1048 
1049     /**
1050      * \brief Notifies the MySQL server that the client wants to end the session and shutdowns SSL.
1051      * \details Sends a quit request to the MySQL server. If the connection is using SSL,
1052      * this function will also perform the SSL shutdown. You should
1053      * close the underlying physical connection after calling this function.
1054      * \n
1055      * If the `Stream` template parameter fulfills the `SocketConnection`
1056      * requirements, use \ref connection::close instead of this function,
1057      * as it also takes care of closing the underlying stream.
1058      */
1059     void quit(error_code& err, diagnostics& diag)
1060     {
1061         impl_.run(detail::quit_connection_algo_params{}, err, diag);
1062     }
1063 
1064     /// \copydoc quit
1065     void quit()
1066     {
1067         error_code err;
1068         diagnostics diag;
1069         quit(err, diag);
1070         detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
1071     }
1072 
1073     /**
1074      * \copydoc quit
1075      * \details
1076      * \par Handler signature
1077      * The handler signature for this operation is `void(boost::mysql::error_code)`.
1078      *
1079      * \par Executor
1080      * Intermediate completion handlers, as well as the final handler, are executed using
1081      * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
1082      * executor.
1083      *
1084      * If the final handler has an associated immediate executor, and the operation
1085      * completes immediately, the final handler is dispatched to it.
1086      * Otherwise, the final handler is called as if it was submitted using `asio::post`,
1087      * and is never be called inline from within this function.
1088      */
1089     template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
1090                   CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
1091     auto async_quit(CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
1092         BOOST_MYSQL_RETURN_TYPE(detail::async_quit_connection_t<CompletionToken&&>)
1093     {
1094         return async_quit(impl_.shared_diag(), std::forward<CompletionToken>(token));
1095     }
1096 
1097     /// \copydoc async_quit
1098     template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
1099                   CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
1100     auto async_quit(
1101         diagnostics& diag,
1102         CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
1103     ) BOOST_MYSQL_RETURN_TYPE(detail::async_quit_connection_t<CompletionToken&&>)
1104     {
1105         return impl_
1106             .async_run(detail::quit_connection_algo_params{}, diag, std::forward<CompletionToken>(token));
1107     }
1108 
1109     /**
1110      * \brief Rebinds the connection type to another executor.
1111      * \details
1112      * The `Stream` type must either provide a `rebind_executor`
1113      * member with the same semantics, or be an instantiation of `boost::asio::ssl::stream` with
1114      * a `Stream` type providing a `rebind_executor` member.
1115      */
1116     template <typename Executor1>
1117     struct rebind_executor
1118     {
1119         /// The connection type when rebound to the specified executor.
1120         using other = connection<typename detail::rebind_executor<Stream, Executor1>::type>;
1121     };
1122 };
1123 
1124 }  // namespace mysql
1125 }  // namespace boost
1126 
1127 #endif