File indexing completed on 2025-04-09 08:28:00
0001
0002
0003
0004
0005
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
0047 template <class... StaticRow>
0048 class static_execution_state;
0049
0050 struct character_set;
0051 class pipeline_request;
0052
0053 namespace detail {
0054
0055
0056 class connection_state;
0057
0058
0059
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
0072 template <class AlgoParams>
0073 typename AlgoParams::result_type get_result(const connection_state&);
0074
0075
0076
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);
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;
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
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
0150 typedef void(type)(error_code);
0151 };
0152
0153 template <class AlgoParams>
0154 struct completion_signature_impl<AlgoParams, false>
0155 {
0156
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
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;
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
0194 template <class AlgoParams>
0195 typename AlgoParams::result_type run_impl(
0196 AlgoParams params,
0197 error_code& ec,
0198 std::true_type
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
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
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
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
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(¶ms->server_address);
0300 async_run_impl(*eng, *st, make_params_connect_v2(*diag, *params), std::forward<Handler>(handler));
0301 }
0302 };
0303
0304
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
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();
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
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
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(¶ms.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 ¶ms,
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 ¶ms,
0466 &diag
0467 );
0468 }
0469
0470
0471 handshake_algo_params make_params_handshake(const handshake_params& params, diagnostics& diag) const
0472 {
0473 return {&diag, params, false};
0474 }
0475
0476
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
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
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
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
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
0585 close_statement_algo_params make_params_close_statement(statement stmt, diagnostics& diag) const
0586 {
0587 return {&diag, stmt.id()};
0588 }
0589
0590
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
0600 ping_algo_params make_params_ping(diagnostics& diag) const { return {&diag}; }
0601
0602
0603 reset_connection_algo_params make_params_reset_connection(diagnostics& diag) const { return {&diag}; }
0604
0605
0606 quit_connection_algo_params make_params_quit(diagnostics& diag) const { return {&diag}; }
0607
0608
0609 close_connection_algo_params make_params_close(diagnostics& diag) const { return {&diag}; }
0610
0611
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
0621
0622
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 }
0692 }
0693 }
0694
0695
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 }
0718 }
0719
0720 #ifdef BOOST_MYSQL_HEADER_ONLY
0721 #include <boost/mysql/impl/connection_impl.ipp>
0722 #endif
0723
0724 #endif