2
0
mirror of https://github.com/boostorg/mysql.git synced 2026-02-15 01:02:17 +00:00

New connection iface

This commit is contained in:
Ruben Perez
2022-07-27 21:17:03 +02:00
parent 77e98230a3
commit 7e01afaca9
10 changed files with 649 additions and 618 deletions

View File

@@ -9,17 +9,20 @@
#define BOOST_MYSQL_CONNECTION_HPP
#include <boost/asio/ssl/context.hpp>
#include <type_traits>
#ifndef BOOST_MYSQL_DOXYGEN // For some arcane reason, Doxygen fails to expand Asio macros without this
#include <boost/mysql/detail/protocol/channel.hpp>
#include <boost/mysql/detail/channel/channel.hpp>
#include <boost/mysql/detail/protocol/protocol_types.hpp>
#include <boost/mysql/detail/network_algorithms/handshake.hpp>
#include <boost/mysql/detail/auxiliar/value_type_traits.hpp>
#include <boost/mysql/error.hpp>
#include <boost/mysql/resultset.hpp>
#include <boost/mysql/prepared_statement.hpp>
#include <boost/mysql/connection_params.hpp>
#include <boost/mysql/execute_params.hpp>
#include <boost/mysql/row.hpp>
#include <type_traits>
#endif
@@ -61,7 +64,7 @@ template <
class connection
{
std::unique_ptr<detail::channel<Stream>> channel_;
protected:
detail::channel<Stream>& 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<Stream> 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<Stream> 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<Stream>)`.
*/
template <
BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(::boost::mysql::error_code, ::boost::mysql::resultset<Stream>)
)
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<Stream>))
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<CompletionToken>(token));
return async_query(query_string, result, shared_info(), std::forward<CompletionToken>(token));
}
/**
@@ -389,15 +391,14 @@ public:
* `void(boost::mysql::error_code, boost::mysql::resultset<Stream>)`.
*/
template <
BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(::boost::mysql::error_code, ::boost::mysql::resultset<Stream>)
)
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<Stream>))
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<Stream> 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<Stream> 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<Stream>)`
*/
template <
BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(::boost::mysql::error_code, ::boost::mysql::prepared_statement<Stream>)
)
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<Stream>))
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<CompletionToken>(token));
return async_prepare_statement(statement, result, shared_info(), std::forward<CompletionToken>(token));
}
/**
@@ -453,15 +453,477 @@ public:
* `void(boost::mysql::error_code, boost::mysql::prepared_statement<Stream>)`
*/
template <
BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(::boost::mysql::error_code, ::boost::mysql::prepared_statement<Stream>)
)
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<Stream>))
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 <class ValueCollection, class EnableIf = detail::enable_if_value_collection<ValueCollection>>
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 <class ValueCollection, class EnableIf = detail::enable_if_value_collection<ValueCollection>>
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<Stream>)`.
*/
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<ValueCollection>
>
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<CompletionToken>(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<Stream>)`.
*/
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<ValueCollection>
>
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<CompletionToken>(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 <class ValueForwardIterator>
void execute_statement(
const execute_params<ValueForwardIterator>& 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 <class ValueForwardIterator>
void execute_statement(
const execute_params<ValueForwardIterator>& 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<Stream>)`.
*/
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<ValueForwardIterator>& params,
resultset& result,
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
)
{
return async_execute(params, result, shared_info(), std::forward<CompletionToken>(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<Stream>)`.
*/
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<ValueForwardIterator>& 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<CompletionToken>(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<CompletionToken>(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<boost::mysql::row>)`.
*/
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<CompletionToken>(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<boost::mysql::row>)`.
*/
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<boost::mysql::row>)`.
*/
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<CompletionToken>(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<boost::mysql::row>)`.
*/
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)
);

View File

@@ -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 <class Stream>
struct null_channel_deleter
{
void operator()(channel<Stream>*) const noexcept {}
};
template <class Stream>
using channel_observer_ptr = std::unique_ptr<channel<Stream>, null_channel_deleter<Stream>>;
} // detail
} // mysql
} // boost

View File

@@ -10,7 +10,7 @@
#include <boost/mysql/error.hpp>
#include <boost/mysql/metadata.hpp>
#include <boost/mysql/detail/protocol/channel.hpp>
#include <boost/mysql/detail/channel/channel.hpp>
#include <boost/mysql/detail/protocol/common_messages.hpp>
namespace boost {

View File

@@ -10,7 +10,7 @@
#include <boost/utility/string_view.hpp>
#include <boost/mysql/detail/network_algorithms/common.hpp>
#include <boost/mysql/detail/protocol/channel.hpp>
#include <boost/mysql/detail/channel/channel.hpp>
#include <boost/mysql/detail/protocol/protocol_types.hpp>
#include <boost/mysql/connection_params.hpp>
#include <boost/mysql/collation.hpp>

View File

@@ -12,7 +12,7 @@
#include <boost/mysql/detail/network_algorithms/quit_connection.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/mysql/detail/protocol/channel.hpp>
#include <boost/mysql/detail/channel/channel.hpp>
#include <boost/mysql/error.hpp>
namespace boost {

View File

@@ -9,6 +9,7 @@
#define BOOST_MYSQL_EXECUTE_PARAMS_HPP
#include <boost/mysql/value.hpp>
#include <boost/mysql/prepared_statement.hpp>
#include <boost/mysql/detail/auxiliar/value_type_traits.hpp>
#include <iterator>
#include <type_traits>
@@ -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 ValueForwardIterator>
class execute_params
{
std::uint32_t statement_id_;
ValueForwardIterator first_;
ValueForwardIterator last_;
static_assert(detail::is_value_forward_iterator<ValueForwardIterator>::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<ValueForwardIterator>
make_execute_params(
std::uint32_t statement_id,
ValueForwardIterator first,
ValueForwardIterator last
)
{
return execute_params<ValueForwardIterator>(first, last);
return execute_params<ValueForwardIterator>(statement_id, first, last);
}
template <
class ValueForwardIterator,
class EnableIf = detail::enable_if_value_forward_iterator<ValueForwardIterator>
>
constexpr execute_params<ValueForwardIterator>
make_execute_params(
const prepared_statement& stmt,
ValueForwardIterator first,
ValueForwardIterator last
)
{
return execute_params<ValueForwardIterator>(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<ValueCollection>
>
constexpr auto make_execute_params(
const prepared_statement& stmt,
const ValueCollection& col
) -> execute_params<decltype(std::begin(col))>
{
return make_execute_params(stmt.id(), std::begin(col), std::end(col));
}
}
} // mysql
} // boost
#endif

View File

@@ -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_;

View File

@@ -11,6 +11,8 @@
#include <boost/mysql/detail/protocol/common_messages.hpp>
#include <boost/mysql/detail/auxiliar/bytestring.hpp>
#include <boost/mysql/field_type.hpp>
#include <boost/utility/string_view_fwd.hpp>
#include <string>
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); }

View File

@@ -8,12 +8,11 @@
#ifndef BOOST_MYSQL_PREPARED_STATEMENT_HPP
#define BOOST_MYSQL_PREPARED_STATEMENT_HPP
#include <boost/mysql/resultset.hpp>
#include <boost/mysql/execute_params.hpp>
#include <boost/mysql/detail/protocol/channel.hpp>
#include <boost/mysql/detail/protocol/prepared_statement_messages.hpp>
#include <boost/mysql/detail/auxiliar/value_type_traits.hpp>
#include <type_traits>
#include <boost/mysql/value.hpp>
#include <array>
#include <cstdint>
namespace boost {
namespace mysql {
@@ -40,18 +39,14 @@ constexpr std::array<value, 0> no_statement_params {};
* whose parent connection has been closed or destroyed results
* in undefined behavior.
*/
template <class Stream>
class prepared_statement
{
detail::channel_observer_ptr<Stream> channel_;
bool valid_ {false};
detail::com_stmt_prepare_ok_packet stmt_msg_;
template <class ValueForwardIterator>
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<Stream>& 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 <class ValueCollection, class EnableIf = detail::enable_if_value_collection<ValueCollection>>
resultset<Stream> 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 <class ValueCollection, class EnableIf = detail::enable_if_value_collection<ValueCollection>>
resultset<Stream> 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<Stream>)`.
*/
template <
class ValueCollection,
BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(::boost::mysql::error_code, ::boost::mysql::resultset<Stream>)
)
CompletionToken
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type),
class EnableIf = detail::enable_if_value_collection<ValueCollection>
>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, resultset<Stream>))
async_execute(
const ValueCollection& params,
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
)
{
return async_execute(
make_execute_params(params),
std::forward<CompletionToken>(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<Stream>)`.
*/
template <
class ValueCollection,
BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(::boost::mysql::error_code, ::boost::mysql::resultset<Stream>)
)
CompletionToken
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type),
class EnableIf = detail::enable_if_value_collection<ValueCollection>
>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, resultset<Stream>))
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<CompletionToken>(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 <class ValueForwardIterator>
resultset<Stream> execute(const execute_params<ValueForwardIterator>& 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 <class ValueForwardIterator>
resultset<Stream> execute(const execute_params<ValueForwardIterator>& 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<Stream>)`.
*/
template <
class ValueForwardIterator,
BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(::boost::mysql::error_code, ::boost::mysql::resultset<Stream>)
)
CompletionToken
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)
>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, resultset<Stream>))
async_execute(
const execute_params<ValueForwardIterator>& params,
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
)
{
return async_execute(params, shared_info(), std::forward<CompletionToken>(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<Stream>)`.
*/
template <
class ValueForwardIterator,
BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(::boost::mysql::error_code, ::boost::mysql::resultset<Stream>)
)
CompletionToken
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)
>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, resultset<Stream>))
async_execute(
const execute_params<ValueForwardIterator>& 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<CompletionToken>(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 <class Executor>
struct rebind_executor
{
/// The prepared statement type when rebound to the specified executor.
using other = prepared_statement<
typename Stream:: template rebind_executor<Executor>::other
>;
};
};
} // mysql
} // boost
#include <boost/mysql/impl/prepared_statement.hpp>
#endif /* INCLUDE_BOOST_MYSQL_PREPARED_STATEMENT_HPP_ */

View File

@@ -11,10 +11,14 @@
#include <boost/mysql/row.hpp>
#include <boost/mysql/metadata.hpp>
#include <boost/mysql/detail/protocol/common_messages.hpp>
#include <boost/mysql/detail/protocol/channel.hpp>
#include <boost/mysql/detail/channel/channel.hpp>
#include <boost/mysql/detail/auxiliar/bytestring.hpp>
#include <boost/mysql/detail/network_algorithms/common.hpp> // deserialize_row_fn
#include <boost/utility/string_view_fwd.hpp>
#include <cassert>
#include <cstdint>
#include <string>
#include <vector>
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<Stream> channel_;
detail::resultset_metadata meta_;
detail::bytestring ok_packet_buffer_;
detail::ok_packet ok_packet_;
bool eof_received_ {false};
std::vector<field_metadata> 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<Stream>& channel, detail::resultset_metadata&& meta,
detail::deserialize_row_fn deserializer):
deserializer_(deserializer), channel_(&channel), meta_(std::move(meta)) {};
resultset(detail::channel<Stream>& 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<field_metadata>&& 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<Stream>::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<CompletionToken>(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<row> 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<row> 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<boost::mysql::row>)`.
*/
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<row>))
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<CompletionToken>(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<boost::mysql::row>)`.
*/
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<row>))
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<row> read_all(error_code& err, error_info& info);
/// Reads all available rows (sync with exceptions version).
std::vector<row> 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<boost::mysql::row>)`.
*/
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<row>))
async_read_all(CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return async_read_all(shared_info(), std::forward<CompletionToken>(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<boost::mysql::row>)`.
*/
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<row>))
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<field_metadata>& fields() const noexcept { return meta_.fields(); }
const std::vector<field_metadata>& fields() const noexcept { return meta_; }
// TODO: hide this
std::vector<field_metadata>& 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 <class Executor>
struct rebind_executor
{
/// The resultset type when rebound to the specified executor.
using other = resultset<
typename Stream:: template rebind_executor<Executor>::other
>;
};
boost::string_view info() const noexcept { return ok_packet_.info(); }
};
} // mysql
} // boost
#include <boost/mysql/impl/resultset.hpp>
#endif