Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-18 08:52:50

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_DETAIL_CONNECTION_IMPL_HPP
0009 #define BOOST_MYSQL_DETAIL_CONNECTION_IMPL_HPP
0010 
0011 #include <boost/mysql/any_address.hpp>
0012 #include <boost/mysql/connect_params.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/field_view.hpp>
0017 #include <boost/mysql/handshake_params.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 
0023 #include <boost/mysql/detail/access.hpp>
0024 #include <boost/mysql/detail/algo_params.hpp>
0025 #include <boost/mysql/detail/config.hpp>
0026 #include <boost/mysql/detail/connect_params_helpers.hpp>
0027 #include <boost/mysql/detail/engine.hpp>
0028 #include <boost/mysql/detail/execution_processor/execution_processor.hpp>
0029 #include <boost/mysql/detail/initiation_base.hpp>
0030 #include <boost/mysql/detail/intermediate_handler.hpp>
0031 
0032 #include <boost/asio/any_io_executor.hpp>
0033 #include <boost/optional/optional.hpp>
0034 #include <boost/system/result.hpp>
0035 
0036 #include <cstddef>
0037 #include <cstdint>
0038 #include <cstring>
0039 #include <memory>
0040 #include <type_traits>
0041 #include <utility>
0042 #include <vector>
0043 
0044 namespace boost {
0045 namespace mysql {
0046 
0047 // Forward decl
0048 template <class... StaticRow>
0049 class static_execution_state;
0050 
0051 struct character_set;
0052 class pipeline_request;
0053 
0054 namespace detail {
0055 
0056 //
0057 // Helpers to interact with connection_state, without including its definition
0058 //
0059 class connection_state;
0060 
0061 struct connection_state_deleter
0062 {
0063     BOOST_MYSQL_DECL void operator()(connection_state*) const;
0064 };
0065 
0066 BOOST_MYSQL_DECL std::vector<field_view>& get_shared_fields(connection_state&);
0067 
0068 template <class AlgoParams>
0069 any_resumable_ref setup(connection_state&, diagnostics&, const AlgoParams&);
0070 
0071 // Note: AlgoParams should have !is_void_result
0072 template <class AlgoParams>
0073 typename AlgoParams::result_type get_result(const connection_state&);
0074 
0075 //
0076 // helpers to run algos
0077 //
0078 template <class AlgoParams>
0079 using has_void_result = std::is_same<typename AlgoParams::result_type, void>;
0080 
0081 template <class AlgoParams, bool is_void>
0082 struct completion_signature_impl;
0083 
0084 template <class AlgoParams>
0085 struct completion_signature_impl<AlgoParams, true>
0086 {
0087     // Using typedef to workaround a msvc 14.1 bug
0088     typedef void(type)(error_code);
0089 };
0090 
0091 template <class AlgoParams>
0092 struct completion_signature_impl<AlgoParams, false>
0093 {
0094     // Using typedef to workaround a msvc 14.1 bug
0095     typedef void(type)(error_code, typename AlgoParams::result_type);
0096 };
0097 
0098 template <class AlgoParams>
0099 using completion_signature_t = typename completion_signature_impl<
0100     AlgoParams,
0101     has_void_result<AlgoParams>::value>::type;
0102 
0103 // Intermediate handler
0104 template <class AlgoParams>
0105 struct generic_algo_fn
0106 {
0107     static_assert(!has_void_result<AlgoParams>::value, "Internal error: result_type should be non-void");
0108 
0109     using result_t = typename AlgoParams::result_type;
0110 
0111     template <class Handler>
0112     void operator()(Handler&& handler, error_code ec)
0113     {
0114         std::move(handler)(ec, ec ? result_t{} : get_result<AlgoParams>(*st));
0115     }
0116 
0117     connection_state* st;
0118 };
0119 
0120 // Note: the 1st async_initiate arg should be a diagnostics*,
0121 // so completion tokens knowing how Boost.MySQL work can operate
0122 class connection_impl
0123 {
0124     std::unique_ptr<engine> engine_;
0125     std::unique_ptr<connection_state, connection_state_deleter> st_;
0126 
0127     asio::any_io_executor get_executor() const { return engine_->get_executor(); }
0128 
0129     // Helper for execution requests
0130     template <class T>
0131     static auto make_request(T&& input, connection_state& st)
0132         -> decltype(execution_request_traits<typename std::decay<T>::type>::make_request(
0133             std::forward<T>(input),
0134             get_shared_fields(st)
0135         ))
0136     {
0137         return execution_request_traits<typename std::decay<T>::type>::make_request(
0138             std::forward<T>(input),
0139             get_shared_fields(st)
0140         );
0141     }
0142 
0143     // Generic algorithm
0144     template <class AlgoParams>
0145     typename AlgoParams::result_type run_impl(
0146         AlgoParams params,
0147         error_code& ec,
0148         diagnostics& diag,
0149         std::true_type /* has_void_result */
0150     )
0151     {
0152         engine_->run(setup(*st_, diag, params), ec);
0153     }
0154 
0155     template <class AlgoParams>
0156     typename AlgoParams::result_type run_impl(
0157         AlgoParams params,
0158         error_code& ec,
0159         diagnostics& diag,
0160         std::false_type /* has_void_result */
0161     )
0162     {
0163         engine_->run(setup(*st_, diag, params), ec);
0164         return get_result<AlgoParams>(*st_);
0165     }
0166 
0167     template <class AlgoParams, class Handler>
0168     static void async_run_impl(
0169         engine& eng,
0170         connection_state& st,
0171         AlgoParams params,
0172         diagnostics& diag,
0173         Handler&& handler,
0174         std::true_type /* has_void_result */
0175     )
0176     {
0177         eng.async_run(setup(st, diag, params), std::forward<Handler>(handler));
0178     }
0179 
0180     template <class AlgoParams, class Handler>
0181     static void async_run_impl(
0182         engine& eng,
0183         connection_state& st,
0184         AlgoParams params,
0185         diagnostics& diag,
0186         Handler&& handler,
0187         std::false_type /* has_void_result */
0188     )
0189     {
0190         eng.async_run(
0191             setup(st, diag, params),
0192             make_intermediate_handler(generic_algo_fn<AlgoParams>{&st}, std::forward<Handler>(handler))
0193         );
0194     }
0195 
0196     template <class AlgoParams, class Handler>
0197     static void async_run_impl(
0198         engine& eng,
0199         connection_state& st,
0200         AlgoParams params,
0201         diagnostics& diag,
0202         Handler&& handler
0203     )
0204     {
0205         async_run_impl(eng, st, params, diag, std::forward<Handler>(handler), has_void_result<AlgoParams>{});
0206     }
0207 
0208     struct run_algo_initiation : initiation_base
0209     {
0210         using initiation_base::initiation_base;
0211 
0212         template <class Handler, class AlgoParams>
0213         void operator()(
0214             Handler&& handler,
0215             diagnostics* diag,
0216             engine* eng,
0217             connection_state* st,
0218             AlgoParams params
0219         )
0220         {
0221             async_run_impl(*eng, *st, params, *diag, std::forward<Handler>(handler));
0222         }
0223     };
0224 
0225     // Connect
0226     static connect_algo_params make_params_connect(const void* server_address, const handshake_params& params)
0227     {
0228         return connect_algo_params{server_address, params, false};
0229     }
0230 
0231     static connect_algo_params make_params_connect_v2(const connect_params& params)
0232     {
0233         return connect_algo_params{
0234             &params.server_address,
0235             make_hparams(params),
0236             params.server_address.type() == address_type::unix_path
0237         };
0238     }
0239 
0240     template <class EndpointType>
0241     struct initiate_connect : initiation_base
0242     {
0243         using initiation_base::initiation_base;
0244 
0245         template <class Handler>
0246         void operator()(
0247             Handler&& handler,
0248             diagnostics* diag,
0249             engine* eng,
0250             connection_state* st,
0251             const EndpointType& endpoint,
0252             handshake_params params
0253         )
0254         {
0255             async_run_impl(
0256                 *eng,
0257                 *st,
0258                 make_params_connect(&endpoint, params),
0259                 *diag,
0260                 std::forward<Handler>(handler)
0261             );
0262         }
0263     };
0264 
0265     struct initiate_connect_v2 : initiation_base
0266     {
0267         using initiation_base::initiation_base;
0268 
0269         template <class Handler>
0270         void operator()(
0271             Handler&& handler,
0272             diagnostics* diag,
0273             engine* eng,
0274             connection_state* st,
0275             const connect_params* params
0276         )
0277         {
0278             async_run_impl(*eng, *st, make_params_connect_v2(*params), *diag, std::forward<Handler>(handler));
0279         }
0280     };
0281 
0282     // execute
0283     struct initiate_execute : initiation_base
0284     {
0285         using initiation_base::initiation_base;
0286 
0287         template <class Handler, class ExecutionRequest>
0288         void operator()(
0289             Handler&& handler,
0290             diagnostics* diag,
0291             engine* eng,
0292             connection_state* st,
0293             ExecutionRequest&& req,
0294             execution_processor* proc
0295         )
0296         {
0297             async_run_impl(
0298                 *eng,
0299                 *st,
0300                 execute_algo_params{make_request(std::forward<ExecutionRequest>(req), *st), proc},
0301                 *diag,
0302                 std::forward<Handler>(handler)
0303             );
0304         }
0305     };
0306 
0307     // start execution
0308     struct initiate_start_execution : initiation_base
0309     {
0310         using initiation_base::initiation_base;
0311 
0312         template <class Handler, class ExecutionRequest>
0313         void operator()(
0314             Handler&& handler,
0315             diagnostics* diag,
0316             engine* eng,
0317             connection_state* st,
0318             ExecutionRequest&& req,
0319             execution_processor* proc
0320         )
0321         {
0322             async_run_impl(
0323                 *eng,
0324                 *st,
0325                 start_execution_algo_params{make_request(std::forward<ExecutionRequest>(req), *st), proc},
0326                 *diag,
0327                 std::forward<Handler>(handler)
0328             );
0329         }
0330     };
0331 
0332 public:
0333     BOOST_MYSQL_DECL connection_impl(
0334         std::size_t read_buff_size,
0335         std::size_t max_buffer_size,
0336         std::unique_ptr<engine> eng
0337     );
0338 
0339     BOOST_MYSQL_DECL metadata_mode meta_mode() const;
0340     BOOST_MYSQL_DECL void set_meta_mode(metadata_mode m);
0341     BOOST_MYSQL_DECL bool ssl_active() const;
0342     BOOST_MYSQL_DECL bool backslash_escapes() const;
0343     BOOST_MYSQL_DECL system::result<character_set> current_character_set() const;
0344     BOOST_MYSQL_DECL boost::optional<std::uint32_t> connection_id() const;
0345     BOOST_MYSQL_DECL diagnostics& shared_diag();
0346 
0347     engine& get_engine()
0348     {
0349         BOOST_ASSERT(engine_);
0350         return *engine_;
0351     }
0352 
0353     const engine& get_engine() const
0354     {
0355         BOOST_ASSERT(engine_);
0356         return *engine_;
0357     }
0358 
0359     // Generic algorithm
0360     template <class AlgoParams>
0361     typename AlgoParams::result_type run(AlgoParams params, error_code& ec, diagnostics& diag)
0362     {
0363         return run_impl(params, ec, diag, has_void_result<AlgoParams>{});
0364     }
0365 
0366     template <class AlgoParams, class CompletionToken>
0367     auto async_run(AlgoParams params, diagnostics& diag, CompletionToken&& token)
0368         -> decltype(asio::async_initiate<CompletionToken, completion_signature_t<AlgoParams>>(
0369             run_algo_initiation(get_executor()),
0370             token,
0371             &diag,
0372             engine_.get(),
0373             st_.get(),
0374             params
0375         ))
0376     {
0377         return asio::async_initiate<CompletionToken, completion_signature_t<AlgoParams>>(
0378             run_algo_initiation(get_executor()),
0379             token,
0380             &diag,
0381             engine_.get(),
0382             st_.get(),
0383             params
0384         );
0385     }
0386 
0387     // Connect
0388     template <class EndpointType>
0389     void connect(
0390         const EndpointType& endpoint,
0391         const handshake_params& params,
0392         error_code& err,
0393         diagnostics& diag
0394     )
0395     {
0396         run(make_params_connect(&endpoint, params), err, diag);
0397     }
0398 
0399     void connect_v2(const connect_params& params, error_code& err, diagnostics& diag)
0400     {
0401         run(make_params_connect_v2(params), err, diag);
0402     }
0403 
0404     template <class EndpointType, class CompletionToken>
0405     auto async_connect(
0406         const EndpointType& endpoint,
0407         const handshake_params& params,
0408         diagnostics& diag,
0409         CompletionToken&& token
0410     )
0411         -> decltype(asio::async_initiate<CompletionToken, void(error_code)>(
0412             initiate_connect<EndpointType>(get_executor()),
0413             token,
0414             &diag,
0415             engine_.get(),
0416             st_.get(),
0417             endpoint,
0418             params
0419         ))
0420     {
0421         return asio::async_initiate<CompletionToken, void(error_code)>(
0422             initiate_connect<EndpointType>(get_executor()),
0423             token,
0424             &diag,
0425             engine_.get(),
0426             st_.get(),
0427             endpoint,
0428             params
0429         );
0430     }
0431 
0432     template <class CompletionToken>
0433     auto async_connect_v2(const connect_params& params, diagnostics& diag, CompletionToken&& token)
0434         -> decltype(asio::async_initiate<CompletionToken, void(error_code)>(
0435             initiate_connect_v2(get_executor()),
0436             token,
0437             &diag,
0438             engine_.get(),
0439             st_.get(),
0440             &params
0441         ))
0442     {
0443         return asio::async_initiate<CompletionToken, void(error_code)>(
0444             initiate_connect_v2(get_executor()),
0445             token,
0446             &diag,
0447             engine_.get(),
0448             st_.get(),
0449             &params
0450         );
0451     }
0452 
0453     // Handshake
0454     handshake_algo_params make_params_handshake(const handshake_params& params) const
0455     {
0456         return {params, false};
0457     }
0458 
0459     // Execute
0460     template <class ExecutionRequest, class ResultsType>
0461     void execute(ExecutionRequest&& req, ResultsType& result, error_code& err, diagnostics& diag)
0462     {
0463         run(
0464             execute_algo_params{
0465                 make_request(std::forward<ExecutionRequest>(req), *st_),
0466                 &access::get_impl(result).get_interface()
0467             },
0468             err,
0469             diag
0470         );
0471     }
0472 
0473     template <class ExecutionRequest, class ResultsType, class CompletionToken>
0474     auto async_execute(
0475         ExecutionRequest&& req,
0476         ResultsType& result,
0477         diagnostics& diag,
0478         CompletionToken&& token
0479     )
0480         -> decltype(asio::async_initiate<CompletionToken, void(error_code)>(
0481             initiate_execute(get_executor()),
0482             token,
0483             &diag,
0484             engine_.get(),
0485             st_.get(),
0486             std::forward<ExecutionRequest>(req),
0487             &access::get_impl(result).get_interface()
0488         ))
0489     {
0490         return asio::async_initiate<CompletionToken, void(error_code)>(
0491             initiate_execute(get_executor()),
0492             token,
0493             &diag,
0494             engine_.get(),
0495             st_.get(),
0496             std::forward<ExecutionRequest>(req),
0497             &access::get_impl(result).get_interface()
0498         );
0499     }
0500 
0501     // Start execution
0502     template <class ExecutionRequest, class ExecutionStateType>
0503     void start_execution(
0504         ExecutionRequest&& req,
0505         ExecutionStateType& exec_st,
0506         error_code& err,
0507         diagnostics& diag
0508     )
0509     {
0510         run(
0511             start_execution_algo_params{
0512                 make_request(std::forward<ExecutionRequest>(req), *st_),
0513                 &access::get_impl(exec_st).get_interface()
0514             },
0515             err,
0516             diag
0517         );
0518     }
0519 
0520     template <class ExecutionRequest, class ExecutionStateType, class CompletionToken>
0521     auto async_start_execution(
0522         ExecutionRequest&& req,
0523         ExecutionStateType& exec_st,
0524         diagnostics& diag,
0525         CompletionToken&& token
0526     )
0527         -> decltype(asio::async_initiate<CompletionToken, void(error_code)>(
0528             initiate_start_execution(get_executor()),
0529             token,
0530             &diag,
0531             engine_.get(),
0532             st_.get(),
0533             std::forward<ExecutionRequest>(req),
0534             &access::get_impl(exec_st).get_interface()
0535         ))
0536     {
0537         return asio::async_initiate<CompletionToken, void(error_code)>(
0538             initiate_start_execution(get_executor()),
0539             token,
0540             &diag,
0541             engine_.get(),
0542             st_.get(),
0543             std::forward<ExecutionRequest>(req),
0544             &access::get_impl(exec_st).get_interface()
0545         );
0546     }
0547 
0548     // Read some rows (dynamic)
0549     read_some_rows_dynamic_algo_params make_params_read_some_rows(execution_state& st) const
0550     {
0551         return {&access::get_impl(st).get_interface()};
0552     }
0553 
0554     // Read some rows (static)
0555     template <class SpanElementType, class ExecutionState>
0556     read_some_rows_algo_params make_params_read_some_rows_static(
0557         ExecutionState& exec_st,
0558         span<SpanElementType> output
0559     ) const
0560     {
0561         return {
0562             &access::get_impl(exec_st).get_interface(),
0563             access::get_impl(exec_st).make_output_ref(output)
0564         };
0565     }
0566 
0567     // Read resultset head
0568     template <class ExecutionStateType>
0569     read_resultset_head_algo_params make_params_read_resultset_head(ExecutionStateType& st) const
0570     {
0571         return {&detail::access::get_impl(st).get_interface()};
0572     }
0573 
0574     // Close statement
0575     close_statement_algo_params make_params_close_statement(statement stmt) const { return {stmt.id()}; }
0576 
0577     // Run pipeline. Separately compiled to avoid including the pipeline header here
0578     BOOST_MYSQL_DECL
0579     static run_pipeline_algo_params make_params_pipeline(
0580         const pipeline_request& req,
0581         std::vector<stage_response>& response
0582     );
0583 
0584     // Exposed for testing
0585     connection_state& get_state() { return *st_; }
0586 };
0587 
0588 // To use some completion tokens, like deferred, in C++11, the old macros
0589 // BOOST_ASIO_INITFN_AUTO_RESULT_TYPE are no longer enough.
0590 // Helper typedefs to reduce duplication
0591 template <class AlgoParams, class CompletionToken>
0592 using async_run_t = decltype(std::declval<connection_impl&>().async_run(
0593     std::declval<AlgoParams>(),
0594     std::declval<diagnostics&>(),
0595     std::declval<CompletionToken>()
0596 ));
0597 
0598 template <class EndpointType, class CompletionToken>
0599 using async_connect_t = decltype(std::declval<connection_impl&>().async_connect(
0600     std::declval<const EndpointType&>(),
0601     std::declval<const handshake_params&>(),
0602     std::declval<diagnostics&>(),
0603     std::declval<CompletionToken>()
0604 ));
0605 
0606 template <class CompletionToken>
0607 using async_connect_v2_t = decltype(std::declval<connection_impl&>().async_connect_v2(
0608     std::declval<const connect_params&>(),
0609     std::declval<diagnostics&>(),
0610     std::declval<CompletionToken>()
0611 ));
0612 
0613 template <class ExecutionRequest, class ResultsType, class CompletionToken>
0614 using async_execute_t = decltype(std::declval<connection_impl&>().async_execute(
0615     std::declval<ExecutionRequest>(),
0616     std::declval<ResultsType&>(),
0617     std::declval<diagnostics&>(),
0618     std::declval<CompletionToken>()
0619 ));
0620 
0621 template <class ExecutionRequest, class ExecutionStateType, class CompletionToken>
0622 using async_start_execution_t = decltype(std::declval<connection_impl&>().async_start_execution(
0623     std::declval<ExecutionRequest>(),
0624     std::declval<ExecutionStateType&>(),
0625     std::declval<diagnostics&>(),
0626     std::declval<CompletionToken>()
0627 ));
0628 
0629 template <class CompletionToken>
0630 using async_handshake_t = async_run_t<handshake_algo_params, CompletionToken>;
0631 
0632 template <class CompletionToken>
0633 using async_read_resultset_head_t = async_run_t<read_resultset_head_algo_params, CompletionToken>;
0634 
0635 template <class CompletionToken>
0636 using async_read_some_rows_dynamic_t = async_run_t<read_some_rows_dynamic_algo_params, CompletionToken>;
0637 
0638 template <class CompletionToken>
0639 using async_prepare_statement_t = async_run_t<prepare_statement_algo_params, CompletionToken>;
0640 
0641 template <class CompletionToken>
0642 using async_close_statement_t = async_run_t<close_statement_algo_params, CompletionToken>;
0643 
0644 template <class CompletionToken>
0645 using async_set_character_set_t = async_run_t<set_character_set_algo_params, CompletionToken>;
0646 
0647 template <class CompletionToken>
0648 using async_ping_t = async_run_t<ping_algo_params, CompletionToken>;
0649 
0650 template <class CompletionToken>
0651 using async_reset_connection_t = async_run_t<reset_connection_algo_params, CompletionToken>;
0652 
0653 template <class CompletionToken>
0654 using async_quit_connection_t = async_run_t<quit_connection_algo_params, CompletionToken>;
0655 
0656 template <class CompletionToken>
0657 using async_close_connection_t = async_run_t<close_connection_algo_params, CompletionToken>;
0658 
0659 template <class CompletionToken>
0660 using async_run_pipeline_t = async_run_t<run_pipeline_algo_params, CompletionToken>;
0661 
0662 }  // namespace detail
0663 }  // namespace mysql
0664 }  // namespace boost
0665 
0666 #ifdef BOOST_MYSQL_HEADER_ONLY
0667 #include <boost/mysql/impl/connection_impl.ipp>
0668 #endif
0669 
0670 #endif