diff --git a/include/boost/mysql/connection.hpp b/include/boost/mysql/connection.hpp index 249102a5..d8f50572 100644 --- a/include/boost/mysql/connection.hpp +++ b/include/boost/mysql/connection.hpp @@ -9,17 +9,20 @@ #define BOOST_MYSQL_CONNECTION_HPP #include -#include #ifndef BOOST_MYSQL_DOXYGEN // For some arcane reason, Doxygen fails to expand Asio macros without this -#include +#include #include #include +#include #include #include #include #include +#include +#include +#include #endif @@ -61,7 +64,7 @@ template < class connection { std::unique_ptr> channel_; -protected: + detail::channel& get_channel() noexcept { assert(valid()); @@ -338,7 +341,7 @@ public: * before calling any function that involves communication with the server over this * connection. Otherwise, the results are undefined. */ - resultset query(boost::string_view query_string, error_code&, error_info&); + void query(boost::string_view query_string, resultset& result, error_code&, error_info&); /** * \brief Executes a SQL text query (sync with exceptions version). @@ -348,7 +351,7 @@ public: * before calling any function that involves communication with the server over this * connection. Otherwise, the results are undefined. */ - resultset query(boost::string_view query_string); + void query(boost::string_view query_string, resultset& result); /** * \brief Executes a SQL text query (async without [reflink error_info] version). @@ -362,19 +365,18 @@ public: * `void(boost::mysql::error_code, boost::mysql::resultset)`. */ template < - BOOST_ASIO_COMPLETION_TOKEN_FOR( - void(::boost::mysql::error_code, ::boost::mysql::resultset) - ) + BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code)) CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) > - BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, resultset)) + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) async_query( boost::string_view query_string, + resultset& result, CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) ) { - return async_query(query_string, shared_info(), std::forward(token)); + return async_query(query_string, result, shared_info(), std::forward(token)); } /** @@ -389,15 +391,14 @@ public: * `void(boost::mysql::error_code, boost::mysql::resultset)`. */ template < - BOOST_ASIO_COMPLETION_TOKEN_FOR( - void(::boost::mysql::error_code, ::boost::mysql::resultset) - ) + BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code)) CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) > - BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, resultset)) + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) async_query( boost::string_view query_string, + resultset& result, error_info& output_info, CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) ); @@ -408,7 +409,7 @@ public: * Prepared statements are only valid while the connection object on which * this function was called is alive and open. */ - prepared_statement prepare_statement(boost::string_view statement, error_code&, error_info&); + void prepare_statement(boost::string_view statement, prepared_statement& result, error_code&, error_info&); /** * \brief Prepares a statement (sync with exceptions version). @@ -416,7 +417,7 @@ public: * Prepared statements are only valid while the connection object on which * this function was called is alive and open. */ - prepared_statement prepare_statement(boost::string_view statement); + void prepare_statement(boost::string_view statement, prepared_statement& result); /** * \brief Prepares a statement (async without [reflink error_info] version). @@ -428,19 +429,18 @@ public: * `void(boost::mysql::error_code, boost::mysql::prepared_statement)` */ template < - BOOST_ASIO_COMPLETION_TOKEN_FOR( - void(::boost::mysql::error_code, ::boost::mysql::prepared_statement) - ) + BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code)) CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) > - BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, prepared_statement)) + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) async_prepare_statement( boost::string_view statement, + prepared_statement& result, CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) ) { - return async_prepare_statement(statement, shared_info(), std::forward(token)); + return async_prepare_statement(statement, result, shared_info(), std::forward(token)); } /** @@ -453,15 +453,477 @@ public: * `void(boost::mysql::error_code, boost::mysql::prepared_statement)` */ template < - BOOST_ASIO_COMPLETION_TOKEN_FOR( - void(::boost::mysql::error_code, ::boost::mysql::prepared_statement) - ) + BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code)) CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) > - BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, prepared_statement)) + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) async_prepare_statement( boost::string_view statement, + prepared_statement& result, + error_info& output_info, + CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) + ); + + + /** + * \brief Executes a statement (collection, sync with error code version). + * \details + * ValueCollection should meet the [reflink ValueCollection] requirements. + * + * After this function has returned, you should read the entire resultset + * before calling any function that involves communication with the server over this + * connection. Otherwise, the results are undefined. + */ + template > + void execute_statement( + const prepared_statement& statement, + const ValueCollection& params, + resultset& result, + error_code& err, + error_info& info + ) + { + return execute_statement(make_execute_params(statement, params), result, err, info); + } + + /** + * \brief Executes a statement (collection, sync with exceptions version). + * \details + * ValueCollection should meet the [reflink ValueCollection] requirements. + * + * After this function has returned, you should read the entire resultset + * before calling any function that involves communication with the server over this + * connection. Otherwise, the results are undefined. + */ + template > + void execute_statement( + const prepared_statement& statement, + const ValueCollection& params, + resultset& result + ) + { + return execute_statement(make_execute_params(statement, params), result); + } + + /** + * \brief Executes a statement (collection, + * async without [reflink error_info] version). + * \details + * ValueCollection should meet the [reflink ValueCollection] requirements. + * + * After this operation completes, you should read the entire resultset + * before calling any function that involves communication with the server over this + * connection. Otherwise, the results are undefined. + * It is __not__ necessary to keep the collection of parameters or the + * values they may point to alive after the initiating function returns. + * + * The handler signature for this operation is + * `void(boost::mysql::error_code, boost::mysql::resultset)`. + */ + template < + class ValueCollection, + BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code)) + CompletionToken + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type), + class EnableIf = detail::enable_if_value_collection + > + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) + async_execute_statement( + const prepared_statement& statement, + const ValueCollection& params, + resultset& result, + CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) + ) + { + return async_execute_statement( + make_execute_params(statement, params), + result, + std::forward(token) + ); + } + + /** + * \brief Executes a statement (collection, + * async with [reflink error_info] version). + * \details + * ValueCollection should meet the [reflink ValueCollection] requirements. + * + * After this operation completes, you should read the entire resultset + * before calling any function that involves communication with the server over this + * connection. Otherwise, the results are undefined. + * It is __not__ necessary to keep the collection of parameters or the + * values they may point to alive after the initiating function returns. + * + * The handler signature for this operation is + * `void(boost::mysql::error_code, boost::mysql::resultset)`. + */ + template < + class ValueCollection, + BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code)) + CompletionToken + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type), + class EnableIf = detail::enable_if_value_collection + > + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) + async_execute_statement( + const prepared_statement& statement, + const ValueCollection& params, + resultset& result, + error_info& output_info, + CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) + ) + { + return async_execute_statement( + make_execute_params(statement, params), + result, + output_info, + std::forward(token) + ); + } + + + /** + * \brief Executes a statement (`execute_params`, sync with error code version). + * \details + * ValueForwardIterator should meet the [reflink ValueForwardIterator] requirements. + * The range \\[`params.first()`, `params.last()`) will be used as parameters for + * statement execution. They should be a valid iterator range. + * + * After this function has returned, you should read the entire resultset + * before calling any function that involves communication with the server over this + * connection. Otherwise, the results are undefined. + */ + template + void execute_statement( + const execute_params& params, + resultset& result, + error_code& ec, + error_info& info + ); + + /** + * \brief Executes a statement (`execute_params`, sync with exceptions version). + * \details + * ValueForwardIterator should meet the [reflink ValueForwardIterator] requirements. + * The range \\[`params.first()`, `params.last()`) will be used as parameters for + * statement execution. They should be a valid iterator range. + * + * After this function has returned, you should read the entire resultset + * before calling any function that involves communication with the server over this + * connection. Otherwise, the results are undefined. + */ + template + void execute_statement( + const execute_params& params, + resultset& result + ); + + /** + * \brief Executes a statement (`execute_params`, + * async without [reflink error_info] version). + * \details + * ValueForwardIterator should meet the [reflink ValueForwardIterator] requirements. + * The range \\[`params.first()`, `params.last()`) will be used as parameters for + * statement execution. They should be a valid iterator range. + * + * After this operation completes, you should read the entire resultset + * before calling any function that involves communication with the server over this + * connection. Otherwise, the results are undefined. + * + * It is __not__ necessary to keep the objects in + * \\[`params.first()`, `params.last()`) or the + * values they may point to alive after the initiating function returns. + * + * The handler signature for this operation is + * `void(boost::mysql::error_code, boost::mysql::resultset)`. + */ + template < + class ValueForwardIterator, + BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code)) + CompletionToken + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) + > + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) + async_execute_statement( + const execute_params& params, + resultset& result, + CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) + ) + { + return async_execute(params, result, shared_info(), std::forward(token)); + } + + /** + * \brief Executes a statement (`execute_params`, + * async with [reflink error_info] version). + * \details + * ValueForwardIterator should meet the [reflink ValueForwardIterator] requirements. + * The range \\[`params.first()`, `params.last()`) will be used as parameters for + * statement execution. They should be a valid iterator range. + * + * After this operation completes, you should read the entire resultset + * before calling any function that involves communication with the server over this + * connection. Otherwise, the results are undefined. + * + * It is __not__ necessary to keep the objects in + * \\[`params.first()`, `params.last()`) or the + * values they may point to alive after the initiating function returns. + * + * The handler signature for this operation is + * `void(boost::mysql::error_code, boost::mysql::resultset)`. + */ + template < + class ValueForwardIterator, + BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code)) + CompletionToken + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) + > + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) + async_execute_statement( + const execute_params& params, + resultset& result, + error_info& output_info, + CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) + ); + + + /** + * \brief Closes a prepared statement, deallocating it from the server + (sync with error code version). + * \details + * After calling this function, no further functions may be called on this prepared + * statement, other than assignment. Failing to do so results in undefined behavior. + */ + void close_statement(const prepared_statement&, error_code&, error_info&); + + /** + * \brief Closes a prepared statement, deallocating it from the server + (sync with exceptions version). + * \details + * After calling this function, no further functions may be called on this prepared + * statement, other than assignment. Failing to do so results in undefined behavior. + */ + void close_statement(const prepared_statement&); + + /** + * \brief Closes a prepared statement, deallocating it from the server + (async without [reflink error_info] version). + * \details + * After the operation completes, no further functions may be called on this prepared + * statement, other than assignment. Failing to do so results in undefined behavior. + * + * The handler signature for this operation is `void(boost::mysql::error_code)`. + */ + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code)) + CompletionToken + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) + > + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) + async_close_statement( + const prepared_statement& stmt, + CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) + ) + { + return async_close_statement(stmt, shared_info(), std::forward(token)); + } + + /** + * \brief Closes a prepared statement, deallocating it from the server + (async with [reflink error_info] version). + * \details + * After the operation completes, no further functions may be called on this prepared + * statement, other than assignment. Failing to do so results in undefined behavior. + * + * The handler signature for this operation is `void(boost::mysql::error_code)`. + */ + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code)) + CompletionToken + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) + > + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) + async_close_statement( + const prepared_statement& stmt, + error_info& output_info, + CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) + ); + + + /** + * \brief Reads a single row (sync with error code version). + * \details Returns `true` if a row was read successfully, `false` if + * there was an error or there were no more rows to read. Calling + * this function on a complete resultset always returns `false`. + * + * If the operation succeeds and returns `true`, the new row will be + * read against `output`, possibly reusing its memory. If the operation + * succeeds but returns `false`, `output` will be set to the empty row + * (as if [refmem row clear] was called). If the operation fails, + * `output` is left in a valid but undetrmined state. + */ + bool read_one_row(resultset& resultset, row& output, error_code& err, error_info& info); + + /** + * \brief Reads a single row (sync with exceptions version). + * \details Returns `true` if a row was read successfully, `false` if + * there was an error or there were no more rows to read. Calling + * this function on a complete resultset always returns `false`. + * + * If the operation succeeds and returns `true`, the new row will be + * read against `output`, possibly reusing its memory. If the operation + * succeeds but returns `false`, `output` will be set to the empty row + * (as if [refmem row clear] was called). If the operation fails, + * `output` is left in a valid but undetrmined state. + */ + bool read_one_row(resultset& resultset, row& output); + + /** + * \brief Reads a single row (async without [reflink error_info] version). + * \details Completes with `true` if a row was read successfully, and with `false` if + * there was an error or there were no more rows to read. Calling + * this function on a complete resultset always returns `false`. + * + * If the operation succeeds and completes with `true`, the new row will be + * read against `output`, possibly reusing its memory. If the operation + * succeeds but completes with `false`, `output` will be set to the empty row + * (as if [refmem row clear] was called). If the operation fails, + * `output` is left in a valid but undetrmined state. + * + * The handler signature for this operation is + * `void(boost::mysql::error_code, bool)`. + */ + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, bool)) + CompletionToken + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) + > + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, bool)) + async_read_one_row( + resultset& resultset, + row& output, + CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) + ) + { + return async_read_one_row(resultset, output, shared_info(), std::forward(token)); + } + + /** + * \brief Reads a single row (async with [reflink error_info] version). + * \details Completes with `true` if a row was read successfully, and with `false` if + * there was an error or there were no more rows to read. Calling + * this function on a complete resultset always returns `false`. + * + * If the operation succeeds and completes with `true`, the new row will be + * read against `output`, possibly reusing its memory. If the operation + * succeeds but completes with `false`, `output` will be set to the empty row + * (as if [refmem row clear] was called). If the operation fails, + * `output` is left in a valid but undetrmined state. + * + * The handler signature for this operation is + * `void(boost::mysql::error_code, bool)`. + */ + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, bool)) + CompletionToken + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) + > + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, bool)) + async_read_one_row( + resultset& resultset, + row& output, + error_info& output_info, + CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) + ); + + bool read_some_rows(resultset& resultset, rows_view& output, error_code& err, error_info& info); + bool read_some_rows(resultset& resultset, rows_view& output); + + /** + * \brief Reads several rows, up to a maximum + * (async without [reflink error_info] version). + * \details + * The handler signature for this operation is + * `void(boost::mysql::error_code, std::vector)`. + */ + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, bool)) + CompletionToken + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) + > + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, bool)) + async_read_some_rows( + resultset& resultset, + rows_view& output, + CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) + ) + { + return async_read_some_rows(resultset, output, shared_info(), std::forward(token)); + } + + /** + * \brief Reads several rows, up to a maximum + * (async with [reflink error_info] version). + * \details + * The handler signature for this operation is + * `void(boost::mysql::error_code, std::vector)`. + */ + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, bool)) + CompletionToken + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) + > + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, bool)) + async_read_some_rows( + resultset& resultset, + rows_view& output, + error_info& output_info, + CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) + ); + + /// Reads all available rows (sync with error code version). + void read_all_rows(resultset& resultset, rows& output, error_code& err, error_info& info); + + /// Reads all available rows (sync with exceptions version). + void read_all_rows(resultset& resultset, rows& output); + + /** + * \brief Reads all available rows (async without [reflink error_info] version). + * \details + * The handler signature for this operation is + * `void(boost::mysql::error_code, std::vector)`. + */ + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code)) + CompletionToken + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) + > + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) + async_read_all_rows( + resultset& resultset, + rows& output, + CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) + ) + { + return async_read_all_rows(resultset, output, shared_info(), std::forward(token)); + } + + /** + * \brief Reads all available rows (async with [reflink error_info] version). + * \details + * The handler signature for this operation is + * `void(boost::mysql::error_code, std::vector)`. + */ + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code)) + CompletionToken + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) + > + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) + async_read_all_rows( + resultset& resultset, + rows& output, error_info& output_info, CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) ); diff --git a/include/boost/mysql/detail/channel/channel.hpp b/include/boost/mysql/detail/channel/channel.hpp index 99e5fe87..d37d00b2 100644 --- a/include/boost/mysql/detail/channel/channel.hpp +++ b/include/boost/mysql/detail/channel/channel.hpp @@ -114,16 +114,6 @@ public: std::uint8_t& shared_sequence_number() noexcept { return shared_sequence_number_; } }; -// Helper class to get move semantics right for some I/O object types -template -struct null_channel_deleter -{ - void operator()(channel*) const noexcept {} -}; - -template -using channel_observer_ptr = std::unique_ptr, null_channel_deleter>; - } // detail } // mysql } // boost diff --git a/include/boost/mysql/detail/network_algorithms/common.hpp b/include/boost/mysql/detail/network_algorithms/common.hpp index 93a836a7..ba672f31 100644 --- a/include/boost/mysql/detail/network_algorithms/common.hpp +++ b/include/boost/mysql/detail/network_algorithms/common.hpp @@ -10,7 +10,7 @@ #include #include -#include +#include #include namespace boost { diff --git a/include/boost/mysql/detail/network_algorithms/handshake.hpp b/include/boost/mysql/detail/network_algorithms/handshake.hpp index 0a61815a..781cbca3 100644 --- a/include/boost/mysql/detail/network_algorithms/handshake.hpp +++ b/include/boost/mysql/detail/network_algorithms/handshake.hpp @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include #include diff --git a/include/boost/mysql/detail/network_algorithms/impl/quit_connection.hpp b/include/boost/mysql/detail/network_algorithms/impl/quit_connection.hpp index 4144431a..25e86dfa 100644 --- a/include/boost/mysql/detail/network_algorithms/impl/quit_connection.hpp +++ b/include/boost/mysql/detail/network_algorithms/impl/quit_connection.hpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include namespace boost { diff --git a/include/boost/mysql/execute_params.hpp b/include/boost/mysql/execute_params.hpp index d6cbb3d8..af529c63 100644 --- a/include/boost/mysql/execute_params.hpp +++ b/include/boost/mysql/execute_params.hpp @@ -9,6 +9,7 @@ #define BOOST_MYSQL_EXECUTE_PARAMS_HPP #include +#include #include #include #include @@ -16,6 +17,7 @@ namespace boost { namespace mysql { + /** * \brief Represents the parameters required to execute a [reflink prepared_statement]. * \details In essence, this class contains an iterator range \\[first, last), pointing @@ -32,14 +34,27 @@ namespace mysql { template class execute_params { + std::uint32_t statement_id_; ValueForwardIterator first_; ValueForwardIterator last_; static_assert(detail::is_value_forward_iterator::value, "ValueForwardIterator requirements not met"); public: /// Constructor. - constexpr execute_params(ValueForwardIterator first, ValueForwardIterator last) : - first_(first), last_(last) {} + constexpr execute_params( + std::uint32_t statement_id, + ValueForwardIterator first, + ValueForwardIterator last + ) : + statement_id_(statement_id), + first_(first), + last_(last) + { + } + + 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_; } @@ -65,11 +80,26 @@ template < > constexpr execute_params make_execute_params( + std::uint32_t statement_id, ValueForwardIterator first, ValueForwardIterator last ) { - return execute_params(first, last); + return execute_params(statement_id, first, last); +} + +template < + class ValueForwardIterator, + class EnableIf = detail::enable_if_value_forward_iterator +> +constexpr execute_params +make_execute_params( + const prepared_statement& stmt, + ValueForwardIterator first, + ValueForwardIterator last +) +{ + return execute_params(stmt.id(), first, last); } /** @@ -88,8 +118,20 @@ constexpr auto make_execute_params( return make_execute_params(std::begin(col), std::end(col)); } +template < + class ValueCollection, + class EnableIf = detail::enable_if_value_collection +> +constexpr auto make_execute_params( + const prepared_statement& stmt, + const ValueCollection& col +) -> execute_params +{ + return make_execute_params(stmt.id(), std::begin(col), std::end(col)); } -} + +} // mysql +} // boost #endif diff --git a/include/boost/mysql/impl/metadata.ipp b/include/boost/mysql/impl/metadata.ipp index 0b4447de..5989d71a 100644 --- a/include/boost/mysql/impl/metadata.ipp +++ b/include/boost/mysql/impl/metadata.ipp @@ -89,7 +89,7 @@ inline boost::mysql::field_type boost::mysql::field_metadata::type() const noexc { if (field_type_ == field_type::_not_computed) { - field_type_ = detail::compute_field_type(msg_.type, msg_.flags); + field_type_ = detail::compute_field_type(type_, flags_); assert(field_type_ != field_type::_not_computed); } return field_type_; diff --git a/include/boost/mysql/metadata.hpp b/include/boost/mysql/metadata.hpp index 62b73d15..982a5f34 100644 --- a/include/boost/mysql/metadata.hpp +++ b/include/boost/mysql/metadata.hpp @@ -11,6 +11,8 @@ #include #include #include +#include +#include namespace boost { namespace mysql { @@ -23,10 +25,19 @@ namespace mysql { */ class field_metadata { - detail::column_definition_packet msg_; + std::string schema_; + std::string table_; // virtual table + std::string org_table_; // physical table + std::string name_; // virtual column name + std::string org_name_; // physical column name + collation character_set_; + std::uint32_t column_length_; // maximum length of the field + detail::protocol_field_type type_; // type of the column as defined in enum_field_types + std::uint16_t flags_; // Flags as defined in Column Definition Flags + std::uint8_t decimals_; // max shown decimal digits. 0x00 for int/static strings; 0x1f for dynamic strings, double, float mutable field_type field_type_ { field_type::_not_computed }; - bool flag_set(std::uint16_t flag) const noexcept { return msg_.flags & flag; } + bool flag_set(std::uint16_t flag) const noexcept { return flags_ & flag; } public: /** * \brief Default constructor. @@ -37,25 +48,39 @@ public: #ifndef BOOST_MYSQL_DOXYGEN // Private, do not use. - field_metadata(const detail::column_definition_packet& msg) noexcept: msg_(msg) {}; + // TODO: hide this + field_metadata(const detail::column_definition_packet& msg, bool copy_strings) : + schema_(copy_strings ? msg.schema.value : boost::string_view()), + table_(copy_strings ? msg.table.value : boost::string_view()), + org_table_(copy_strings ? msg.org_table.value : boost::string_view()), + name_(copy_strings ? msg.name.value : boost::string_view()), + org_name_(copy_strings ? msg.org_name.value : boost::string_view()), + character_set_(msg.character_set), + column_length_(msg.column_length), + type_(msg.type), + flags_(msg.flags), + decimals_(msg.decimals) + { + + } #endif /// Returns the name of the database (schema) the field belongs to. - boost::string_view database() const noexcept { return msg_.schema.value; } + boost::string_view database() const noexcept { return schema_; } /** * \brief Returns the name of the virtual table the field belongs to. * \details If the table was aliased, this will be the name of the alias * (e.g. in `"SELECT * FROM employees emp"`, `table()` will be `"emp"`). */ - boost::string_view table() const noexcept { return msg_.table.value; } + boost::string_view table() const noexcept { return table_; } /** * \brief Returns the name of the physical table the field belongs to. * \details E.g. in `"SELECT * FROM employees emp"`, * `original_table()` will be `"employees"`. */ - boost::string_view original_table() const noexcept { return msg_.org_table.value; } + boost::string_view original_table() const noexcept { return org_table_; } /** * \brief Returns the actual name of the field. @@ -63,31 +88,31 @@ public: * (e.g. in `"SELECT id AS employee_id FROM employees"`, * `field_name()` will be `"employee_id"`). */ - boost::string_view field_name() const noexcept { return msg_.name.value; } + boost::string_view field_name() const noexcept { return name_; } /** * \brief Returns the original (physical) name of the field. * \details E.g. in `"SELECT id AS employee_id FROM employees"`, * `original_field_name()` will be `"id"`. */ - boost::string_view original_field_name() const noexcept { return msg_.org_name.value; } + boost::string_view original_field_name() const noexcept { return org_name_; } /// Returns the character set ([reflink collation]) for the column. - collation character_set() const noexcept { return msg_.character_set; } + collation character_set() const noexcept { return character_set_; } /// Returns the maximum length of the field. - unsigned column_length() const noexcept { return msg_.column_length; } + unsigned column_length() const noexcept { return column_length_; } #ifndef BOOST_MYSQL_DOXYGEN - // Private, do not use - detail::protocol_field_type protocol_type() const noexcept { return msg_.type; } + // Private, do not use. TODO: hide this + detail::protocol_field_type protocol_type() const noexcept { return type_; } #endif /// Returns the type of the field (see [reflink field_type] for more info). field_type type() const noexcept; /// Returns the number of decimals of the field. - unsigned decimals() const noexcept { return msg_.decimals; } + unsigned decimals() const noexcept { return decimals_; } /// Returns `true` if the field is not allowed to be NULL, `false` if it is nullable. bool is_not_null() const noexcept { return flag_set(detail::column_flags::not_null); } diff --git a/include/boost/mysql/prepared_statement.hpp b/include/boost/mysql/prepared_statement.hpp index b9a2ff64..e45c13ed 100644 --- a/include/boost/mysql/prepared_statement.hpp +++ b/include/boost/mysql/prepared_statement.hpp @@ -8,12 +8,11 @@ #ifndef BOOST_MYSQL_PREPARED_STATEMENT_HPP #define BOOST_MYSQL_PREPARED_STATEMENT_HPP -#include -#include -#include + #include -#include -#include +#include +#include +#include namespace boost { namespace mysql { @@ -40,18 +39,14 @@ constexpr std::array no_statement_params {}; * whose parent connection has been closed or destroyed results * in undefined behavior. */ -template class prepared_statement { - detail::channel_observer_ptr channel_; + 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; - error_info& shared_info() noexcept { assert(channel_); return channel_->shared_info(); } - - struct async_execute_initiation; public: /** * \brief Default constructor. @@ -59,329 +54,28 @@ public: */ prepared_statement() = default; - /** - * \brief Move constructor. - * \details The constructed statement will be valid if `other` is valid. - * After this operation, `other` is guaranteed to be invalid. - */ - prepared_statement(prepared_statement&& other) = default; - - /** - * \brief Move assignment. - * \details The assigned-to statement will be valid if `other` is valid. - */ - prepared_statement& operator=(prepared_statement&& rhs) = default; - #ifndef BOOST_MYSQL_DOXYGEN - prepared_statement(const prepared_statement&) = delete; - prepared_statement& operator=(const prepared_statement&) = delete; - - // Private. Do not use. - prepared_statement(detail::channel& chan, const detail::com_stmt_prepare_ok_packet& msg) noexcept: - channel_(&chan), stmt_msg_(msg) {} + // Private. Do not use. TODO: hide this + prepared_statement(const detail::com_stmt_prepare_ok_packet& msg) noexcept: + valid_(true), stmt_msg_(msg) {} #endif - /// The executor type associated to this object. - using executor_type = typename Stream::executor_type; - - /// Retrieves the executor associated to this object. - executor_type get_executor() { assert(channel_); return channel_->get_executor(); } - - /// Retrieves the stream object associated with the underlying connection. - Stream& next_layer() noexcept { assert(channel_); return channel_->next_layer(); } - - /// Retrieves the stream object associated with the underlying connection. - const Stream& next_layer() const noexcept { assert(channel_); return channel_->next_layer(); } - /** * \brief Returns `true` if the statement is not a default-constructed object. * \details Calling any function other than assignment on an statement for which * this function returns `false` results in undefined behavior. */ - bool valid() const noexcept { return channel_ != nullptr; } + bool valid() const noexcept { return valid_; } /// Returns a server-side identifier for the statement (unique in a per-connection basis). - unsigned id() const noexcept { assert(valid()); return stmt_msg_.statement_id; } + std::uint32_t id() const noexcept { assert(valid()); return stmt_msg_.statement_id; } /// Returns the number of parameters that should be provided when executing the statement. unsigned num_params() const noexcept { assert(valid()); return stmt_msg_.num_params; } - /** - * \brief Executes a statement (collection, sync with error code version). - * \details - * ValueCollection should meet the [reflink ValueCollection] requirements. - * - * After this function has returned, you should read the entire resultset - * before calling any function that involves communication with the server over this - * connection. Otherwise, the results are undefined. - */ - template > - resultset execute(const ValueCollection& params, error_code& err, error_info& info) - { - return execute(make_execute_params(params), err, info); - } - - /** - * \brief Executes a statement (collection, sync with exceptions version). - * \details - * ValueCollection should meet the [reflink ValueCollection] requirements. - * - * After this function has returned, you should read the entire resultset - * before calling any function that involves communication with the server over this - * connection. Otherwise, the results are undefined. - */ - template > - resultset execute(const ValueCollection& params) - { - return execute(make_execute_params(params)); - } - - /** - * \brief Executes a statement (collection, - * async without [reflink error_info] version). - * \details - * ValueCollection should meet the [reflink ValueCollection] requirements. - * - * After this operation completes, you should read the entire resultset - * before calling any function that involves communication with the server over this - * connection. Otherwise, the results are undefined. - * It is __not__ necessary to keep the collection of parameters or the - * values they may point to alive after the initiating function returns. - * - * The handler signature for this operation is - * `void(boost::mysql::error_code, boost::mysql::resultset)`. - */ - template < - class ValueCollection, - BOOST_ASIO_COMPLETION_TOKEN_FOR( - void(::boost::mysql::error_code, ::boost::mysql::resultset) - ) - CompletionToken - BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type), - class EnableIf = detail::enable_if_value_collection - > - BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, resultset)) - async_execute( - const ValueCollection& params, - CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) - ) - { - return async_execute( - make_execute_params(params), - std::forward(token) - ); - } - - /** - * \brief Executes a statement (collection, - * async with [reflink error_info] version). - * \details - * ValueCollection should meet the [reflink ValueCollection] requirements. - * - * After this operation completes, you should read the entire resultset - * before calling any function that involves communication with the server over this - * connection. Otherwise, the results are undefined. - * It is __not__ necessary to keep the collection of parameters or the - * values they may point to alive after the initiating function returns. - * - * The handler signature for this operation is - * `void(boost::mysql::error_code, boost::mysql::resultset)`. - */ - template < - class ValueCollection, - BOOST_ASIO_COMPLETION_TOKEN_FOR( - void(::boost::mysql::error_code, ::boost::mysql::resultset) - ) - CompletionToken - BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type), - class EnableIf = detail::enable_if_value_collection - > - BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, resultset)) - async_execute( - const ValueCollection& params, - error_info& output_info, - CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) - ) - { - return async_execute( - make_execute_params(params), - output_info, - std::forward(token) - ); - } - - - /** - * \brief Executes a statement (`execute_params`, sync with error code version). - * \details - * ValueForwardIterator should meet the [reflink ValueForwardIterator] requirements. - * The range \\[`params.first()`, `params.last()`) will be used as parameters for - * statement execution. They should be a valid iterator range. - * - * After this function has returned, you should read the entire resultset - * before calling any function that involves communication with the server over this - * connection. Otherwise, the results are undefined. - */ - template - resultset execute(const execute_params& params, - error_code&, error_info&); - - /** - * \brief Executes a statement (`execute_params`, sync with exceptions version). - * \details - * ValueForwardIterator should meet the [reflink ValueForwardIterator] requirements. - * The range \\[`params.first()`, `params.last()`) will be used as parameters for - * statement execution. They should be a valid iterator range. - * - * After this function has returned, you should read the entire resultset - * before calling any function that involves communication with the server over this - * connection. Otherwise, the results are undefined. - */ - template - resultset execute(const execute_params& params); - - /** - * \brief Executes a statement (`execute_params`, - * async without [reflink error_info] version). - * \details - * ValueForwardIterator should meet the [reflink ValueForwardIterator] requirements. - * The range \\[`params.first()`, `params.last()`) will be used as parameters for - * statement execution. They should be a valid iterator range. - * - * After this operation completes, you should read the entire resultset - * before calling any function that involves communication with the server over this - * connection. Otherwise, the results are undefined. - * - * It is __not__ necessary to keep the objects in - * \\[`params.first()`, `params.last()`) or the - * values they may point to alive after the initiating function returns. - * - * The handler signature for this operation is - * `void(boost::mysql::error_code, boost::mysql::resultset)`. - */ - template < - class ValueForwardIterator, - BOOST_ASIO_COMPLETION_TOKEN_FOR( - void(::boost::mysql::error_code, ::boost::mysql::resultset) - ) - CompletionToken - BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) - > - BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, resultset)) - async_execute( - const execute_params& params, - CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) - ) - { - return async_execute(params, shared_info(), std::forward(token)); - } - - /** - * \brief Executes a statement (`execute_params`, - * async with [reflink error_info] version). - * \details - * ValueForwardIterator should meet the [reflink ValueForwardIterator] requirements. - * The range \\[`params.first()`, `params.last()`) will be used as parameters for - * statement execution. They should be a valid iterator range. - * - * After this operation completes, you should read the entire resultset - * before calling any function that involves communication with the server over this - * connection. Otherwise, the results are undefined. - * - * It is __not__ necessary to keep the objects in - * \\[`params.first()`, `params.last()`) or the - * values they may point to alive after the initiating function returns. - * - * The handler signature for this operation is - * `void(boost::mysql::error_code, boost::mysql::resultset)`. - */ - template < - class ValueForwardIterator, - BOOST_ASIO_COMPLETION_TOKEN_FOR( - void(::boost::mysql::error_code, ::boost::mysql::resultset) - ) - CompletionToken - BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) - > - BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, resultset)) - async_execute( - const execute_params& params, - error_info& output_info, - CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) - ); - - /** - * \brief Closes a prepared statement, deallocating it from the server - (sync with error code version). - * \details - * After calling this function, no further functions may be called on this prepared - * statement, other than assignment. Failing to do so results in undefined behavior. - */ - void close(error_code&, error_info&); - - /** - * \brief Closes a prepared statement, deallocating it from the server - (sync with exceptions version). - * \details - * After calling this function, no further functions may be called on this prepared - * statement, other than assignment. Failing to do so results in undefined behavior. - */ - void close(); - - /** - * \brief Closes a prepared statement, deallocating it from the server - (async without [reflink error_info] version). - * \details - * After the operation completes, no further functions may be called on this prepared - * statement, other than assignment. Failing to do so results in undefined behavior. - * - * The handler signature for this operation is `void(boost::mysql::error_code)`. - */ - template < - BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code)) - CompletionToken - BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) - > - BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) - async_close(CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) - { - return async_close(shared_info(), std::forward(token)); - } - - /** - * \brief Closes a prepared statement, deallocating it from the server - (async with [reflink error_info] version). - * \details - * After the operation completes, no further functions may be called on this prepared - * statement, other than assignment. Failing to do so results in undefined behavior. - * - * The handler signature for this operation is `void(boost::mysql::error_code)`. - */ - template < - BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code)) - CompletionToken - BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) - > - BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code)) - async_close( - error_info& output_info, - CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) - ); - - /// Rebinds the prepared statement type to another executor. - template - struct rebind_executor - { - /// The prepared statement type when rebound to the specified executor. - using other = prepared_statement< - typename Stream:: template rebind_executor::other - >; - }; }; } // mysql } // boost -#include - #endif /* INCLUDE_BOOST_MYSQL_PREPARED_STATEMENT_HPP_ */ diff --git a/include/boost/mysql/resultset.hpp b/include/boost/mysql/resultset.hpp index 2fcb869d..33f0d22c 100644 --- a/include/boost/mysql/resultset.hpp +++ b/include/boost/mysql/resultset.hpp @@ -11,10 +11,14 @@ #include #include #include -#include +#include #include #include // deserialize_row_fn +#include #include +#include +#include +#include namespace boost { namespace mysql { @@ -32,281 +36,107 @@ namespace mysql { * and moved-from resultsets. Calling any member function on an invalid * resultset, other than assignment, results in undefined behavior. */ -template < - class Stream -> class resultset { + class ok_packet_data + { + bool has_data_ {false}; + std::uint64_t affected_rows_; + std::uint64_t last_insert_id_; + std::uint16_t warnings_; + std::string info_; + public: + ok_packet_data() = default; + ok_packet_data(const detail::ok_packet& pack) + { + assign(pack); + } + + void reset() noexcept { has_data_ = false; } + void assign(const detail::ok_packet& pack) + { + has_data_ = true; + affected_rows_ = pack.affected_rows.value; + last_insert_id_ = pack.last_insert_id.value; + warnings_ = pack.warnings; + info_.assign(pack.info.value.begin(), pack.info.value.end()); + } + + bool has_value() const noexcept { return has_data_; } + std::uint64_t affected_rows() const noexcept { assert(has_data_); return affected_rows_; } + std::uint64_t last_insert_id() const noexcept { assert(has_data_); return last_insert_id_; } + unsigned warning_count() const noexcept { assert(has_data_); return warnings_; } + boost::string_view info() const noexcept { assert(has_data_); return info_; } + }; + + bool valid_ {false}; detail::deserialize_row_fn deserializer_ {}; - detail::channel_observer_ptr channel_; - detail::resultset_metadata meta_; - detail::bytestring ok_packet_buffer_; - detail::ok_packet ok_packet_; - bool eof_received_ {false}; + std::vector meta_; + ok_packet_data ok_packet_; - error_info& shared_info() noexcept { assert(channel_); return channel_->shared_info(); } - - struct read_one_op; - struct read_many_op; - struct read_many_op_impl; - - public: +public: /// \brief Default constructor. /// \details Default constructed resultsets have [refmem resultset valid] return `false`. - resultset(): channel_(nullptr) {}; - - /** - * \brief Move constructor. - * \details The constructed resultset will be valid if `other` is valid. - * After this operation, `other` is guaranteed to be invalid. - */ - resultset(resultset&& other) = default; - - /** - * \brief Move assignment. - * \details The assigned-to resultset will be valid if `other` is valid. - */ - resultset& operator=(resultset&& rhs) = default; + resultset() = default; #ifndef BOOST_MYSQL_DOXYGEN - resultset(const resultset&) = delete; - resultset& operator=(const resultset&) = delete; - - // Private, do not use - resultset(detail::channel& channel, detail::resultset_metadata&& meta, - detail::deserialize_row_fn deserializer): - deserializer_(deserializer), channel_(&channel), meta_(std::move(meta)) {}; - resultset(detail::channel& channel, detail::bytestring&& buffer, - const detail::ok_packet& ok_pack): - channel_(&channel), ok_packet_buffer_(std::move(buffer)), ok_packet_(ok_pack), eof_received_(true) {}; + // Private, do not use. TODO: hide these + resultset(std::vector&& meta, detail::deserialize_row_fn deserializer) noexcept: + valid_(true), + deserializer_(deserializer), + meta_(std::move(meta)) + { + }; + resultset(const detail::ok_packet& ok_pack): + valid_(true), + ok_packet_(ok_pack) + { + }; #endif - /// The executor type associated to the object. - using executor_type = typename detail::channel::executor_type; - - /// Retrieves the executor associated to the object. - executor_type get_executor() { assert(channel_); return channel_->get_executor(); } - - /// Retrieves the stream object associated with the underlying connection. - Stream& next_layer() noexcept { assert(channel_); return channel_->next_layer(); } - - /// Retrieves the stream object associated with the underlying connection. - const Stream& next_layer() const noexcept { assert(channel_); return channel_->next_layer(); } - - /** - * \brief Reads a single row (sync with error code version). - * \details Returns `true` if a row was read successfully, `false` if - * there was an error or there were no more rows to read. Calling - * this function on a complete resultset always returns `false`. - * - * If the operation succeeds and returns `true`, the new row will be - * read against `output`, possibly reusing its memory. If the operation - * succeeds but returns `false`, `output` will be set to the empty row - * (as if [refmem row clear] was called). If the operation fails, - * `output` is left in a valid but undetrmined state. - */ - bool read_one(row& output, error_code& err, error_info& info); - - /** - * \brief Reads a single row (sync with exceptions version). - * \details Returns `true` if a row was read successfully, `false` if - * there was an error or there were no more rows to read. Calling - * this function on a complete resultset always returns `false`. - * - * If the operation succeeds and returns `true`, the new row will be - * read against `output`, possibly reusing its memory. If the operation - * succeeds but returns `false`, `output` will be set to the empty row - * (as if [refmem row clear] was called). If the operation fails, - * `output` is left in a valid but undetrmined state. - */ - bool read_one(row& output); - - /** - * \brief Reads a single row (async without [reflink error_info] version). - * \details Completes with `true` if a row was read successfully, and with `false` if - * there was an error or there were no more rows to read. Calling - * this function on a complete resultset always returns `false`. - * - * If the operation succeeds and completes with `true`, the new row will be - * read against `output`, possibly reusing its memory. If the operation - * succeeds but completes with `false`, `output` will be set to the empty row - * (as if [refmem row clear] was called). If the operation fails, - * `output` is left in a valid but undetrmined state. - * - * The handler signature for this operation is - * `void(boost::mysql::error_code, bool)`. - */ - template < - BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, bool)) - CompletionToken - BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) - > - BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, bool)) - async_read_one(row& output, CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) - { - return async_read_one(output, shared_info(), std::forward(token)); - } - - /** - * \brief Reads a single row (async with [reflink error_info] version). - * \details Completes with `true` if a row was read successfully, and with `false` if - * there was an error or there were no more rows to read. Calling - * this function on a complete resultset always returns `false`. - * - * If the operation succeeds and completes with `true`, the new row will be - * read against `output`, possibly reusing its memory. If the operation - * succeeds but completes with `false`, `output` will be set to the empty row - * (as if [refmem row clear] was called). If the operation fails, - * `output` is left in a valid but undetrmined state. - * - * The handler signature for this operation is - * `void(boost::mysql::error_code, bool)`. - */ - template < - BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, bool)) - CompletionToken - BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) - > - BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, bool)) - async_read_one( - row& output, - error_info& output_info, - CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) - ); - - /// Reads several rows, up to a maximum (sync with error code version). - std::vector read_many(std::size_t count, error_code& err, error_info& info); - - /// Reads several rows, up to a maximum (sync with exceptions version). - std::vector read_many(std::size_t count); - - /** - * \brief Reads several rows, up to a maximum - * (async without [reflink error_info] version). - * \details - * The handler signature for this operation is - * `void(boost::mysql::error_code, std::vector)`. - */ - template < - BOOST_ASIO_COMPLETION_TOKEN_FOR( - void(::boost::mysql::error_code, std::vector<::boost::mysql::row>) - ) - CompletionToken - BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) - > - BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, std::vector)) - async_read_many( - std::size_t count, - CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) - ) - { - return async_read_many(count, shared_info(), std::forward(token)); - } - - /** - * \brief Reads several rows, up to a maximum - * (async with [reflink error_info] version). - * \details - * The handler signature for this operation is - * `void(boost::mysql::error_code, std::vector)`. - */ - template < - BOOST_ASIO_COMPLETION_TOKEN_FOR( - void(::boost::mysql::error_code, std::vector<::boost::mysql::row>) - ) - CompletionToken - BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) - > - BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, std::vector)) - async_read_many( - std::size_t count, - error_info& output_info, - CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) - ); - - /// Reads all available rows (sync with error code version). - std::vector read_all(error_code& err, error_info& info); - - /// Reads all available rows (sync with exceptions version). - std::vector read_all(); - - /** - * \brief Reads all available rows (async without [reflink error_info] version). - * \details - * The handler signature for this operation is - * `void(boost::mysql::error_code, std::vector)`. - */ - template < - BOOST_ASIO_COMPLETION_TOKEN_FOR( - void(::boost::mysql::error_code, std::vector<::boost::mysql::row>) - ) - CompletionToken - BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) - > - BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, std::vector)) - async_read_all(CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) - { - return async_read_all(shared_info(), std::forward(token)); - } - - /** - * \brief Reads all available rows (async with [reflink error_info] version). - * \details - * The handler signature for this operation is - * `void(boost::mysql::error_code, std::vector)`. - */ - template < - BOOST_ASIO_COMPLETION_TOKEN_FOR( - void(::boost::mysql::error_code, std::vector<::boost::mysql::row>) - ) - CompletionToken - BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) - > - BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, std::vector)) - async_read_all( - error_info& output_info, - CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) - ); - /** * \brief Returns whether this object represents a valid resultset. * \details Returns `false` for default-constructed and moved-from resultsets. * Calling any member function on an invalid resultset, * other than assignment, results in undefined behavior. */ - bool valid() const noexcept { return channel_ != nullptr; } + bool valid() const noexcept { return valid_; } /// \brief Returns whether the resultset has been completely read or not. /// \details See [link mysql.resultsets.complete this section] for more info. - bool complete() const noexcept { return eof_received_; } + bool complete() const noexcept { return ok_packet_.has_value(); } + // TODO: hide this /** * \brief Returns [link mysql.resultsets.metadata metadata] about the fields in the query. * \details There will be as many [reflink field_metadata] objects as fields * in the SQL query, and in the same order. */ - const std::vector& fields() const noexcept { return meta_.fields(); } + const std::vector& fields() const noexcept { return meta_; } + + // TODO: hide this + std::vector& fields() noexcept { return meta_; } /** * \brief The number of rows affected by the SQL that generated this resultset. * \details The resultset __must be [link mysql.resultsets.complete complete]__ * before calling this function. */ - std::uint64_t affected_rows() const noexcept { assert(complete()); return ok_packet_.affected_rows.value; } + std::uint64_t affected_rows() const noexcept { return ok_packet_.affected_rows(); } /** * \brief The last insert ID produced by the SQL that generated this resultset. * \details The resultset __must be [link mysql.resultsets.complete complete]__ * before calling this function. */ - std::uint64_t last_insert_id() const noexcept { assert(complete()); return ok_packet_.last_insert_id.value; } + std::uint64_t last_insert_id() const noexcept { return ok_packet_.last_insert_id(); } /** * \brief The number of warnings produced by the SQL that generated this resultset. * \details The resultset __must be [link mysql.resultsets.complete complete]__ * before calling this function. */ - unsigned warning_count() const noexcept { assert(complete()); return ok_packet_.warnings; } + unsigned warning_count() const noexcept { return ok_packet_.warning_count(); } /** * \brief Additionat text information about the execution of @@ -315,22 +145,10 @@ class resultset * before calling this function. The returned string is guaranteed to be valid * until the resultset object is destroyed. */ - boost::string_view info() const noexcept { assert(complete()); return ok_packet_.info.value; } - - /// Rebinds the resultset type to another executor. - template - struct rebind_executor - { - /// The resultset type when rebound to the specified executor. - using other = resultset< - typename Stream:: template rebind_executor::other - >; - }; + boost::string_view info() const noexcept { return ok_packet_.info(); } }; } // mysql } // boost -#include - #endif