// // Copyright (c) 2019-2023 Ruben Perez Hidalgo (rubenperez038 at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BHO_MYSQL_DETAIL_NETWORK_ALGORITHMS_HPP #define BHO_MYSQL_DETAIL_NETWORK_ALGORITHMS_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace bho { namespace mysql { template class static_execution_state; namespace detail { class channel; template using any_handler = asio::any_completion_handler; using any_void_handler = asio::any_completion_handler; // execution helpers template std::array tuple_to_array_impl(const std::tuple& t, mp11::index_sequence) noexcept { return std::array{{to_field(std::get(t))...}}; } template std::array tuple_to_array(const std::tuple& t) noexcept { return tuple_to_array_impl(t, mp11::make_index_sequence()); } struct query_request_getter { any_execution_request value; any_execution_request get() const noexcept { return value; } }; inline query_request_getter make_request_getter(string_view q, channel&) noexcept { return query_request_getter{q}; } struct stmt_it_request_getter { statement stmt; span params; // Points into channel shared_fields() any_execution_request get() const noexcept { return any_execution_request(stmt, params); } }; template inline stmt_it_request_getter make_request_getter( const bound_statement_iterator_range& req, channel& chan ) { auto& impl = access::get_impl(req); auto& shared_fields = get_shared_fields(chan); shared_fields.assign(impl.first, impl.last); return {impl.stmt, shared_fields}; } template struct stmt_tuple_request_getter { statement stmt; std::array params; any_execution_request get() const noexcept { return any_execution_request(stmt, params); } }; template stmt_tuple_request_getter::value> make_request_getter(const bound_statement_tuple& req, channel&) { auto& impl = access::get_impl(req); return {impl.stmt, tuple_to_array(impl.params)}; } // // connect // BHO_MYSQL_DECL void connect_erased( channel& chan, const void* endpoint, const handshake_params& params, error_code& err, diagnostics& diag ); BHO_MYSQL_DECL void async_connect_erased( channel& chan, const void* endpoint, const handshake_params& params, diagnostics& diag, any_void_handler handler ); // Handles casting from the generic EndpointType we've got in the interface to the concrete endpoint type template void connect_interface( channel& chan, const typename Stream::lowest_layer_type::endpoint_type& ep, const handshake_params& params, error_code& err, diagnostics& diag ) { connect_erased(chan, &ep, params, err, diag); } template struct connect_initiation { template void operator()( Handler&& handler, channel* chan, const typename Stream::lowest_layer_type::endpoint_type& endpoint, handshake_params params, diagnostics* diag ) { async_connect_erased(*chan, &endpoint, params, *diag, std::forward(handler)); } }; template ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) async_connect_interface( channel& chan, const typename Stream::lowest_layer_type::endpoint_type& endpoint, const handshake_params& params, diagnostics& diag, CompletionToken&& token ) { return asio::async_initiate( connect_initiation(), token, &chan, endpoint, params, &diag ); } // // handshake // BHO_MYSQL_DECL void handshake_erased(channel& channel, const handshake_params& params, error_code& err, diagnostics& diag); BHO_MYSQL_DECL void async_handshake_erased( channel& chan, const handshake_params& params, diagnostics& diag, any_void_handler ); inline void handshake_interface( channel& channel, const handshake_params& params, error_code& err, diagnostics& diag ) { handshake_erased(channel, params, err, diag); } struct handshake_initiation { template void operator()(Handler&& handler, channel* chan, handshake_params params, diagnostics* diag) { async_handshake_erased(*chan, params, *diag, std::forward(handler)); } }; template ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) async_handshake_interface( channel& chan, const handshake_params& params, diagnostics& diag, CompletionToken&& token ) { return asio::async_initiate( handshake_initiation(), token, &chan, params, &diag ); } // // execute // BHO_MYSQL_DECL void execute_erased( channel& channel, const any_execution_request& req, execution_processor& output, error_code& err, diagnostics& diag ); BHO_MYSQL_DECL void async_execute_erased( channel& chan, const any_execution_request& req, execution_processor& output, diagnostics& diag, any_void_handler handler ); struct initiate_execute { template void operator()( Handler&& handler, channel& chan, const ExecutionRequest& req, execution_processor& proc, diagnostics& diag ) { auto getter = make_request_getter(req, chan); async_execute_erased(chan, getter.get(), proc, diag, std::forward(handler)); } }; template void execute_interface( channel& channel, const ExecutionRequest& req, ResultsType& result, error_code& err, diagnostics& diag ) { auto getter = make_request_getter(req, channel); execute_erased(channel, getter.get(), access::get_impl(result).get_interface(), err, diag); } template ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) async_execute_interface( channel& chan, ExecutionRequest&& req, ResultsType& result, diagnostics& diag, CompletionToken&& token ) { return asio::async_initiate( initiate_execute(), token, std::ref(chan), std::forward(req), std::ref(access::get_impl(result).get_interface()), std::ref(diag) ); } // // start_execution // BHO_MYSQL_DECL void start_execution_erased( channel& channel, const any_execution_request& req, execution_processor& proc, error_code& err, diagnostics& diag ); BHO_MYSQL_DECL void async_start_execution_erased( channel& channel, const any_execution_request& req, execution_processor& proc, diagnostics& diag, any_void_handler handler ); struct initiate_start_execution { template void operator()( Handler&& handler, channel& chan, const ExecutionRequest& req, execution_processor& proc, diagnostics& diag ) { auto getter = make_request_getter(req, chan); async_start_execution_erased(chan, getter.get(), proc, diag, std::forward(handler)); } }; template void start_execution_interface( channel& channel, const ExecutionRequest& req, ExecutionStateType& st, error_code& err, diagnostics& diag ) { auto getter = make_request_getter(req, channel); start_execution_erased(channel, getter.get(), access::get_impl(st).get_interface(), err, diag); } template ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) async_start_execution_interface( channel& chan, ExecutionRequest&& req, ExecutionStateType& st, diagnostics& diag, CompletionToken&& token ) { return asio::async_initiate( initiate_start_execution(), token, std::ref(chan), std::forward(req), std::ref(access::get_impl(st).get_interface()), std::ref(diag) ); } // // prepare_statement // BHO_MYSQL_DECL statement prepare_statement_erased(channel& chan, string_view stmt, error_code& err, diagnostics& diag); BHO_MYSQL_DECL void async_prepare_statement_erased( channel& chan, string_view stmt, diagnostics& diag, any_handler handler ); struct prepare_statement_initiation { template void operator()(Handler&& handler, channel* chan, string_view stmt_sql, diagnostics* diag) { async_prepare_statement_erased(*chan, stmt_sql, *diag, std::forward(handler)); } }; inline statement prepare_statement_interface( channel& chan, string_view stmt, error_code& err, diagnostics& diag ) { return prepare_statement_erased(chan, stmt, err, diag); } template ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(bho::mysql::error_code, bho::mysql::statement)) async_prepare_statement_interface(channel& chan, string_view stmt, diagnostics& diag, CompletionToken&& token) { return asio::async_initiate( prepare_statement_initiation(), token, &chan, stmt, &diag ); } // // close_statement // BHO_MYSQL_DECL void close_statement_erased(channel& chan, const statement& stmt, error_code& err, diagnostics& diag); BHO_MYSQL_DECL void async_close_statement_erased( channel& chan, const statement& stmt, diagnostics& diag, any_void_handler handler ); struct close_statement_initiation { template void operator()(Handler&& handler, channel* chan, statement stmt, diagnostics* diag) { async_close_statement_erased(*chan, stmt, *diag, std::forward(handler)); } }; inline void close_statement_interface( channel& chan, const statement& stmt, error_code& err, diagnostics& diag ) { close_statement_erased(chan, stmt, err, diag); } template ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) async_close_statement_interface( channel& chan, const statement& stmt, diagnostics& diag, CompletionToken&& token ) { return asio::async_initiate( close_statement_initiation(), token, &chan, stmt, &diag ); } // // read_some_rows (dynamic) // BHO_MYSQL_DECL rows_view read_some_rows_dynamic_erased( channel& chan, execution_state_impl& st, error_code& err, diagnostics& diag ); BHO_MYSQL_DECL void async_read_some_rows_dynamic_erased( channel& chan, execution_state_impl& st, diagnostics& diag, any_handler handler ); struct read_some_rows_dynamic_initiation { template void operator()(Handler&& handler, channel* chan, execution_state_impl* st, diagnostics* diag) { async_read_some_rows_dynamic_erased(*chan, *st, *diag, std::forward(handler)); } }; inline rows_view read_some_rows_dynamic_interface( channel& chan, execution_state& st, error_code& err, diagnostics& diag ) { return read_some_rows_dynamic_erased(chan, access::get_impl(st), err, diag); } template ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, rows_view)) async_read_some_rows_dynamic_interface( channel& chan, execution_state& st, diagnostics& diag, CompletionToken&& token ) { return asio::async_initiate( read_some_rows_dynamic_initiation(), token, &chan, &access::get_impl(st).get_interface(), &diag ); } // // read_some_rows (static) // BHO_MYSQL_DECL std::size_t read_some_rows_static_erased( channel& chan, execution_processor& proc, const output_ref& output, error_code& err, diagnostics& diag ); BHO_MYSQL_DECL void async_read_some_rows_erased( channel& chan, execution_processor& proc, const output_ref& output, diagnostics& diag, any_handler handler ); template std::size_t read_some_rows_static_interface( channel& chan, static_execution_state& st, span output, error_code& err, diagnostics& diag ) { constexpr std::size_t index = get_type_index(); static_assert(index != index_not_found, "SpanRowType must be one of the types returned by the query"); return read_some_rows_static_erased( chan, access::get_impl(st).get_interface(), output_ref(output, index), err, diag ); } struct read_some_rows_static_initiation { template void operator()( Handler&& handler, channel* chan, execution_processor* proc, const output_ref& output, diagnostics* diag ) { async_read_some_rows_erased(*chan, *proc, output, *diag, std::forward(handler)); } }; template < class SpanRowType, class... RowType, ASIO_COMPLETION_TOKEN_FOR(void(::bho::mysql::error_code, std::size_t)) CompletionToken> ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, rows_view)) async_read_some_rows_static_interface( channel& chan, static_execution_state& st, span output, diagnostics& diag, CompletionToken&& token ) { constexpr std::size_t index = get_type_index(); static_assert(index != index_not_found, "SpanRowType must be one of the types returned by the query"); return asio::async_initiate( read_some_rows_static_initiation(), token, &chan, &access::get_impl(st).get_interface(), output_ref(output, index), &diag ); } // // read_resultset_head // BHO_MYSQL_DECL void read_resultset_head_erased( channel& channel, execution_processor& proc, error_code& err, diagnostics& diag ); BHO_MYSQL_DECL void async_read_resultset_head_erased( channel& chan, execution_processor& proc, diagnostics& diag, any_void_handler handler ); template void read_resultset_head_interface( channel& channel, ExecutionStateType& st, error_code& err, diagnostics& diag ) { read_resultset_head_erased(channel, access::get_impl(st).get_interface(), err, diag); } struct read_resultset_head_initiation { template void operator()(Handler&& handler, channel* chan, execution_processor* proc, diagnostics* diag) { async_read_resultset_head_erased(*chan, *proc, *diag, std::forward(handler)); } }; template ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) async_read_resultset_head_interface( channel& chan, ExecutionStateType& st, diagnostics& diag, CompletionToken&& token ) { return asio::async_initiate( read_resultset_head_initiation(), token, &chan, &access::get_impl(st).get_interface(), &diag ); } // // ping // BHO_MYSQL_DECL void ping_erased(channel& chan, error_code& code, diagnostics& diag); BHO_MYSQL_DECL void async_ping_erased(channel& chan, diagnostics& diag, any_void_handler handler); struct ping_initiation { template void operator()(Handler&& handler, channel* chan, diagnostics* diag) { async_ping_erased(*chan, *diag, std::forward(handler)); } }; inline void ping_interface(channel& chan, error_code& code, diagnostics& diag) { ping_erased(chan, code, diag); } template ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) async_ping_interface(channel& chan, diagnostics& diag, CompletionToken&& token) { return asio::async_initiate(ping_initiation(), token, &chan, &diag); } // // reset_connection // BHO_MYSQL_DECL void reset_connection_erased(channel& chan, error_code& code, diagnostics& diag); BHO_MYSQL_DECL void async_reset_connection_erased(channel& chan, diagnostics& diag, any_void_handler handler); struct reset_connection_initiation { template void operator()(Handler&& handler, channel* chan, diagnostics* diag) { async_reset_connection_erased(*chan, *diag, std::forward(handler)); } }; inline void reset_connection_interface(channel& chan, error_code& code, diagnostics& diag) { reset_connection_erased(chan, code, diag); } template ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) async_reset_connection_interface(channel& chan, diagnostics& diag, CompletionToken&& token) { return asio::async_initiate( reset_connection_initiation(), token, &chan, &diag ); } // // close connection // BHO_MYSQL_DECL void close_connection_erased(channel& chan, error_code& code, diagnostics& diag); BHO_MYSQL_DECL void async_close_connection_erased(channel& chan, diagnostics& diag, any_void_handler handler); struct close_connection_initiation { template void operator()(Handler&& handler, channel* chan, diagnostics* diag) { async_close_connection_erased(*chan, *diag, std::forward(handler)); } }; inline void close_connection_interface(channel& chan, error_code& code, diagnostics& diag) { close_connection_erased(chan, code, diag); } template ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) async_close_connection_interface(channel& chan, diagnostics& diag, CompletionToken&& token) { return asio::async_initiate( close_connection_initiation(), token, &chan, &diag ); } // // quit connection // BHO_MYSQL_DECL void quit_connection_erased(channel& chan, error_code& err, diagnostics& diag); BHO_MYSQL_DECL void async_quit_connection_erased(channel& chan, diagnostics& diag, any_void_handler handler); struct quit_connection_initiation { template void operator()(Handler&& handler, channel* chan, diagnostics* diag) { async_quit_connection_erased(*chan, *diag, std::forward(handler)); } }; inline void quit_connection_interface(channel& chan, error_code& err, diagnostics& diag) { quit_connection_erased(chan, err, diag); } template ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) async_quit_connection_interface(channel& chan, diagnostics& diag, CompletionToken&& token) { return asio::async_initiate( quit_connection_initiation(), token, &chan, &diag ); } } // namespace detail } // namespace mysql } // namespace bho #ifdef BHO_MYSQL_HEADER_ONLY #include #endif #endif