Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-09 08:28:00

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