diff --git a/include/boost/mysql/connection.hpp b/include/boost/mysql/connection.hpp index d8f50572..caf6cdbd 100644 --- a/include/boost/mysql/connection.hpp +++ b/include/boost/mysql/connection.hpp @@ -521,7 +521,7 @@ public: * The handler signature for this operation is * `void(boost::mysql::error_code, boost::mysql::resultset)`. */ - template < + template< class ValueCollection, BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code)) CompletionToken diff --git a/include/boost/mysql/detail/network_algorithms/connect.hpp b/include/boost/mysql/detail/network_algorithms/connect.hpp index 3264ab45..222b3197 100644 --- a/include/boost/mysql/detail/network_algorithms/connect.hpp +++ b/include/boost/mysql/detail/network_algorithms/connect.hpp @@ -30,8 +30,8 @@ async_connect( channel& chan, const typename Stream::lowest_layer_type::endpoint_type& endpoint, const connection_params& params, - CompletionToken&& token, - error_info& info + error_info& info, + CompletionToken&& token ); } // detail diff --git a/include/boost/mysql/detail/network_algorithms/execute_statement.hpp b/include/boost/mysql/detail/network_algorithms/execute_statement.hpp index 223ad7ec..2bf41631 100644 --- a/include/boost/mysql/detail/network_algorithms/execute_statement.hpp +++ b/include/boost/mysql/detail/network_algorithms/execute_statement.hpp @@ -11,6 +11,8 @@ #include #include #include +#include +#include namespace boost { namespace mysql { @@ -19,9 +21,7 @@ namespace detail { template void execute_statement( channel& channel, - std::uint32_t statement_id, - ValueForwardIterator params_begin, - ValueForwardIterator params_end, + const execute_params& params, resultset& output, error_code& err, error_info& info @@ -31,9 +31,7 @@ template BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) async_execute_statement( channel& chan, - std::uint32_t statement_id, - ValueForwardIterator params_begin, - ValueForwardIterator params_end, + const execute_params& params, resultset& output, error_info& info, CompletionToken&& token diff --git a/include/boost/mysql/detail/network_algorithms/handshake.hpp b/include/boost/mysql/detail/network_algorithms/handshake.hpp index 781cbca3..ceea2123 100644 --- a/include/boost/mysql/detail/network_algorithms/handshake.hpp +++ b/include/boost/mysql/detail/network_algorithms/handshake.hpp @@ -32,8 +32,8 @@ BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) async_handshake( channel& channel, const connection_params& params, - CompletionToken&& token, - error_info& info + error_info& info, + CompletionToken&& token ); } // detail diff --git a/include/boost/mysql/detail/network_algorithms/impl/connect.hpp b/include/boost/mysql/detail/network_algorithms/impl/connect.hpp index 35791766..16379893 100644 --- a/include/boost/mysql/detail/network_algorithms/impl/connect.hpp +++ b/include/boost/mysql/detail/network_algorithms/impl/connect.hpp @@ -110,8 +110,8 @@ boost::mysql::detail::async_connect( channel& chan, const typename Stream::lowest_layer_type::endpoint_type& endpoint, const connection_params& params, - CompletionToken&& token, - error_info& info + error_info& info, + CompletionToken&& token ) { return boost::asio::async_compose( diff --git a/include/boost/mysql/detail/network_algorithms/impl/execute_statement.hpp b/include/boost/mysql/detail/network_algorithms/impl/execute_statement.hpp index 73d379bf..e5cc3177 100644 --- a/include/boost/mysql/detail/network_algorithms/impl/execute_statement.hpp +++ b/include/boost/mysql/detail/network_algorithms/impl/execute_statement.hpp @@ -11,6 +11,7 @@ #pragma once #include +#include #include #include #include @@ -22,21 +23,20 @@ namespace detail { template com_stmt_execute_packet make_stmt_execute_packet( - std::uint32_t statement_id, - ValueForwardIterator params_begin, - ValueForwardIterator params_end + const execute_params& params ) { return com_stmt_execute_packet { - statement_id, + params.statement_id(), std::uint8_t(0), // flags std::uint32_t(1), // iteration count std::uint8_t(1), // new params flag: set - params_begin, - params_end + params.first(), + params.last() }; } + } // detail } // mysql } // boost @@ -44,9 +44,7 @@ com_stmt_execute_packet make_stmt_execute_packet( template void boost::mysql::detail::execute_statement( channel& chan, - std::uint32_t statement_id, - ValueForwardIterator params_begin, - ValueForwardIterator params_end, + const execute_params& params, resultset& output, error_code& err, error_info& info @@ -55,7 +53,7 @@ void boost::mysql::detail::execute_statement( execute_generic( &deserialize_binary_row, chan, - make_stmt_execute_packet(statement_id, params_begin, params_end), + make_stmt_execute_packet(params), output, err, info @@ -69,9 +67,7 @@ BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( ) boost::mysql::detail::async_execute_statement( channel& chan, - std::uint32_t statement_id, - ValueForwardIterator params_begin, - ValueForwardIterator params_end, + const execute_params& params, resultset& output, error_info& info, CompletionToken&& token @@ -80,7 +76,7 @@ boost::mysql::detail::async_execute_statement( return async_execute_generic( &deserialize_binary_row, chan, - make_stmt_execute_packet(statement_id, params_begin, params_end), + make_stmt_execute_packet(params), output, info, std::forward(token) diff --git a/include/boost/mysql/detail/network_algorithms/impl/handshake.hpp b/include/boost/mysql/detail/network_algorithms/impl/handshake.hpp index a003953d..ee7a93b3 100644 --- a/include/boost/mysql/detail/network_algorithms/impl/handshake.hpp +++ b/include/boost/mysql/detail/network_algorithms/impl/handshake.hpp @@ -551,8 +551,8 @@ BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( boost::mysql::detail::async_handshake( channel& chan, const connection_params& params, - CompletionToken&& token, - error_info& info + error_info& info, + CompletionToken&& token ) { chan.reset(); diff --git a/include/boost/mysql/execute_params.hpp b/include/boost/mysql/execute_params.hpp index af529c63..ac1343fa 100644 --- a/include/boost/mysql/execute_params.hpp +++ b/include/boost/mysql/execute_params.hpp @@ -10,13 +10,35 @@ #include #include +#include #include #include +#include #include namespace boost { namespace mysql { +// TODO: move this to impl file +namespace detail { + +template +void check_num_params( + ValueForwardIterator first, + ValueForwardIterator last, + const prepared_statement& stmt +) +{ + auto param_count = std::distance(first, last); + if (param_count != stmt.num_params()) + { + throw std::domain_error(detail::stringize( + "prepared_statement::execute: expected ", stmt.num_params(), " params, but got ", param_count)); + } +} + +} // detail + /** * \brief Represents the parameters required to execute a [reflink prepared_statement]. @@ -41,53 +63,27 @@ class execute_params "ValueForwardIterator requirements not met"); public: /// Constructor. - constexpr execute_params( - std::uint32_t statement_id, + execute_params( + const prepared_statement& stmt, ValueForwardIterator first, ValueForwardIterator last ) : - statement_id_(statement_id), + statement_id_(stmt.id()), first_(first), last_(last) { + detail::check_num_params(first, last, stmt); } constexpr std::uint32_t statement_id() const noexcept { return statement_id_; } - void set_statement_id(std::uint32_t v) noexcept { statement_id_ = v; } - /// Retrieves the parameter value range's begin. constexpr ValueForwardIterator first() const { return first_; } /// Retrieves the parameter value range's end. constexpr ValueForwardIterator last() const { return last_; } - - /// Sets the parameter value range's begin. - void set_first(ValueForwardIterator v) { first_ = v;} - - /// Sets the parameter value range's end. - void set_last(ValueForwardIterator v) { last_ = v; } }; -/** - * \relates execute_params - * \brief Creates an instance of [reflink execute_params] from a pair of iterators. - * \details ValueForwardIterator should meet the [reflink ValueForwardIterator] type requirements. - */ -template < - class ValueForwardIterator, - class EnableIf = detail::enable_if_value_forward_iterator -> -constexpr execute_params -make_execute_params( - std::uint32_t statement_id, - ValueForwardIterator first, - ValueForwardIterator last -) -{ - return execute_params(statement_id, first, last); -} - template < class ValueForwardIterator, class EnableIf = detail::enable_if_value_forward_iterator @@ -99,23 +95,7 @@ make_execute_params( ValueForwardIterator last ) { - return execute_params(stmt.id(), first, last); -} - -/** - * \relates execute_params - * \brief Creates an instance of [reflink execute_params] from a collection. - * \details ValueCollection should meet the [reflink ValueCollection] type requirements. - */ -template < - class ValueCollection, - class EnableIf = detail::enable_if_value_collection -> -constexpr auto make_execute_params( - const ValueCollection& col -) -> execute_params -{ - return make_execute_params(std::begin(col), std::end(col)); + return execute_params(stmt, first, last); } template < @@ -127,7 +107,7 @@ constexpr auto make_execute_params( const ValueCollection& col ) -> execute_params { - return make_execute_params(stmt.id(), std::begin(col), std::end(col)); + return make_execute_params(stmt, std::begin(col), std::end(col)); } } // mysql diff --git a/include/boost/mysql/impl/connection.hpp b/include/boost/mysql/impl/connection.hpp index 10e3f529..ba5fda64 100644 --- a/include/boost/mysql/impl/connection.hpp +++ b/include/boost/mysql/impl/connection.hpp @@ -11,15 +11,22 @@ #pragma once #include +#include +#include #include #include #include #include +#include +#include +#include #include #include #include +#include +// connect template template void boost::mysql::connection::connect( @@ -66,11 +73,13 @@ boost::mysql::connection::async_connect( this->get_channel(), endpoint, params, - std::forward(token), - output_info + output_info, + std::forward(token) ); } + +// handshake template void boost::mysql::connection::handshake( const connection_params& params, @@ -108,47 +117,46 @@ boost::mysql::connection::async_handshake( return detail::async_handshake( get_channel(), params, - std::forward(token), - output_info + output_info, + std::forward(token) ); } // Query template -boost::mysql::resultset boost::mysql::connection::query( +void boost::mysql::connection::query( boost::string_view query_string, + resultset& result, error_code& err, error_info& info ) { detail::clear_errors(err, info); - resultset res; - detail::execute_query(get_channel(), query_string, res, err, info); - return res; + detail::execute_query(get_channel(), query_string, result, err, info); } template -boost::mysql::resultset boost::mysql::connection::query( - boost::string_view query_string +void boost::mysql::connection::query( + boost::string_view query_string, + resultset& result ) { - resultset res; detail::error_block blk; - detail::execute_query(get_channel(), query_string, res, blk.err, blk.info); + detail::execute_query(get_channel(), query_string, result, blk.err, blk.info); blk.check(); - return res; } template template ) + void(::boost::mysql::error_code) ) CompletionToken> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( CompletionToken, - void(boost::mysql::error_code, boost::mysql::resultset) + void(boost::mysql::error_code) ) boost::mysql::connection::async_query( boost::string_view query_string, + resultset& result, error_info& output_info, CompletionToken&& token ) @@ -157,46 +165,48 @@ boost::mysql::connection::async_query( return detail::async_execute_query( get_channel(), query_string, - std::forward(token), - output_info + result, + output_info, + std::forward(token) ); } + +// Prepare statement template -boost::mysql::prepared_statement boost::mysql::connection::prepare_statement( +void boost::mysql::connection::prepare_statement( boost::string_view statement, + prepared_statement& output, error_code& err, error_info& info ) { - mysql::prepared_statement res; detail::clear_errors(err, info); - detail::prepare_statement(get_channel(), statement, err, info, res); - return res; + detail::prepare_statement(get_channel(), statement, output, err, info); } template -boost::mysql::prepared_statement boost::mysql::connection::prepare_statement( - boost::string_view statement +void boost::mysql::connection::prepare_statement( + boost::string_view statement, + prepared_statement& output ) { - mysql::prepared_statement res; detail::error_block blk; - detail::prepare_statement(get_channel(), statement, blk.err, blk.info, res); + detail::prepare_statement(get_channel(), statement, output, blk.err, blk.info); blk.check(); - return res; } template template ) + void(::boost::mysql::error_code) ) CompletionToken> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( CompletionToken, - void(boost::mysql::error_code, boost::mysql::prepared_statement) + void(boost::mysql::error_code) ) boost::mysql::connection::async_prepare_statement( boost::string_view statement, + prepared_statement& output, error_info& output_info, CompletionToken&& token ) @@ -205,12 +215,125 @@ boost::mysql::connection::async_prepare_statement( return detail::async_prepare_statement( get_channel(), statement, + output, + output_info, + std::forward(token) + ); +} + + +// Execute statement +template +template +void boost::mysql::connection::execute_statement( + const execute_params& params, + resultset& result, + error_code& err, + error_info& info +) +{ + detail::clear_errors(err, info); + detail::execute_statement( + get_channel(), + params, + result, + err, + info + ); +} + +template +template +void boost::mysql::connection::execute_statement( + const execute_params& params, + resultset& result +) +{ + detail::error_block blk; + detail::execute_statement( + get_channel(), + params, + result, + blk.err, + blk.info + ); + blk.check(); +} + + +template +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, + void(boost::mysql::error_code) +) +boost::mysql::connection::async_execute_statement( + const execute_params& params, + resultset& result, + error_info& output_info, + CompletionToken&& token +) +{ + output_info.clear(); + detail::async_execute_statement( + get_channel(), + params, + result, + output_info, + std::forward(token) + ); +} + +// Close statement +template +void boost::mysql::connection::close_statement( + const prepared_statement& stmt, + error_code& code, + error_info& info +) +{ + detail::clear_errors(code, info); + detail::close_statement(get_channel(), stmt.id(), code, info); +} + +template +void boost::mysql::connection::close_statement( + const prepared_statement& stmt +) +{ + detail::error_block blk; + detail::close_statement(get_channel(), stmt.id(), blk.err, blk.info); + blk.check(); +} + + +template +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, + void(boost::mysql::error_code) +) +boost::mysql::connection::async_close_statement( + const prepared_statement& stmt, + error_info& output_info, + CompletionToken&& token +) +{ + output_info.clear(); + return detail::async_close_statement( + get_channel(), + stmt.id(), std::forward(token), output_info ); } +// Close template void boost::mysql::connection::close( error_code& err, diff --git a/include/boost/mysql/impl/prepared_statement.hpp b/include/boost/mysql/impl/prepared_statement.hpp deleted file mode 100644 index 81e81994..00000000 --- a/include/boost/mysql/impl/prepared_statement.hpp +++ /dev/null @@ -1,208 +0,0 @@ -// -// Copyright (c) 2019-2022 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 BOOST_MYSQL_IMPL_PREPARED_STATEMENT_HPP -#define BOOST_MYSQL_IMPL_PREPARED_STATEMENT_HPP - -#pragma once - -#include -#include -#include -#include -#include - - -template -template -void boost::mysql::prepared_statement::check_num_params( - ValueForwardIterator first, - ValueForwardIterator last, - error_code& err, - error_info& info -) const -{ - auto param_count = std::distance(first, last); - if (param_count != num_params()) - { - err = make_error_code(errc::wrong_num_params); - info.set_message(detail::stringize( - "prepared_statement::execute: expected ", num_params(), " params, but got ", param_count)); - } -} - - -template -template -boost::mysql::resultset boost::mysql::prepared_statement::execute( - const execute_params& params, - error_code& err, - error_info& info -) -{ - assert(valid()); - - mysql::resultset res; - detail::clear_errors(err, info); - - // Verify we got passed the right number of params - check_num_params(params.first(), params.last(), err, info); - if (!err) - { - detail::execute_statement( - *channel_, - stmt_msg_.statement_id, - params.first(), - params.last(), - res, - err, - info - ); - } - - return res; -} - -template -template -boost::mysql::resultset boost::mysql::prepared_statement::execute( - const execute_params& params -) -{ - detail::error_block blk; - auto res = execute(params, blk.err, blk.info); - blk.check(); - return res; -} - -// Helper for async_execute -template -struct boost::mysql::prepared_statement::async_execute_initiation -{ - template - struct error_handler - { - error_code err; - HandlerType h; - - void operator()() - { - std::forward(h)(err, resultset()); - } - }; - - template - void operator()( - HandlerType&& handler, - error_code err, - error_info& info, - prepared_statement& stmt, - ValueForwardIterator params_first, - ValueForwardIterator params_last - ) const - { - if (err) - { - auto executor = boost::asio::get_associated_executor( - handler, - stmt.next_layer().get_executor() - ); - - boost::asio::post(boost::asio::bind_executor( - executor, - error_handler{err, std::forward(handler)} - )); - } - else - { - // Actually execute the statement - detail::async_execute_statement( - *stmt.channel_, - stmt.stmt_msg_.statement_id, - params_first, - params_last, - std::forward(handler), - info - ); - } - } -}; - -template -template ) -) CompletionToken> -BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( - CompletionToken, - void(boost::mysql::error_code, boost::mysql::resultset) -) -boost::mysql::prepared_statement::async_execute( - const execute_params& params, - error_info& output_info, - CompletionToken&& token -) -{ - output_info.clear(); - assert(valid()); - - // Check we got passed the right number of params - error_code err; - check_num_params(params.first(), params.last(), err, output_info); - - return boost::asio::async_initiate)>( - async_execute_initiation(), - token, - err, - std::ref(output_info), - std::ref(*this), - params.first(), - params.last() - ); -} - -template -void boost::mysql::prepared_statement::close( - error_code& code, - error_info& info -) -{ - assert(valid()); - detail::clear_errors(code, info); - detail::close_statement(*channel_, id(), code, info); -} - -template -void boost::mysql::prepared_statement::close() -{ - assert(valid()); - detail::error_block blk; - detail::close_statement(*channel_, id(), blk.err, blk.info); - blk.check(); -} - -template -template -BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( - CompletionToken, - void(boost::mysql::error_code) -) -boost::mysql::prepared_statement::async_close( - error_info& output_info, - CompletionToken&& token -) -{ - assert(valid()); - output_info.clear(); - return detail::async_close_statement( - *channel_, - id(), - std::forward(token), - output_info - ); -} - -#endif /* INCLUDE_BOOST_MYSQL_IMPL_PREPARED_STATEMENT_HPP_ */ diff --git a/include/boost/mysql/prepared_statement.hpp b/include/boost/mysql/prepared_statement.hpp index e45c13ed..6b3a69ac 100644 --- a/include/boost/mysql/prepared_statement.hpp +++ b/include/boost/mysql/prepared_statement.hpp @@ -43,10 +43,6 @@ class prepared_statement { bool valid_ {false}; detail::com_stmt_prepare_ok_packet stmt_msg_; - - template - void check_num_params(ValueForwardIterator first, ValueForwardIterator last, error_code& err, error_info& info) const; - public: /** * \brief Default constructor.