connection_impl.hpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. //
  2. // Copyright (c) 2019-2024 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. #ifndef BOOST_MYSQL_DETAIL_CONNECTION_IMPL_HPP
  8. #define BOOST_MYSQL_DETAIL_CONNECTION_IMPL_HPP
  9. #include <boost/mysql/any_address.hpp>
  10. #include <boost/mysql/connect_params.hpp>
  11. #include <boost/mysql/diagnostics.hpp>
  12. #include <boost/mysql/error_code.hpp>
  13. #include <boost/mysql/execution_state.hpp>
  14. #include <boost/mysql/field_view.hpp>
  15. #include <boost/mysql/handshake_params.hpp>
  16. #include <boost/mysql/metadata_mode.hpp>
  17. #include <boost/mysql/rows_view.hpp>
  18. #include <boost/mysql/statement.hpp>
  19. #include <boost/mysql/string_view.hpp>
  20. #include <boost/mysql/detail/access.hpp>
  21. #include <boost/mysql/detail/algo_params.hpp>
  22. #include <boost/mysql/detail/any_execution_request.hpp>
  23. #include <boost/mysql/detail/config.hpp>
  24. #include <boost/mysql/detail/connect_params_helpers.hpp>
  25. #include <boost/mysql/detail/engine.hpp>
  26. #include <boost/mysql/detail/execution_processor/execution_processor.hpp>
  27. #include <boost/mysql/detail/writable_field_traits.hpp>
  28. #include <boost/core/ignore_unused.hpp>
  29. #include <boost/mp11/integer_sequence.hpp>
  30. #include <boost/system/result.hpp>
  31. #include <array>
  32. #include <cstddef>
  33. #include <cstring>
  34. #include <memory>
  35. #include <tuple>
  36. #include <utility>
  37. namespace boost {
  38. namespace mysql {
  39. // Forward decl
  40. template <class... StaticRow>
  41. class static_execution_state;
  42. struct character_set;
  43. class pipeline_request;
  44. namespace detail {
  45. // Forward decl
  46. class connection_state;
  47. //
  48. // Helpers to interact with connection_state, without including its definition
  49. //
  50. struct connection_state_deleter
  51. {
  52. BOOST_MYSQL_DECL void operator()(connection_state*) const;
  53. };
  54. BOOST_MYSQL_DECL std::vector<field_view>& get_shared_fields(connection_state&);
  55. template <class AlgoParams>
  56. any_resumable_ref setup(connection_state&, const AlgoParams&);
  57. // Note: AlgoParams should have !is_void_result
  58. template <class AlgoParams>
  59. typename AlgoParams::result_type get_result(const connection_state&);
  60. //
  61. // execution helpers
  62. //
  63. template <class... T, std::size_t... I>
  64. std::array<field_view, sizeof...(T)> tuple_to_array_impl(const std::tuple<T...>& t, mp11::index_sequence<I...>) noexcept
  65. {
  66. boost::ignore_unused(t); // MSVC gets confused if sizeof...(T) == 0
  67. return std::array<field_view, sizeof...(T)>{{to_field(std::get<I>(t))...}};
  68. }
  69. template <class... T>
  70. std::array<field_view, sizeof...(T)> tuple_to_array(const std::tuple<T...>& t) noexcept
  71. {
  72. return tuple_to_array_impl(t, mp11::make_index_sequence<sizeof...(T)>());
  73. }
  74. struct query_request_getter
  75. {
  76. any_execution_request value;
  77. any_execution_request get() const noexcept { return value; }
  78. };
  79. inline query_request_getter make_request_getter(string_view q, std::vector<field_view>&) noexcept
  80. {
  81. return query_request_getter{q};
  82. }
  83. struct stmt_it_request_getter
  84. {
  85. statement stmt;
  86. span<const field_view> params; // Points into the connection state's shared fields
  87. any_execution_request get() const noexcept { return any_execution_request(stmt, params); }
  88. };
  89. template <class FieldViewFwdIterator>
  90. inline stmt_it_request_getter make_request_getter(
  91. const bound_statement_iterator_range<FieldViewFwdIterator>& req,
  92. std::vector<field_view>& shared_fields
  93. )
  94. {
  95. auto& impl = access::get_impl(req);
  96. shared_fields.assign(impl.first, impl.last);
  97. return {impl.stmt, shared_fields};
  98. }
  99. template <std::size_t N>
  100. struct stmt_tuple_request_getter
  101. {
  102. statement stmt;
  103. std::array<field_view, N> params;
  104. any_execution_request get() const noexcept { return any_execution_request(stmt, params); }
  105. };
  106. template <class WritableFieldTuple>
  107. stmt_tuple_request_getter<std::tuple_size<WritableFieldTuple>::value>
  108. make_request_getter(const bound_statement_tuple<WritableFieldTuple>& req, std::vector<field_view>&)
  109. {
  110. auto& impl = access::get_impl(req);
  111. return {impl.stmt, tuple_to_array(impl.params)};
  112. }
  113. //
  114. // helpers to run algos
  115. //
  116. template <class AlgoParams>
  117. using has_void_result = std::is_same<typename AlgoParams::result_type, void>;
  118. template <class AlgoParams, bool is_void>
  119. struct completion_signature_impl;
  120. template <class AlgoParams>
  121. struct completion_signature_impl<AlgoParams, true>
  122. {
  123. // Using typedef to workaround a msvc 14.1 bug
  124. typedef void(type)(error_code);
  125. };
  126. template <class AlgoParams>
  127. struct completion_signature_impl<AlgoParams, false>
  128. {
  129. // Using typedef to workaround a msvc 14.1 bug
  130. typedef void(type)(error_code, typename AlgoParams::result_type);
  131. };
  132. template <class AlgoParams>
  133. using completion_signature_t = typename completion_signature_impl<
  134. AlgoParams,
  135. has_void_result<AlgoParams>::value>::type;
  136. // Intermediate handler
  137. template <class AlgoParams, class Handler>
  138. struct generic_algo_handler
  139. {
  140. static_assert(!has_void_result<AlgoParams>::value, "Internal error: result_type should be non-void");
  141. using result_t = typename AlgoParams::result_type;
  142. template <class DeducedHandler>
  143. generic_algo_handler(DeducedHandler&& h, connection_state& st)
  144. : final_handler(std::forward<DeducedHandler>(h)), st(&st)
  145. {
  146. }
  147. void operator()(error_code ec)
  148. {
  149. std::move(final_handler)(ec, ec ? result_t{} : get_result<AlgoParams>(*st));
  150. }
  151. Handler final_handler; // needs to be accessed by associator
  152. connection_state* st;
  153. };
  154. class connection_impl
  155. {
  156. std::unique_ptr<engine> engine_;
  157. std::unique_ptr<connection_state, connection_state_deleter> st_;
  158. // Generic algorithm
  159. template <class AlgoParams>
  160. typename AlgoParams::result_type run_impl(
  161. AlgoParams params,
  162. error_code& ec,
  163. std::true_type /* has_void_result */
  164. )
  165. {
  166. engine_->run(setup(*st_, params), ec);
  167. }
  168. template <class AlgoParams>
  169. typename AlgoParams::result_type run_impl(
  170. AlgoParams params,
  171. error_code& ec,
  172. std::false_type /* has_void_result */
  173. )
  174. {
  175. engine_->run(setup(*st_, params), ec);
  176. return get_result<AlgoParams>(*st_);
  177. }
  178. template <class AlgoParams, class Handler>
  179. static void async_run_impl(
  180. engine& eng,
  181. connection_state& st,
  182. AlgoParams params,
  183. Handler&& handler,
  184. std::true_type /* has_void_result */
  185. )
  186. {
  187. eng.async_run(setup(st, params), std::forward<Handler>(handler));
  188. }
  189. template <class AlgoParams, class Handler>
  190. static void async_run_impl(
  191. engine& eng,
  192. connection_state& st,
  193. AlgoParams params,
  194. Handler&& handler,
  195. std::false_type /* has_void_result */
  196. )
  197. {
  198. using intermediate_handler_t = generic_algo_handler<AlgoParams, typename std::decay<Handler>::type>;
  199. eng.async_run(setup(st, params), intermediate_handler_t(std::forward<Handler>(handler), st));
  200. }
  201. template <class AlgoParams, class Handler>
  202. static void async_run_impl(engine& eng, connection_state& st, AlgoParams params, Handler&& handler)
  203. {
  204. async_run_impl(eng, st, params, std::forward<Handler>(handler), has_void_result<AlgoParams>{});
  205. }
  206. struct run_algo_initiation
  207. {
  208. template <class Handler, class AlgoParams>
  209. void operator()(Handler&& handler, engine* eng, connection_state* st, AlgoParams params)
  210. {
  211. async_run_impl(*eng, *st, params, std::forward<Handler>(handler));
  212. }
  213. };
  214. // Connect
  215. static connect_algo_params make_params_connect(diagnostics& diag, const handshake_params& params)
  216. {
  217. return connect_algo_params{&diag, params, false};
  218. }
  219. static connect_algo_params make_params_connect_v2(diagnostics& diag, const connect_params& params)
  220. {
  221. return connect_algo_params{
  222. &diag,
  223. make_hparams(params),
  224. params.server_address.type() == address_type::unix_path
  225. };
  226. }
  227. template <class EndpointType>
  228. struct initiate_connect
  229. {
  230. template <class Handler>
  231. void operator()(
  232. Handler&& handler,
  233. engine* eng,
  234. connection_state* st,
  235. const EndpointType& endpoint,
  236. handshake_params params,
  237. diagnostics* diag
  238. )
  239. {
  240. eng->set_endpoint(&endpoint);
  241. async_run_impl(*eng, *st, make_params_connect(*diag, params), std::forward<Handler>(handler));
  242. }
  243. };
  244. struct initiate_connect_v2
  245. {
  246. template <class Handler>
  247. void operator()(
  248. Handler&& handler,
  249. engine* eng,
  250. connection_state* st,
  251. const connect_params* params,
  252. diagnostics* diag
  253. )
  254. {
  255. eng->set_endpoint(&params->server_address);
  256. async_run_impl(*eng, *st, make_params_connect_v2(*diag, *params), std::forward<Handler>(handler));
  257. }
  258. };
  259. // execute
  260. struct initiate_execute
  261. {
  262. template <class Handler, class ExecutionRequest>
  263. void operator()(
  264. Handler&& handler,
  265. engine* eng,
  266. connection_state* st,
  267. const ExecutionRequest& req,
  268. execution_processor* proc,
  269. diagnostics* diag
  270. )
  271. {
  272. auto getter = make_request_getter(req, get_shared_fields(*st));
  273. async_run_impl(
  274. *eng,
  275. *st,
  276. execute_algo_params{diag, getter.get(), proc},
  277. std::forward<Handler>(handler)
  278. );
  279. }
  280. };
  281. // start execution
  282. struct initiate_start_execution
  283. {
  284. template <class Handler, class ExecutionRequest>
  285. void operator()(
  286. Handler&& handler,
  287. engine* eng,
  288. connection_state* st,
  289. const ExecutionRequest& req,
  290. execution_processor* proc,
  291. diagnostics* diag
  292. )
  293. {
  294. auto getter = make_request_getter(req, get_shared_fields(*st));
  295. async_run_impl(
  296. *eng,
  297. *st,
  298. start_execution_algo_params{diag, getter.get(), proc},
  299. std::forward<Handler>(handler)
  300. );
  301. }
  302. };
  303. public:
  304. BOOST_MYSQL_DECL connection_impl(
  305. std::size_t read_buff_size,
  306. std::size_t max_buffer_size,
  307. std::unique_ptr<engine> eng
  308. );
  309. BOOST_MYSQL_DECL metadata_mode meta_mode() const;
  310. BOOST_MYSQL_DECL void set_meta_mode(metadata_mode m);
  311. BOOST_MYSQL_DECL bool ssl_active() const;
  312. BOOST_MYSQL_DECL bool backslash_escapes() const;
  313. BOOST_MYSQL_DECL system::result<character_set> current_character_set() const;
  314. BOOST_MYSQL_DECL diagnostics& shared_diag(); // TODO: get rid of this
  315. engine& get_engine()
  316. {
  317. BOOST_ASSERT(engine_);
  318. return *engine_;
  319. }
  320. const engine& get_engine() const
  321. {
  322. BOOST_ASSERT(engine_);
  323. return *engine_;
  324. }
  325. // Generic algorithm
  326. template <class AlgoParams>
  327. typename AlgoParams::result_type run(AlgoParams params, error_code& ec)
  328. {
  329. return run_impl(params, ec, has_void_result<AlgoParams>{});
  330. }
  331. template <class AlgoParams, class CompletionToken>
  332. auto async_run(AlgoParams params, CompletionToken&& token)
  333. -> decltype(asio::async_initiate<CompletionToken, completion_signature_t<AlgoParams>>(
  334. run_algo_initiation(),
  335. token,
  336. engine_.get(),
  337. st_.get(),
  338. params
  339. ))
  340. {
  341. return asio::async_initiate<CompletionToken, completion_signature_t<AlgoParams>>(
  342. run_algo_initiation(),
  343. token,
  344. engine_.get(),
  345. st_.get(),
  346. params
  347. );
  348. }
  349. // Connect
  350. template <class EndpointType>
  351. void connect(
  352. const EndpointType& endpoint,
  353. const handshake_params& params,
  354. error_code& err,
  355. diagnostics& diag
  356. )
  357. {
  358. engine_->set_endpoint(&endpoint);
  359. run(make_params_connect(diag, params), err);
  360. }
  361. void connect_v2(const connect_params& params, error_code& err, diagnostics& diag)
  362. {
  363. engine_->set_endpoint(&params.server_address);
  364. run(make_params_connect_v2(diag, params), err);
  365. }
  366. template <class EndpointType, class CompletionToken>
  367. auto async_connect(
  368. const EndpointType& endpoint,
  369. const handshake_params& params,
  370. diagnostics& diag,
  371. CompletionToken&& token
  372. )
  373. -> decltype(asio::async_initiate<CompletionToken, void(error_code)>(
  374. initiate_connect<EndpointType>(),
  375. token,
  376. engine_.get(),
  377. st_.get(),
  378. endpoint,
  379. params,
  380. &diag
  381. ))
  382. {
  383. return asio::async_initiate<CompletionToken, void(error_code)>(
  384. initiate_connect<EndpointType>(),
  385. token,
  386. engine_.get(),
  387. st_.get(),
  388. endpoint,
  389. params,
  390. &diag
  391. );
  392. }
  393. template <class CompletionToken>
  394. auto async_connect_v2(const connect_params& params, diagnostics& diag, CompletionToken&& token)
  395. -> decltype(asio::async_initiate<CompletionToken, void(error_code)>(
  396. initiate_connect_v2(),
  397. token,
  398. engine_.get(),
  399. st_.get(),
  400. &params,
  401. &diag
  402. ))
  403. {
  404. return asio::async_initiate<CompletionToken, void(error_code)>(
  405. initiate_connect_v2(),
  406. token,
  407. engine_.get(),
  408. st_.get(),
  409. &params,
  410. &diag
  411. );
  412. }
  413. // Handshake
  414. handshake_algo_params make_params_handshake(const handshake_params& params, diagnostics& diag) const
  415. {
  416. return {&diag, params, false};
  417. }
  418. // Execute
  419. template <class ExecutionRequest, class ResultsType>
  420. void execute(const ExecutionRequest& req, ResultsType& result, error_code& err, diagnostics& diag)
  421. {
  422. auto getter = make_request_getter(req, get_shared_fields(*st_));
  423. run(execute_algo_params{&diag, getter.get(), &access::get_impl(result).get_interface()}, err);
  424. }
  425. template <class ExecutionRequest, class ResultsType, class CompletionToken>
  426. auto async_execute(
  427. ExecutionRequest&& req,
  428. ResultsType& result,
  429. diagnostics& diag,
  430. CompletionToken&& token
  431. )
  432. -> decltype(asio::async_initiate<CompletionToken, void(error_code)>(
  433. initiate_execute(),
  434. token,
  435. engine_.get(),
  436. st_.get(),
  437. std::forward<ExecutionRequest>(req),
  438. &access::get_impl(result).get_interface(),
  439. &diag
  440. ))
  441. {
  442. return asio::async_initiate<CompletionToken, void(error_code)>(
  443. initiate_execute(),
  444. token,
  445. engine_.get(),
  446. st_.get(),
  447. std::forward<ExecutionRequest>(req),
  448. &access::get_impl(result).get_interface(),
  449. &diag
  450. );
  451. }
  452. // Start execution
  453. template <class ExecutionRequest, class ExecutionStateType>
  454. void start_execution(
  455. const ExecutionRequest& req,
  456. ExecutionStateType& exec_st,
  457. error_code& err,
  458. diagnostics& diag
  459. )
  460. {
  461. auto getter = make_request_getter(req, get_shared_fields(*st_));
  462. run(start_execution_algo_params{&diag, getter.get(), &access::get_impl(exec_st).get_interface()},
  463. err);
  464. }
  465. template <class ExecutionRequest, class ExecutionStateType, class CompletionToken>
  466. auto async_start_execution(
  467. ExecutionRequest&& req,
  468. ExecutionStateType& exec_st,
  469. diagnostics& diag,
  470. CompletionToken&& token
  471. )
  472. -> decltype(asio::async_initiate<CompletionToken, void(error_code)>(
  473. initiate_start_execution(),
  474. token,
  475. engine_.get(),
  476. st_.get(),
  477. std::forward<ExecutionRequest>(req),
  478. &access::get_impl(exec_st).get_interface(),
  479. &diag
  480. ))
  481. {
  482. return asio::async_initiate<CompletionToken, void(error_code)>(
  483. initiate_start_execution(),
  484. token,
  485. engine_.get(),
  486. st_.get(),
  487. std::forward<ExecutionRequest>(req),
  488. &access::get_impl(exec_st).get_interface(),
  489. &diag
  490. );
  491. }
  492. // Read some rows (dynamic)
  493. read_some_rows_dynamic_algo_params make_params_read_some_rows(execution_state& st, diagnostics& diag)
  494. const
  495. {
  496. return {&diag, &access::get_impl(st).get_interface()};
  497. }
  498. // Read some rows (static)
  499. template <class SpanElementType, class ExecutionState>
  500. read_some_rows_algo_params make_params_read_some_rows_static(
  501. ExecutionState& exec_st,
  502. span<SpanElementType> output,
  503. diagnostics& diag
  504. ) const
  505. {
  506. return {
  507. &diag,
  508. &access::get_impl(exec_st).get_interface(),
  509. access::get_impl(exec_st).make_output_ref(output)
  510. };
  511. }
  512. // Read resultset head
  513. template <class ExecutionStateType>
  514. read_resultset_head_algo_params make_params_read_resultset_head(ExecutionStateType& st, diagnostics& diag)
  515. const
  516. {
  517. return {&diag, &detail::access::get_impl(st).get_interface()};
  518. }
  519. // Close statement
  520. close_statement_algo_params make_params_close_statement(statement stmt, diagnostics& diag) const
  521. {
  522. return {&diag, stmt.id()};
  523. }
  524. // Set character set
  525. set_character_set_algo_params make_params_set_character_set(
  526. const character_set& charset,
  527. diagnostics& diag
  528. ) const
  529. {
  530. return {&diag, charset};
  531. }
  532. // Ping
  533. ping_algo_params make_params_ping(diagnostics& diag) const { return {&diag}; }
  534. // Reset connection
  535. reset_connection_algo_params make_params_reset_connection(diagnostics& diag) const { return {&diag}; }
  536. // Quit connection
  537. quit_connection_algo_params make_params_quit(diagnostics& diag) const { return {&diag}; }
  538. // Close connection
  539. close_connection_algo_params make_params_close(diagnostics& diag) const { return {&diag}; }
  540. // Run pipeline. Separately compiled to avoid including the pipeline header here
  541. BOOST_MYSQL_DECL
  542. static run_pipeline_algo_params make_params_pipeline(
  543. const pipeline_request& req,
  544. std::vector<stage_response>& response,
  545. diagnostics& diag
  546. );
  547. };
  548. // To use some completion tokens, like deferred, in C++11, the old macros
  549. // BOOST_ASIO_INITFN_AUTO_RESULT_TYPE are no longer enough.
  550. // Helper typedefs to reduce duplication
  551. template <class AlgoParams, class CompletionToken>
  552. using async_run_t = decltype(std::declval<connection_impl&>()
  553. .async_run(std::declval<AlgoParams>(), std::declval<CompletionToken>()));
  554. template <class EndpointType, class CompletionToken>
  555. using async_connect_t = decltype(std::declval<connection_impl&>().async_connect(
  556. std::declval<const EndpointType&>(),
  557. std::declval<const handshake_params&>(),
  558. std::declval<diagnostics&>(),
  559. std::declval<CompletionToken>()
  560. ));
  561. template <class CompletionToken>
  562. using async_connect_v2_t = decltype(std::declval<connection_impl&>().async_connect_v2(
  563. std::declval<const connect_params&>(),
  564. std::declval<diagnostics&>(),
  565. std::declval<CompletionToken>()
  566. ));
  567. template <class ExecutionRequest, class ResultsType, class CompletionToken>
  568. using async_execute_t = decltype(std::declval<connection_impl&>().async_execute(
  569. std::declval<ExecutionRequest>(),
  570. std::declval<ResultsType&>(),
  571. std::declval<diagnostics&>(),
  572. std::declval<CompletionToken>()
  573. ));
  574. template <class ExecutionRequest, class ExecutionStateType, class CompletionToken>
  575. using async_start_execution_t = decltype(std::declval<connection_impl&>().async_start_execution(
  576. std::declval<ExecutionRequest>(),
  577. std::declval<ExecutionStateType&>(),
  578. std::declval<diagnostics&>(),
  579. std::declval<CompletionToken>()
  580. ));
  581. template <class CompletionToken>
  582. using async_handshake_t = async_run_t<handshake_algo_params, CompletionToken>;
  583. template <class CompletionToken>
  584. using async_read_resultset_head_t = async_run_t<read_resultset_head_algo_params, CompletionToken>;
  585. template <class CompletionToken>
  586. using async_read_some_rows_dynamic_t = async_run_t<read_some_rows_dynamic_algo_params, CompletionToken>;
  587. template <class CompletionToken>
  588. using async_prepare_statement_t = async_run_t<prepare_statement_algo_params, CompletionToken>;
  589. template <class CompletionToken>
  590. using async_close_statement_t = async_run_t<close_statement_algo_params, CompletionToken>;
  591. template <class CompletionToken>
  592. using async_set_character_set_t = async_run_t<set_character_set_algo_params, CompletionToken>;
  593. template <class CompletionToken>
  594. using async_ping_t = async_run_t<ping_algo_params, CompletionToken>;
  595. template <class CompletionToken>
  596. using async_reset_connection_t = async_run_t<reset_connection_algo_params, CompletionToken>;
  597. template <class CompletionToken>
  598. using async_quit_connection_t = async_run_t<quit_connection_algo_params, CompletionToken>;
  599. template <class CompletionToken>
  600. using async_close_connection_t = async_run_t<close_connection_algo_params, CompletionToken>;
  601. template <class CompletionToken>
  602. using async_run_pipeline_t = async_run_t<run_pipeline_algo_params, CompletionToken>;
  603. } // namespace detail
  604. } // namespace mysql
  605. } // namespace boost
  606. // Propagate associated properties
  607. namespace boost {
  608. namespace asio {
  609. template <template <class, class> class Associator, class AlgoParams, class Handler, class DefaultCandidate>
  610. struct associator<Associator, mysql::detail::generic_algo_handler<AlgoParams, Handler>, DefaultCandidate>
  611. : Associator<Handler, DefaultCandidate>
  612. {
  613. using mysql_handler = mysql::detail::generic_algo_handler<AlgoParams, Handler>;
  614. static typename Associator<Handler, DefaultCandidate>::type get(const mysql_handler& h)
  615. {
  616. return Associator<Handler, DefaultCandidate>::get(h.final_handler);
  617. }
  618. static auto get(const mysql_handler& h, const DefaultCandidate& c)
  619. -> decltype(Associator<Handler, DefaultCandidate>::get(h.final_handler, c))
  620. {
  621. return Associator<Handler, DefaultCandidate>::get(h.final_handler, c);
  622. }
  623. };
  624. } // namespace asio
  625. } // namespace boost
  626. #ifdef BOOST_MYSQL_HEADER_ONLY
  627. #include <boost/mysql/impl/connection_impl.ipp>
  628. #endif
  629. #endif