mirror of
https://github.com/boostorg/mysql.git
synced 2026-02-14 00:42:53 +00:00
Added coroutines to integration tests
Changed all prepared_statement functions to not use auto return type declaration Fixed wrong return value in prepared_statement::execute
This commit is contained in:
1
TODO.txt
1
TODO.txt
@@ -15,6 +15,7 @@ Handshake
|
||||
SSL
|
||||
compression
|
||||
Usability
|
||||
Static asserts for completion tokens
|
||||
Connection quit
|
||||
Incomplete query reads: how does this affect further queries?
|
||||
Metadata in rows: being able to index by name
|
||||
|
||||
@@ -31,7 +31,7 @@ void main_impl(int argc, char** argv)
|
||||
// TCP and MySQL level connect
|
||||
boost::asio::io_context ctx;
|
||||
boost::mysql::tcp_connection conn (ctx);
|
||||
conn.next_level().connect(ep);
|
||||
conn.next_layer().connect(ep);
|
||||
conn.handshake(params);
|
||||
|
||||
// Issue the query
|
||||
|
||||
@@ -39,7 +39,7 @@ void main_impl(int argc, char** argv)
|
||||
|
||||
// Declare the connection object and authenticate to the server
|
||||
boost::mysql::tcp_connection conn (ctx);
|
||||
conn.next_level().connect(ep); // next_level() returns a boost::asio::ip::tcp::socket
|
||||
conn.next_layer().connect(ep); // next_level() returns a boost::asio::ip::tcp::socket
|
||||
conn.handshake(params); // Authenticates to the MySQL server
|
||||
|
||||
/**
|
||||
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
|
||||
void connect()
|
||||
{
|
||||
connection.next_level().async_connect(ep, [this](error_code err) {
|
||||
connection.next_layer().async_connect(ep, [this](error_code err) {
|
||||
die_on_error(err);
|
||||
connection.async_handshake(conn_params, [this](error_code err, const error_info& info) {
|
||||
die_on_error(err, info);
|
||||
|
||||
@@ -68,7 +68,7 @@ void main_impl(int argc, char** argv)
|
||||
boost::mysql::error_code ec;
|
||||
|
||||
// TCP connect
|
||||
conn.next_level().async_connect(ep, yield[ec]);
|
||||
conn.next_layer().async_connect(ep, yield[ec]);
|
||||
check_error(ec);
|
||||
|
||||
// MySQL handshake
|
||||
|
||||
@@ -65,7 +65,7 @@ void main_impl(int argc, char** argv)
|
||||
* - Authenticating to the MySQL server.
|
||||
*/
|
||||
boost::mysql::tcp_connection conn (ctx);
|
||||
conn.next_level().connect(ep); // next_level() returns a boost::asio::ip::tcp::socket
|
||||
conn.next_layer().connect(ep); // next_level() returns a boost::asio::ip::tcp::socket
|
||||
conn.handshake(params); // Authenticates to the MySQL server
|
||||
|
||||
/**
|
||||
|
||||
@@ -67,7 +67,7 @@ class connection
|
||||
{
|
||||
using channel_type = detail::channel<Stream>;
|
||||
|
||||
Stream next_level_;
|
||||
Stream next_layer_;
|
||||
channel_type channel_;
|
||||
public:
|
||||
/**
|
||||
@@ -76,16 +76,16 @@ public:
|
||||
*/
|
||||
template <typename... Args>
|
||||
connection(Args&&... args) :
|
||||
next_level_(std::forward<Args>(args)...),
|
||||
channel_(next_level_)
|
||||
next_layer_(std::forward<Args>(args)...),
|
||||
channel_(next_layer_)
|
||||
{
|
||||
}
|
||||
|
||||
/// Retrieves the underlying Stream object.
|
||||
Stream& next_level() { return next_level_; }
|
||||
Stream& next_layer() { return next_layer_; }
|
||||
|
||||
/// Retrieves the underlying Stream object.
|
||||
const Stream& next_level() const { return next_level_; }
|
||||
const Stream& next_layer() const { return next_layer_; }
|
||||
|
||||
/// Performs the MySQL-level handshake (synchronous with error code version).
|
||||
void handshake(const connection_params& params, error_code& ec, error_info& info);
|
||||
|
||||
@@ -74,7 +74,11 @@ boost::mysql::resultset<Stream> boost::mysql::prepared_statement<Stream>::execut
|
||||
|
||||
template <typename StreamType>
|
||||
template <typename ForwardIterator, typename CompletionToken>
|
||||
auto boost::mysql::prepared_statement<StreamType>::async_execute(
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
CompletionToken,
|
||||
typename boost::mysql::prepared_statement<StreamType>::execute_signature
|
||||
)
|
||||
boost::mysql::prepared_statement<StreamType>::async_execute(
|
||||
ForwardIterator params_first,
|
||||
ForwardIterator params_last,
|
||||
CompletionToken&& token
|
||||
@@ -89,7 +93,8 @@ auto boost::mysql::prepared_statement<StreamType>::async_execute(
|
||||
using HandlerArg = async_handler_arg<resultset<StreamType>>;
|
||||
using HandlerSignature = void(error_code, HandlerArg);
|
||||
boost::asio::async_completion<CompletionToken, HandlerSignature> completion (token);
|
||||
return boost::asio::post(
|
||||
// TODO: is executor correctly preserved here?
|
||||
boost::asio::post(
|
||||
channel_->next_layer().get_executor(),
|
||||
boost::beast::bind_front_handler(
|
||||
std::move(completion.completion_handler),
|
||||
@@ -97,6 +102,7 @@ auto boost::mysql::prepared_statement<StreamType>::async_execute(
|
||||
HandlerArg(std::move(info))
|
||||
)
|
||||
);
|
||||
return completion.result.get();
|
||||
}
|
||||
|
||||
// Actually execute the statement
|
||||
@@ -133,7 +139,11 @@ void boost::mysql::prepared_statement<StreamType>::close()
|
||||
|
||||
template <typename StreamType>
|
||||
template <typename CompletionToken>
|
||||
auto boost::mysql::prepared_statement<StreamType>::async_close(
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
CompletionToken,
|
||||
typename boost::mysql::prepared_statement<StreamType>::close_signature
|
||||
)
|
||||
boost::mysql::prepared_statement<StreamType>::async_close(
|
||||
CompletionToken&& token
|
||||
)
|
||||
{
|
||||
|
||||
@@ -59,6 +59,12 @@ public:
|
||||
prepared_statement(detail::channel<Stream>& chan, const detail::com_stmt_prepare_ok_packet& msg) noexcept:
|
||||
channel_(&chan), stmt_msg_(msg) {}
|
||||
|
||||
/// 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(); }
|
||||
|
||||
/// Returns true if the statement is not a default-constructed object.
|
||||
bool valid() const noexcept { return channel_ != nullptr; }
|
||||
|
||||
@@ -86,13 +92,17 @@ public:
|
||||
return execute(std::begin(params), std::end(params));
|
||||
}
|
||||
|
||||
/// The handler signature for execute.
|
||||
using execute_signature = void(error_code, async_handler_arg<resultset<Stream>>);
|
||||
|
||||
/**
|
||||
* \brief Executes a statement (collection, sync with exceptions code version).
|
||||
* \details It is **not** necessary to keep the collection of parameters or the
|
||||
* values they may point to alive.
|
||||
*/
|
||||
template <typename Collection, typename CompletionToken>
|
||||
auto async_execute(const Collection& params, CompletionToken&& token) const
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, execute_signature)
|
||||
async_execute(const Collection& params, CompletionToken&& token) const
|
||||
{
|
||||
return async_execute(std::begin(params), std::end(params), std::forward<CompletionToken>(token));
|
||||
}
|
||||
@@ -118,7 +128,8 @@ public:
|
||||
* by the elements of the sequence need **not** be kept alive.
|
||||
*/
|
||||
template <typename ForwardIterator, typename CompletionToken>
|
||||
auto async_execute(ForwardIterator params_first, ForwardIterator params_last, CompletionToken&& token) const;
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, execute_signature)
|
||||
async_execute(ForwardIterator params_first, ForwardIterator params_last, CompletionToken&& token) const;
|
||||
|
||||
/**
|
||||
* \brief Closes a prepared statement, deallocating it from the server (sync with error code version).
|
||||
@@ -137,9 +148,13 @@ public:
|
||||
/// Closes a prepared statement, deallocating it from the server (sync with exceptions version).
|
||||
void close();
|
||||
|
||||
/// The handler signature for close.
|
||||
using close_signature = void(error_code, error_info);
|
||||
|
||||
/// Closes a prepared statement, deallocating it from the server (async version).
|
||||
template <typename CompletionToken>
|
||||
auto async_close(CompletionToken&& token);
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, close_signature)
|
||||
async_close(CompletionToken&& token);
|
||||
};
|
||||
|
||||
/// A prepared statement associated to a TCP connection to the MySQL server.
|
||||
|
||||
@@ -70,6 +70,12 @@ public:
|
||||
resultset(channel_type& channel, detail::bytestring&& buffer, const detail::ok_packet& ok_pack):
|
||||
channel_(&channel), buffer_(std::move(buffer)), ok_packet_(ok_pack), eof_received_(true) {};
|
||||
|
||||
/// Retrieves the stream object associated with the underlying connection.
|
||||
StreamType& next_layer() noexcept { assert(channel_); return channel_->next_layer(); }
|
||||
|
||||
/// Retrieves the stream object associated with the underlying connection.
|
||||
const StreamType& next_layer() const noexcept { assert(channel_); return channel_->next_layer(); }
|
||||
|
||||
/**
|
||||
* \brief Fetches a single row (sync with error code version).
|
||||
* \details The returned object will be nullptr if there are no more rows
|
||||
|
||||
@@ -58,6 +58,8 @@ add_test(
|
||||
)
|
||||
|
||||
# Integration testing
|
||||
find_package(Boost REQUIRED COMPONENTS coroutine)
|
||||
|
||||
add_executable(
|
||||
mysql_integrationtests
|
||||
integration/metadata_validator.cpp
|
||||
@@ -78,6 +80,7 @@ target_link_libraries(
|
||||
gtest_main
|
||||
gmock
|
||||
mysql_asio
|
||||
Boost::coroutine
|
||||
)
|
||||
target_include_directories(
|
||||
mysql_integrationtests
|
||||
|
||||
@@ -29,7 +29,7 @@ struct IntegTest : testing::Test
|
||||
try
|
||||
{
|
||||
boost::asio::ip::tcp::endpoint endpoint (boost::asio::ip::address_v4::loopback(), 3306);
|
||||
conn.next_level().connect(endpoint);
|
||||
conn.next_layer().connect(endpoint);
|
||||
}
|
||||
catch (...) // prevent terminate without an active exception on connect error
|
||||
{
|
||||
@@ -42,7 +42,7 @@ struct IntegTest : testing::Test
|
||||
~IntegTest()
|
||||
{
|
||||
error_code code;
|
||||
conn.next_level().close(code);
|
||||
conn.next_layer().close(code);
|
||||
guard.reset();
|
||||
runner.join();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "network_functions.hpp"
|
||||
#include <boost/asio/spawn.hpp>
|
||||
#include <future>
|
||||
|
||||
using namespace boost::mysql::test;
|
||||
@@ -12,6 +13,7 @@ using boost::mysql::errc;
|
||||
using boost::mysql::value;
|
||||
using boost::mysql::row;
|
||||
using boost::mysql::owning_row;
|
||||
using boost::asio::yield_context;
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -214,7 +216,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class async : public network_functions
|
||||
class async_callback : public network_functions
|
||||
{
|
||||
template <typename R, typename Callable>
|
||||
static network_result<R> impl(Callable&& cb) {
|
||||
@@ -238,7 +240,7 @@ class async : public network_functions
|
||||
return prom.get_future().get();
|
||||
}
|
||||
public:
|
||||
const char* name() const override { return "async"; }
|
||||
const char* name() const override { return "async_callback"; }
|
||||
network_result<no_result> handshake(
|
||||
tcp_connection& conn,
|
||||
const boost::mysql::connection_params& params
|
||||
@@ -320,14 +322,125 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class async_coroutine : public network_functions
|
||||
{
|
||||
template <typename IoObj, typename Callable>
|
||||
static auto impl(IoObj& obj, Callable&& cb) {
|
||||
using R = typename decltype(cb(std::declval<yield_context>()))::value_type;
|
||||
auto executor = obj.next_layer().get_executor();
|
||||
std::promise<network_result<R>> prom;
|
||||
boost::asio::spawn(executor, [&](yield_context yield) {
|
||||
error_code ec;
|
||||
auto result = cb(yield[ec]);
|
||||
prom.set_value(network_result<R>{ec, std::move(result.error()), std::move(result.get())});
|
||||
});
|
||||
return prom.get_future().get();
|
||||
}
|
||||
|
||||
template <typename IoObj, typename Callable>
|
||||
static network_result<no_result> impl_no_result(IoObj& obj, Callable&& cb) {
|
||||
auto executor = obj.next_layer().get_executor();
|
||||
std::promise<network_result<no_result>> prom;
|
||||
boost::asio::spawn(executor, [&](yield_context yield) {
|
||||
error_code ec;
|
||||
error_info info = cb(yield[ec]);
|
||||
prom.set_value(network_result<no_result>{ec, std::move(info), no_result()});
|
||||
});
|
||||
return prom.get_future().get();
|
||||
}
|
||||
public:
|
||||
const char* name() const override { return "async_coroutine"; }
|
||||
network_result<no_result> handshake(
|
||||
tcp_connection& conn,
|
||||
const boost::mysql::connection_params& params
|
||||
) override
|
||||
{
|
||||
return impl_no_result(conn, [&](yield_context yield) {
|
||||
return conn.async_handshake(params, yield);
|
||||
});
|
||||
}
|
||||
network_result<tcp_resultset> query(
|
||||
tcp_connection& conn,
|
||||
std::string_view query
|
||||
) override
|
||||
{
|
||||
return impl(conn, [&](yield_context yield) {
|
||||
return conn.async_query(query, yield);
|
||||
});
|
||||
}
|
||||
network_result<tcp_prepared_statement> prepare_statement(
|
||||
tcp_connection& conn,
|
||||
std::string_view statement
|
||||
) override
|
||||
{
|
||||
return impl(conn, [&](yield_context yield) {
|
||||
return conn.async_prepare_statement(statement, yield);
|
||||
});
|
||||
}
|
||||
network_result<tcp_resultset> execute_statement(
|
||||
tcp_prepared_statement& stmt,
|
||||
value_list_it params_first,
|
||||
value_list_it params_last
|
||||
) override
|
||||
{
|
||||
return impl(stmt, [&](yield_context yield) {
|
||||
return stmt.async_execute(params_first, params_last, yield);
|
||||
});
|
||||
}
|
||||
network_result<tcp_resultset> execute_statement(
|
||||
tcp_prepared_statement& stmt,
|
||||
const std::vector<value>& values
|
||||
) override
|
||||
{
|
||||
return impl(stmt, [&](yield_context yield) {
|
||||
return stmt.async_execute(values, yield);
|
||||
});
|
||||
}
|
||||
network_result<no_result> close_statement(
|
||||
tcp_prepared_statement& stmt
|
||||
) override
|
||||
{
|
||||
return impl_no_result(stmt, [&](yield_context yield) {
|
||||
return stmt.async_close(yield);
|
||||
});
|
||||
}
|
||||
network_result<const row*> fetch_one(
|
||||
tcp_resultset& r
|
||||
) override
|
||||
{
|
||||
return impl(r, [&](yield_context yield) {
|
||||
return r.async_fetch_one(yield);
|
||||
});
|
||||
}
|
||||
network_result<std::vector<owning_row>> fetch_many(
|
||||
tcp_resultset& r,
|
||||
std::size_t count
|
||||
) override
|
||||
{
|
||||
return impl(r, [&](yield_context yield) {
|
||||
return r.async_fetch_many(count, yield);
|
||||
});
|
||||
}
|
||||
network_result<std::vector<owning_row>> fetch_all(
|
||||
tcp_resultset& r
|
||||
) override
|
||||
{
|
||||
return impl(r, [&](yield_context yield) {
|
||||
return r.async_fetch_all(yield);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Global objects to be exposed
|
||||
sync_errc sync_errc_obj;
|
||||
sync_exc sync_exc_obj;
|
||||
async async_obj;
|
||||
async_callback async_callback_obj;
|
||||
async_coroutine async_coroutine_obj;
|
||||
|
||||
}
|
||||
|
||||
// Visible stuff
|
||||
boost::mysql::test::network_functions* boost::mysql::test::sync_errc_network_functions = &sync_errc_obj;
|
||||
boost::mysql::test::network_functions* boost::mysql::test::sync_exc_network_functions = &sync_exc_obj;
|
||||
boost::mysql::test::network_functions* boost::mysql::test::async_network_functions = &async_obj;
|
||||
boost::mysql::test::network_functions* boost::mysql::test::async_callback_network_functions = &async_callback_obj;
|
||||
boost::mysql::test::network_functions* boost::mysql::test::async_coroutine_network_functions = &async_coroutine_obj;
|
||||
|
||||
@@ -66,12 +66,14 @@ public:
|
||||
|
||||
extern network_functions* sync_errc_network_functions;
|
||||
extern network_functions* sync_exc_network_functions;
|
||||
extern network_functions* async_network_functions;
|
||||
extern network_functions* async_callback_network_functions;
|
||||
extern network_functions* async_coroutine_network_functions;
|
||||
|
||||
inline network_functions* all_network_functions [] = {
|
||||
sync_errc_network_functions,
|
||||
sync_exc_network_functions,
|
||||
async_network_functions
|
||||
async_callback_network_functions,
|
||||
async_coroutine_network_functions
|
||||
};
|
||||
|
||||
#define MYSQL_NETWORK_TEST_SUITE(TestSuiteName) \
|
||||
|
||||
Reference in New Issue
Block a user